home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / genie-commodore-file-library / Information / HACKING6F.SFX / hacking6f
Encoding:
Text File  |  1993-09-17  |  31.2 KB  |  755 lines

  1. and you're in business.  The program will display "Keyscan128 installed" and
  2. go to work.  The program loads into memory at addresses $1500-$17BA (5376-6074
  3. decimal), so you'll want to watch out for conflicts with other utilities.
  4. This program also takes over the IRQ vector and the BASIC restart vector
  5. ($A00).  The program will survive a RUN/STOP+RESTORE.  To uninstall this
  6. program, you must reset the machine (or poke the kernel values back into the
  7. vectors); it does not uninstall itself.
  8.  
  9. Loading the C-64 version is a bit trickier, so a small BASIC loader program is
  10. provided.  LOAD and RUN the "KEYSCAN64.BOOT" program.  It will load the
  11. "KEYSCAN64" program into memory at addresses $C500-$C77E (50432-51070 decimal)
  12. and execute it (with a SYS 50432).  To uninstall the program, enter SYS 50435.
  13. The program takes over the IRQ and NMI vectors and only gives them back to the
  14. kernel upon uninstallation.  The program will survive a RUN/STOP+RESTORE.
  15.  
  16. Something that you may or may not know about the C-64 is that its keys can be
  17. made to repeat by poking to address 650 decimal.  POKE650,128 will enable the
  18. repeating of all keys.  POKE650,0 will enable only the repeating of the SPACE,
  19. DELETE, and CURSOR keys.  POKE650,64 will disable the repeating of all keys.
  20. An unusual side effect of changing this to either full repeat or no repeat is
  21. that holding down SHIFT+COMMODORE (character set shift) will repeat rapidly.
  22.  
  23. To see the rollover in action, hold down the "J" key for a while, and then
  24. press "K" without releasing "J".  "K" will come out as expected, as it would
  25. with the kernal.  Now, release the "J" key.  If you are on a C-128, you will
  26. notice that the "K" key will now stop repeating (this is actually an important
  27. feature - it avoids problems if you don't release all of the keys you are
  28. holding down, at once).  Now, press and hold the "J" key again without
  29. releasing the "K".  "J" will now appear.  It wouldn't using the Kernal key
  30. scanner.  You can also try this with 3-key combinations.  There will be some
  31. combinations that cause problems; more on this below.
  32.  
  33. Also, take a spaz on the joystick plugged into port #1 and observe that no
  34. garbage gets typed in.  This was an annoying problem with the kernel of both
  35. the 64 and 128 and has lead many different games to picking between joystick
  36. #1 and #2 as the primary controller.  The joystick in port #2 is not a problem
  37. to either Keyscan-128/64 or the Kernal.
  38.  
  39. 3. KEYBOARD SCANNING
  40.  
  41. The Kernal scans the keyboard sixty times a second to see what keys you are
  42. holding down.  Because of hardware peculiarities, there are multiple scanning
  43. techniques that will give different results.
  44.  
  45. 3.1. SCANNING EXAMPLE
  46.  
  47. An example program is included to demonstrate different keyboard scanning
  48. techniques possible.  To run it from a C-128 in 40-column (slow) mode, enter:
  49.  
  50. BOOT "KEYSHOW"
  51. On a C-64, you must:
  52. LOAD "KEYSHOW",8,1
  53. and then:
  54. SYS 4864
  55.  
  56. The same program works on both machines.  Four maps of the keyscanning matrix
  57. will be displayed on the 40-column screen, as scanned by different techniques.
  58. The leftmost one is scanned from top to bottom "quickly".  The second from the
  59. left scans from bottom to top "quickly".  The third from the left scans the
  60. keyboard sideways, and the rightmost matrix scans the keys from top to bottom
  61. "slowly".
  62.  
  63. The mapping of keyscan matrix positions to keys is as follows:
  64.  
  65. ROWS: \             COLUMNS:    peek($DC01)
  66. poke   \
  67. $DC00   \   128      64      32      16      8       4       2       1
  68.          +-------+-------+-------+-------+-------+-------+-------+-------+
  69.   255-1  | DOWN  |   F5  |   F3  |   F1  |   F7  | RIGHT | RETURN| DELETE|
  70.          +-------+-------+-------+-------+-------+-------+-------+-------+
  71.   255-2  |LEFT-SH|   E   |   S   |   Z   |   4   |   A   |   W   |   3   |
  72.          +-------+-------+-------+-------+-------+-------+-------+-------+
  73.   255-4  |   X   |   T   |   F   |   C   |   6   |   D   |   R   |   5   |
  74.          +-------+-------+-------+-------+-------+-------+-------+-------+
  75.   255-8  |   V   |   U   |   H   |   B   |   8   |   G   |   Y   |   7   |
  76.          +-------+-------+-------+-------+-------+-------+-------+-------+
  77.  255-16  |   N   |   O   |   K   |   M   |   0   |   J   |   I   |   9   |
  78.          +-------+-------+-------+-------+-------+-------+-------+-------+
  79.  255-32  |   ,   |   @   |   :   |   .   |   -   |   L   |   P   |   +   |
  80.          +-------+-------+-------+-------+-------+-------+-------+-------+
  81.  255-64  |   /   |   ^   |   =   |RGHT-SH|  HOME |   ;   |   *   |   \   |
  82.          +-------+-------+-------+-------+-------+-------+-------+-------+
  83. 255-128  | STOP  |   Q   |COMMODR| SPACE |   2   |CONTROL|   _   |   1   |
  84.          +-------+-------+-------+-------+-------+-------+-------+-------+
  85.  
  86. The following table contains the additional keys which must be scanned on the
  87. C128 (but which are not displayed by the example scanning program).
  88.  
  89. ROWS: \               COLUMNS:    peek($DC01)
  90. poke   \
  91. $D02F   \   128      64      32      16      8       4       2       1
  92.          +-------+-------+-------+-------+-------+-------+-------+-------+
  93.   255-1  |   1   |   7   |   4   |   2   |  TAB  |   5   |   8   |  HELP |
  94.          +-------+-------+-------+-------+-------+-------+-------+-------+
  95.   255-2  |   3   |   9   |   6   | ENTER |   LF  |   -   |   +   |  ESC  |
  96.          +-------+-------+-------+-------+-------+-------+-------+-------+
  97.   255-4  |NO-SCRL| RIGHT |  LEFT |  DOWN |   UP  |   .   |   0   |  ALT  |
  98.          +-------+-------+-------+-------+-------+-------+-------+-------+
  99.  
  100. These tables are presented on page 642 of the Commodore 128 Programmer's
  101. Reference Guide.  The scan codes that are stored in location 212 on the C128
  102. and location 197 on the C64 are calculated based on the above tables.  The
  103. entry in the "1" bit position of the first line of the first table (DELETE)
  104. has a scan code of 0, the "2" entry (RETURN) has a scan code of 1, etc., the
  105. entry on the second scan line in the "1" position ("3") has a scan code of 8,
  106. etc., all the way down to code 63.  The scan codes for the 128 go all the way
  107. to 87, continuing in the second table like the first.
  108.  
  109. You will notice some strange effects of the different scanning techniques when
  110. you hold down multiple keys.  More on this below.  Also try pushing joystick
  111. #1 around.
  112.  
  113. 3.2. SCANNING HARDWARE
  114. To scan the 128 keyboard, you must poke a value into $DC00 (CIA#1 port A) and
  115. $D02F (VIC chip keyboard select port) to select the row to be scanned.  The
  116. Data Direction Register for this port will be set to all outputs by the
  117. Kernal, so you don't have to worry about it.  Each bit of $DC00 and the three
  118. least significant bits of $D02F are used for selecting rows.  A "0" bit means
  119. that a row IS selected, and a "1" means that a row IS NOT selected.  The poke
  120. value to use for selecting among the various rows are given in the two tables
  121. in the previous section.
  122.  
  123. Using one bit per row allows you to select multiple rows at the same time.  It
  124. can be useful to select all rows at one time or no rows.  To read the row that
  125. has been selected, simply peek at location $DC01 (CIA#1 port B).  Each bit
  126. will tell you whether the corresponding key is currently being held down or
  127. not.  Again, we have reverse logic; a "0" means that the key is being held
  128. down, and a "1" means that the key is not held down.  The bit values
  129. corresponding to the keys are given as the column headings in the tables in
  130. the previous section.  Since there is no such thing as a perfect mechanical
  131. switch, it is recommended that you "debounce" each key row read in the
  132. following way:
  133.  
  134. again:
  135.    lda $dc01
  136.    cmp $dc01
  137.    bne again
  138.  
  139. So, to scan the entire keyboard, you simply select each scan row in some
  140. order, and read and remember the keys held down on the row.  As it turns out,
  141. you have to be a bit careful of exactly how you "select" a row.  Also, there
  142. is a shortcut that you can take.  In order to find out if any key is being
  143. held down in one operation, all you have to do is select all rows at once and
  144. see if there are any "0" bits in the read value.  If so, there is a key being
  145. held down somewhere; if not, then there is no key being held down, so you
  146. don't have to bother scanning the entire keyboard.  This will reduce our
  147. keyscanning significantly, which is important, since the keyboard will be
  148. scanned every 1/60 of a second.
  149.  
  150. As mentioned above, joystick #1 will interfere with the Kernal reading the
  151. keyboard.  This is because the read value of joystick #1 is wired into CIA#1
  152. port A, the same place that the keyboard read is wired in.  So, whenever a
  153. switch in the joystick is pushed, the corresponding bit of the keyboard scan
  154. register will be forced to "0", regardless of which keys are pressed and
  155. regardless of which scan row is selected.  There's the catch.  If we were to
  156. un-select all scan rows and still notice "0"s in the keyboard read register,
  157. then we would know that the joystick was being pushed and would interfere with
  158. our keyboard scanning, so we could abort keyboard scanning and handle this
  159. case as if no keys were being held down.
  160.  
  161. It still would be possible but unlikely that the user could push the joystick
  162. in the middle of us scanning the keyboard and screw up our results, so to
  163. defend against this, we check for the joystick being pushed both before and
  164. after scanning the keyboard.  If we find that the joystick is pushed at either
  165. of these times, then we throw out the results and assume that no keys are held
  166. down.  This way, the only way that a user could screw up the scanning is if
  167. he/she/it were to press a switch after we begin scanning and release it before
  168. we finish scanning.  Not bloody likely for a human.
  169.  
  170. You get the same deal for keyboard scanning on the 64, except you only need to
  171. use $DC00 for selecting the scan rows.  Also note that you will not be able to
  172. play with keyboard scanning from BASIC because of the interrupt reading of the
  173. keyboard.  You must make sure that interrupts are disabled when playing with
  174. the keyboard hardware, or interrupt scanning can come along at any time and
  175. change all of the register settings.
  176.  
  177. 3.3. SCANNING SOURCE CODE
  178. The four keyboard scanning techniques of the example program are presented
  179. below.  The declarations required for all of them are:
  180.  
  181. pa = $dc00        ;row select
  182. pb = $dc01        ;column read
  183. ddra = $dc02      ;ddr for row select
  184. ddrb = $dc03      ;ddr for column read
  185. scanTable .buf 8  ;storage for scan
  186. mask = $03        ;work location
  187.  
  188. The code is as follows, in Buddy format.  Each routine scans the keyboard and
  189. stores the results in the "scanTable" table.
  190.  
  191. ------------------+------------------+------------------+------------------+
  192.  Row forward fast | Row backward fast| Column right     | Row forward slow
  193. ------------------+------------------+------------------+------------------+
  194.   sei             |  sei             |  sei             |  sei
  195.   ldx #0          |  ldx #7          |  lda #$00        |  ldx #0
  196.   lda #$fe        |  lda #$7f        |  sta ddra        |  lda #$fe
  197.   sta pa          |  sta pa          |  lda #$ff        |  sta mask
  198.   nextRow = *     |  nextRow = *     |  sta ddrb        |  nextRow = *
  199. - lda pb          |- lda pb          |  ldy #7          |  lda mask
  200.   cmp pb          |  cmp pb          |  lda #$7f        |  sta pa
  201.   bne -           |  bne -           |  sta mask        |- lda pb
  202.   eor #$ff        |  eor #$ff        |  nextCol = *     |  cmp pb
  203.   sta scanTable,x |  sta scanTable,x |  lda mask        |  bne -
  204.   sec             |  sec             |  sta pb          |  eor #$ff
  205.   rol pa          |  ror pa          |- lda pa          |  sta scanTable,x
  206.   inx             |  dex             |  cmp pa          |  sec
  207.   cpx #8          |  bpl nextRow     |  bne -           |  rol mask
  208.   bcc nextRow     |  cli             |  ldx #$ff        |  inx
  209.   cli             |  rts             |  stx pb          |  cpx #8
  210.   rts             |                  |  eor #$ff        |  bcc nextRow
  211. ------------------+------------------+  ldx #7          |  cli
  212.                                      |- asl             |  rts
  213. The forward "quick" scanning stores  |  rol scanTable,x +------------------+
  214. the scan row selection mask into     |  dex             |
  215. the row selection register and       |  bpl -           |
  216. shifts the "0" bit one position      |  sec             |
  217. "forward" for each row, directly,    |  ror mask        |
  218. using a "rol $dc00" instruction.     |  dey             |
  219. This would probably be the obvious   |  bpl nextCol     |
  220. solution to an optimizing assembler  |  lda #$ff        |
  221. programmer.  However, for some       |  sta ddra        |
  222. reason not quite understood by this  |  lda #$00        |
  223. author, there are "shadowing"        |  sta ddrb        |
  224. problems with this approach.  If     |  cli             |
  225. you were to hold down the two keys   |  rts             |
  226. "H" and "K" at the same time, you    +------------------+
  227. would notice that these two keys
  228. are on the same column of two successive rows.  If you hold them both down,
  229. you will see the two positions become active, but so will the same column of
  230. all successive rows after the "H" and "K", even though these other keys are
  231. not actually held down.  You will get an inaccurate reading if bad keys are
  232. held down simultaneously.  You will notice the use of the term "active" above.
  233. This is because although the hardware returns a "0" for active, the routine
  234. converts that into a "1" for easier processing later.  I am not sure if
  235. everyone will get this same result, but if your keyboard is wired the same as
  236. mine, you will.
  237.  
  238. The backward "quick" scanning operates quite similarly to the forward
  239. scanning, except for the direction of the scan and the direction of the
  240. "shadow"; the shadow goes upwards.  You might think that ANDing together the
  241. results of the forward and backward scan together would eliminate the shadow,
  242. but this will not work since any rows between the rows containing the two keys
  243. held down will be incorrectly read as being active.
  244.  
  245. The columnwise right scanning is the most complicated because the rows must be
  246. converted into columns, to allow the scan matrix to be interpreted as before.
  247. Also, the Data Direction Registers have to be changed.  You might think that
  248. combinging row-wise scanning with columnwise scanning would give better
  249. results, and it probably would, if it weren't for a bizarre hardware problem.
  250. If you hold down two or more keys on the same scan row, say "W" and "E", some
  251. of the keys will flicker or disappear, giving an inaccurate reading.
  252.  
  253. The forward "slow" scanning is the best of the bunch.  Incidentally, it is
  254. what the Kernal uses (as near as I can figure - their code is extremely
  255. convoluted).  This technique is the same as the forward "quick scan," except
  256. that the row selection mask is shifted in a working storage location and poked
  257. into the CIA register, rather than being shifted in place.  I don't know why
  258. this makes a difference, but it does.  There is still a problem with this
  259. technique, but this problem occurs with all techniques.  If you hold down
  260. three keys that form three "corners" of a rectangle in the scanning matrix,
  261. then the missing corner will be read as being held down also.  For example, if
  262. you hold down "C", "N", and "M", then the keyboard hardware will also think
  263. that you are holding down the "X" key.  This is why this article implements a
  264. "three-key" rollover rather than an "N-key" rollover.  Many three-key
  265. combinations will still be interpreted correctly.  Note, however, that shift
  266. keys such as SHIFT or CONTROL will add one more key to the hardware scanning
  267. (but will not be counted in the three-key rollover), making inaccurate results
  268. more likely if you are holding down multiple other keys at the same time.
  269.  
  270. 4. THE C-128 KEYSCANNER
  271. This section gives the source code for the C-128 implementation of the
  272. three-key rollover.  The forward "slow" key matrix scanning technique is used,
  273. extended to work with the extra keys of the 128.  It was a bit of a pain
  274. wedging into the Kernal, since there is not a convenient indirect JMP into
  275. scanning the keyboard, like there are for decoding and buffering pressed keys.
  276. A rather lengthy IRQ "preamble" had to be copied from the ROM, up to the
  277. point where it JSRs to the keyscanning routine.  This code in included in
  278. the form of a ".byte" table, to spare you the details.
  279.  
  280. Before scanning the keyboard, we check to see if joystick #1 is pushed and if
  281. a key is actually pressed.  If not, we abort scanning and JMP to the key
  282. repeat handling in the ROM.  If a key is held down, we scan the keyboard and
  283. then examine the result.  First we check for the shift keys (SHIFT, COMMODORE,
  284. CONTROL, ALT, and CAPS LOCK), put them into location $D3 (shift flags) in bit
  285. postitions 1, 2, 4, 8, and 16, respectively, and remove them from the scan
  286. matrix.  The CAPS LOCK key is not on the main key matrix; it is read from the
  287. processor I/O port.  This is good, because otherwise we could not abort
  288. scanning if it were the only key held down.
  289.  
  290. Then we scan the keymatrix for the first three keys that are being held down,
  291. or as many as are held down if less than three.  We store the scan codes of
  292. these keys into a 3-element array.  We also retain a copy of the 3-element
  293. array from the previous scan and we check for different keys being in the two
  294. arrays.  If the old array contains a key that is not present in the new array,
  295. then the use has released a key, so we set a flag to inhibit interpretation of
  296. keys and pretend that no keys are held down.  This is to eliminate undesirable
  297. effects of having other keys held down repeat if you release the most recently
  298. pushed key first.  PC keyboards do this.  This inhibiting will be ignored if
  299. new keys are discovered in the next step.
  300.  
  301. If there are keys in the new array that are not in the old, then the user has
  302. just pressed a new key, so that new key goes to the head of the old array and
  303. we stop comparing the arrays there.  The key in the first position of the old
  304. array is poked into the Kernal "key held down" location for the Kernal to
  305. interpret later.  If more than one new key is discovered at the same time,
  306. then each of the new keys will be picked up on successive keyboard scans and
  307. will be interpreted as just being pushed.  So, if you press the "A", "N", and
  308. "D" keys all at the same time, some permutation of all three of these keys
  309. will appear on the screen.
  310.  
  311. When we are done interpreting the keys, we check the joystick once more and if
  312. it is still inactive, we present the most recently pushed down key to the
  313. Kernal and JMP into the ROM keyboard decoding routine.
  314.  
  315. Unlike in previous issues, this source code is here in literal form; just
  316. extract everything between the "-----=-----"s to nab the source for yourself.
  317. The source is in Buddy assembler format.
  318.  
  319. -----=-----
  320. ;3-Key Rollover-128 by Craig Bruce 18-Jun-93 for C= Hacking magazine
  321.  
  322. .org $1500
  323. .obj "@0:keyscan128"
  324.  
  325. scanrows = 11
  326. rollover = 3
  327.  
  328. pa = $dc00
  329. pb = $dc01
  330. pk = $d02f
  331.  
  332. jmp initialInstall
  333.  
  334. ;ugly IRQ patch code.
  335.  
  336. irq = *  ;$1503
  337.    .byte $d8,$20,$0a,$15,$4c,$69,$fa,$38,$ad,$19,$d0,$29,$01,$f0,$07,$8d
  338.    .byte $19,$d0,$a5,$d8,$c9,$ff,$f0,$6f,$2c,$11,$d0,$30,$04,$29,$40,$d0
  339.    .byte $31,$38,$a5,$d8,$f0,$2c,$24,$d8,$50,$06,$ad,$34,$0a,$8d,$12,$d0
  340.    .byte $a5,$01,$29,$fd,$09,$04,$48,$ad,$2d,$0a,$48,$ad,$11,$d0,$29,$7f
  341.    .byte $09,$20,$a8,$ad,$16,$d0,$24,$d8,$30,$03,$29,$ef,$2c,$09,$10,$aa
  342.    .byte $d0,$28,$a9,$ff,$8d,$12,$d0,$a5,$01,$09,$02,$29,$fb,$05,$d9,$48
  343.    .byte $ad,$2c,$0a,$48,$ad,$11,$d0,$29,$5f,$a8,$ad,$16,$d0,$29,$ef,$aa
  344.    .byte $b0,$08,$a2,$07,$ca,$d0,$fd,$ea,$ea,$aa,$68,$8d,$18,$d0,$68,$85
  345.    .byte $01,$8c,$11,$d0,$8e,$16,$d0,$b0,$13,$ad,$30,$d0,$29,$01,$f0,$0c
  346.    .byte $a5,$d8,$29,$40,$f0,$06,$ad,$11,$d0,$10,$01,$38,$58,$90,$07,$20
  347.    .byte $aa,$15,$20,$e7,$c6,$38,$60
  348.  
  349. ;keyscanning entry point
  350.  
  351. main = *
  352.    lda #0               ;check if any keys are held down
  353.    sta pa
  354.    sta pk
  355. -  lda pb
  356.    cmp pb
  357.    bne -
  358.    cmp #$ff
  359.    beq noKeyPressed     ;if not, then don't scan keyboard, goto Kernal
  360.  
  361.    jsr checkJoystick    ;if so, make sure joystick not pressed
  362.    bcc joystickPressed
  363.    jsr keyscan          ;scan the keyboard and store results
  364.    jsr checkJoystick    ;make sure joystick not pressed again
  365.    bcc joystickPressed
  366.    jsr shiftdecode      ;decode the shift keys
  367.    jsr keydecode        ;decode the first 3 regular keys held down
  368.    jsr keyorder         ;see which new keys pressed, old keys released, and
  369.                         ;  determine which key to present to the Kernal
  370.    lda $033e            ;set up for and dispatch to Kernal
  371.    sta $cc
  372.    lda $033f
  373.    sta $cd
  374.    ldx #$ff
  375.    bit ignoreKeys
  376.    bmi ++
  377.    lda prevKeys+0
  378.    cmp #$ff
  379.    bne +
  380.    lda $d3
  381.    beq ++
  382.    lda #88
  383. +  sta $d4
  384.    tay
  385.    jmp ($033a)
  386.  
  387.    noKeyPressed = *     ;no keys pressed; select default scan row
  388.    lda #$7f
  389.    sta pa
  390.    lda #$ff
  391.    sta pk
  392.  
  393.    joystickPressed = *
  394.    lda #$ff             ;record that no keys are down in old 3-key array
  395.    ldx #rollover-1
  396. -  sta prevKeys,x
  397.    dex
  398.    bpl -
  399.    jsr scanCaps         ;scan the CAPS LOCK key
  400.    ldx #$ff
  401.    lda #0
  402.    sta ignoreKeys
  403.  
  404. +  lda #88              ;present "no key held" to Kernal
  405.    sta $d4
  406.    tay
  407.    jmp $c697
  408.  
  409. initialInstall = *      ;install wedge: set restore vector, print message
  410.    jsr install
  411.    lda #<reinstall
  412.    ldy #>reinstall
  413.    sta $0a00
  414.    sty $0a01
  415.    ldx #0
  416. -  lda installMsg,x
  417.    beq +
  418.    jsr $ffd2
  419.    inx
  420.    bne -
  421. +  rts
  422.  
  423.    installMsg = *
  424.    .byte 13
  425.    .asc "keyscan128 installed"
  426.    .byte 0
  427.  
  428. reinstall = *           ;re-install wedge after a RUN/STOP+RESTORE
  429.    jsr install
  430.    jmp $4003
  431.  
  432. install = *             ;guts of installation: set IRQ vector to patch code
  433.    sei                  ;  and initialize scanning variables
  434.    lda #<irq
  435.    ldy #>irq
  436.    sta $0314
  437.    sty $0315
  438.    cli
  439.    ldx #rollover-1
  440.    lda #$ff
  441. -  sta prevKeys,x
  442.    dex
  443.    bpl -
  444.    lda #0
  445.    sta ignoreKeys
  446.    rts
  447.  
  448. mask = $cc
  449.  
  450. keyscan = *             ;scan the (extended) keyboard using the forward
  451.    ldx #$ff             ;  row-wise "slow" technique
  452.    ldy #$ff
  453.    lda #$fe
  454.    sta mask+0
  455.    lda #$ff
  456.    sta mask+1
  457.    jmp +
  458.    nextRow = *
  459. -  lda pb
  460.    cmp pb
  461.    bne -
  462.    sty pa
  463.    sty pk
  464.    eor #$ff
  465.    sta scanTable,x
  466.    sec
  467.    rol mask+0
  468.    rol mask+1
  469. +  lda mask+0
  470.    sta pa
  471.    lda mask+1
  472.    sta pk
  473.    inx
  474.    cpx #scanrows
  475.    bcc nextRow
  476.    rts
  477.  
  478. shiftValue = $d3
  479.  
  480. shiftRows .byte $01,$06,$07,$07,$0a
  481. shiftBits .byte $80,$10,$20,$04,$01
  482. shiftMask .byte $01,$01,$02,$04,$08
  483.  
  484. shiftdecode = *         ;see which "shift" keys are held down, put them into
  485.    jsr scanCaps         ;  proper positions in $D3 (shift flags), and remove
  486.    ldy #4               ;  them from the scan matrix
  487. -  ldx shiftRows,y
  488.    lda scanTable,x
  489.    and shiftBits,y
  490.    beq +
  491.    lda shiftMask,y
  492.    ora shiftValue
  493.    sta shiftValue
  494.    lda shiftBits,y
  495.    eor #$ff
  496.    and scanTable,x
  497.    sta scanTable,x
  498. +  dey
  499.    bpl -
  500.    rts
  501.  
  502. scanCaps = *            ;scan the CAPS LOCK key from the processor I/O port
  503. -  lda $1
  504.    cmp $1
  505.    bne -
  506.    eor #$ff
  507.    and #$40
  508.    lsr
  509.    lsr
  510.    sta shiftValue
  511.    rts
  512.  
  513. newpos = $cc
  514. keycode = $d4
  515. xsave = $cd
  516.  
  517. keydecode = *           ;get the scan codes of the first three keys held down
  518.    ldx #rollover-1      ;initialize: $ff means no key held
  519.    lda #$ff
  520. -  sta newKeys,x
  521.    dex
  522.    bpl -
  523.    ldy #0
  524.    sty newpos
  525.    ldx #0
  526.    stx keycode
  527.  
  528.    decodeNextRow = *    ;decode a row, incrementing the current scan code
  529.    lda scanTable,x
  530.    beq decodeContinue
  531.                         ;at this point, we know that the row has a key held
  532.    ldy keycode
  533. -  lsr
  534.    bcc ++
  535.    pha                  ;here we know which key it is, so store its scan code,
  536.    stx xsave            ;  up to 3 keys
  537.    ldx newpos
  538.    cpx #rollover
  539.    bcs +
  540.    tya
  541.    sta newKeys,x
  542.    inc newpos
  543. +  ldx xsave
  544.    pla
  545. +  iny
  546.    cmp #$00
  547.    bne -
  548.  
  549.    decodeContinue = *
  550.    clc
  551.    lda keycode
  552.    adc #8
  553.    sta keycode
  554.    inx
  555.    cpx #scanrows
  556.    bcc decodeNextRow
  557.    rts
  558.  
  559. ;keyorder: determine what key to present to the Kernal as being logically the
  560. ;only one pressed, based on which keys previously held have been released and
  561. ;which new keys have just been pressed
  562.  
  563. keyorder = *
  564.    ;** remove old keys no longer held from old scan code array
  565.    ldy #0
  566.    nextRemove = *
  567.    lda prevKeys,y       ;get current old key
  568.    cmp #$ff
  569.    beq ++
  570.    ldx #rollover-1      ;search for it in the new scan code array
  571. -  cmp newKeys,x
  572.    beq +
  573.    dex
  574.    bpl -
  575.    tya                  ;here, old key no longer held; remove it
  576.    tax
  577. -  lda prevKeys+1,x
  578.    sta prevKeys+0,x
  579.    inx
  580.    cpx #rollover-1
  581.    bcc -
  582.    lda #$ff
  583.    sta prevKeys+rollover-1
  584.    sta ignoreKeys
  585. +  iny                  ;check next old key
  586.    cpy #rollover
  587.    bcc nextRemove
  588.  
  589.    ;** insert new keys at front of old scan code array 
  590. +  ldy #0
  591.    nextInsert = *
  592.    lda newKeys,y        ;get current new key
  593.    cmp #$ff
  594.    beq ++
  595.    ldx #rollover-1      ;check old scan code array for it
  596. -  cmp prevKeys,x
  597.    beq +
  598.    dex
  599.    bpl -
  600.    pha                  ;it's not there, so insert new key at front, exit
  601.    ldx #rollover-2
  602. -  lda prevKeys+0,x
  603.    sta prevKeys+1,x
  604.    dex
  605.    bpl -
  606.    lda #0
  607.    sta ignoreKeys
  608.    pla
  609.    sta prevKeys+0
  610.    ldy #rollover        ;(trick to exit)
  611. +  iny
  612.    cpy #rollover
  613.    bcc nextInsert
  614. +  rts                  ;now, the head of the old scan code array contains
  615.                         ;  the scan code to present to the Kernal, and other
  616.                         ;  positions represent keys that are also held down
  617.                         ;  that have already been processed and therefore can
  618.                         ;  be ignored until they are released
  619.  
  620. checkJoystick = *       ;check if joystick is pushed: un-select all keyboard
  621.    lda #$ff             ;  rows and see if there are any "0"s in the scan
  622.    sta pa               ;  status register
  623.    sta pk
  624. -  lda pb
  625.    cmp pb
  626.    bne -
  627.    cmp #$ff
  628.    lda #$7f             ;restore to default Kernal row selected (to the one
  629.    sta pa               ;  containing the STOP key)
  630.    lda #$ff
  631.    sta pk
  632.    rts
  633.  
  634. ;global variables
  635.  
  636. scanTable  .buf scanrows        ;values of the eleven keyboard scan rows
  637. newKeys    .buf rollover        ;codes of up to three keys held simultaneously
  638. ignoreKeys .buf 1               ;flag: if an old key has been released and no
  639.                                 ;  new key has been pressed, stop all key
  640.                                 ;  repeating
  641. prevKeys   .buf rollover+2      ;keys held on previous scan
  642. -----=-----
  643.  
  644. And that's all there is to it.  :-)
  645.  
  646. 5. THE C-64 KEYSCANNER
  647.  
  648. The boot program for the C-64 keyscanner is as follows:
  649.  
  650. 10 d=peek(186)
  651. 20 if a=1 then 60
  652. 30 a=1
  653. 40 load"keyscan64",d,1
  654. 50 goto 10
  655. 60 sys 49152+5*256  : rem $c500
  656.  
  657. It is very much like boot programs for other machine language programs that
  658. don't load at the start of BASIC.  It will load the binary from the last
  659. device accessed, and activate it.
  660.  
  661. A listing of the C-64 keyscanning code is not presented here because it is so
  662. similar to the C-128 listing.  The only things that are different are the
  663. Kernal patches and the keyboard scanning (because the three extra rows don't
  664. have to be scanned).  The IRQ had to be substantially copied from the ROM,
  665. again, to get at the call to the key scanning.  Also, rather than taking
  666. over the BASIC reset vector (since there isn't one), the NMI vector is
  667. taken over to insure the survival of the key scanner after a RUN/STOP+RESTORE.
  668. A bit of its preamble also had to be copied out of ROM to get at the good
  669. stuff.  If you want a copy of the C-64 listing, you can e-mail me.
  670.  
  671. 6. UUENCODED FILES
  672.  
  673. Here are the binary executables in uuencoded form.  The CRC32s of the four
  674. files are as follows:
  675.  
  676. crc32 = 3398956287 for "keyscan128"
  677. crc32 = 2301926894 for "keyscan64.boot"
  678. crc32 = 1767081474 for "keyscan64"
  679. crc32 = 1604419896 for "keyshow"
  680.  
  681. begin 640 keyscan128
  682. M`!5,'A;8(`H53&GZ.*T9T"D!\`>-&="EV,G_\&\L$=`P!"E`T#$XI=CP+"38
  683. M4`:M-`J-$M"E`2G]"01(K2T*2*T1T"E_"2"HK1;0)-@P`RGO+`D0JM`HJ?^-
  684. M$M"E`0D"*?L%V4BM+`I(K1'0*5^HK1;0*>^JL`BB!\K0_>KJJFB-&-!HA0&,
  685. M$=".%M"P$ZTPT"D!\`REV"E`\`:M$=`0`3A8D`<@JA4@Y\8X8*D`C0#<C2_0
  686. MK0'<S0'<T/C)__`Z((D7D#\@<18@B1>0-R"W%B#L%B`L%ZT^`X7,K3\#A<VB
  687. M_RRT%S`QK;47R?_0!J73\":I6(74J&PZ`ZE_C0#<J?^-+]"I_Z("G;47RA#Z
  688. M(-T6HO^I`(VT%ZE8A=2H3)?&(%46J4^@%HT`"HP!"J(`O3D6\`8@TO_HT/5@
  689. M#4M%65-#04XQ,C@@24Y35$%,3$5$`"!5%DP#0'BI`Z`5C10#C!4#6*("J?^=
  690. MM1?*$/JI`(VT%V"B_Z#_J?Z%S*G_A<U,F!:M`=S-`=S0^(P`W(POT$G_G:87
  691. M.";,)LVES(T`W*7-C2_0Z.`+D-E@`08'!PJ`$"`$`0$!`@0((-T6H`2^J!:]
  692. MIA<YK1;P$KFR%@73A=.YK19)_SVF%YVF%X@0X&"E`<4!T/I)_RE`2DJ%TV"B
  693. M`JG_G;$7RA#ZH`"$S*(`AM2]IA?P'*342I`22(;-ILS@`[`&F)VQ%^;,ILUH
  694. MR,D`T.88I=1I"(74Z.`+D--@H`"YM1?)__`DH@+=L1?P&,H0^)BJO;87G;47
  695. MZ.`"D/6I_XVW%XVT%\C``Y#5H`"YL1?)__`FH@+=M1?P&LH0^$BB`;VU%YVV
  696. M%\H0]ZD`C;07:(VU%Z`#R,`#D--@J?^-`-R-+]"M`=S-`=S0^,G_J7^-`-RI
  697. 9_XTOT&``````````````````````````````
  698. `
  699. end
  700. begin 640 keyscan64.boot
  701. M`0@."`H`1++"*#$X-BD`'0@4`(L@0;(Q(*<@-C``)0@>`$&R,0`Z""@`DR)+
  702. M15E30T%.-C0B+$0L,0!#"#(`B2`Q,`!@"#P`GB`T.3$U,JHUK#(U-B`@.B"/
  703. )("1#-3`P````````
  704. `
  705. end
  706. begin 640 keyscan64
  707. M`,5,Q,5,$,9,ZL4@ZO^ES-`IQLW0):D4A<VDTT;/KH<"L=&P$>;/A<X@).JQ
  708. M\XV'`JZ&`J7.28`@'.JE`2D0\`J@`(3`I0$)(-`(I<#0!J4!*1^%`2!9Q4Q^
  709. MZJD`C0#<K0'<S0'<T/C)__`Y(%C'D#D@6,8@6,>0,2"-QB"[QB#[QJF!A?6I
  710. MZX7VHO\L>,<P+:UYQ\G_T`>MC0+P(:E`A<NH;(\"J7^-`-RI_Z("G7G'RA#Z
  711. M(+7&HO^I`(UXQZE`A<NH3";K(.K%H@"]U<7P!B#2_^C0]6!+15E30T%.-C0@
  712. M24Y35$%,3$5$#0!XJ0F@Q8T4`XP5`ZDGH,:-&`.,&0-8H@*I_YUYQ\H0^JD`
  713. MC7C'8'BI,:#JC10#C!4#J4>@_HT8`XP9`UA@2(I(F$BI?XT-W:P-W3`?(`+]
  714. MT`-L`H`@O/8@X?_0#R`5_2"C_2`8Y2#JQ6P"H$QR_J+_H/^I_H7U3';&K0'<
  715. MS0'<T/B,`-Q)_YUMQS@F]:7UC0#<Z.`(D.-@`08'!X`0(`0!`0($(+7&H`.^
  716. M@<:];<<YA<;P%+F)Q@V-`HV-`KF%QDG_/6W'G6W'B!#>8*D`C8T"8*("J?^=
  717. M=<?*$/J@`(3UH@"&R[UMQ_`<I,M*D!)(AO:F]>`#L`:8G77'YO6F]FC(R0#0
  718. MYABERVD(A<OHX`B0TV"@`+EYQ\G_\"2B`MUUQ_`8RA#XF*J]>L>=><?HX`*0
  719. M]:G_C7O'C7C'R,`#D-6@`+EUQ\G_\":B`MUYQ_`:RA#X2*(!O7G'G7K'RA#W
  720. MJ0"->,=HC7G'H`/(P`.0TV"I_XT`W*T!W,T!W-#XR?^I?XT`W&``````````
  721. *````````````````
  722. `
  723. end
  724. begin 640 keyshow
  725. M`!-,"Q,``````````*F3(-+_(#83H@`@%Q0@5A.B"B`7%"!T$Z(4(!<4(/03
  726. MHAX@%Q0@3!1,$!-XH@"I_HT`W*T!W,T!W-#X2?^=`Q,X+@#<Z.`(D.I88'BB
  727. M!ZE_C0#<K0'<S0'<T/A)_YT#$SAN`-S*$.Q88'BI`(T"W*G_C0/<H`>I?X4#
  728. MI0.-`=RM`-S-`-S0^*+_C@'<2?^B!PH^`Q/*$/DX9@.($-VI_XT"W*D`C0/<
  729. M6&!XJ0"-`MRI_XT#W*`'J7^%`Z4#C0'<K0#<S0#<T/BB_XX!W$G_H@<*/@,3
  730. MRA#Y.&8#B!#=J?^-`MRI`(T#W%A@>*(`J?Z%`Z4#C0#<K0'<S0'<T/A)_YT#
  731. M$S@F`^C@")#F6&"@!(8$A`6B`+T#$R`V%!BE!&DHA020`N8%Z.`(D.I@A0*@
  732. 6!T8"J0!I,)$$B!#U8````````*(`8```
  733. `
  734. end
  735. ================================================================================
  736. In the Next Issue:
  737.  
  738. Next Issue:
  739.  
  740. Tech-tech - more resolution to vertical shift
  741.  
  742. One time half of the demos had pictures waving horizontally on the width
  743. of the whole screen. This effect is named tech-tech and it is done using
  744. character graphics. How exactly and is the same possible with sprites ?
  745.  
  746. THE DESIGN OF ACE-128/64
  747.  
  748. Design of ACE-128/64 command shell environment (and kernel replacement).  This
  749. will cover the organization, internal operation, and the kernel interface of
  750. the still-under-development but possibly catching-on kernel replacement for
  751. the 128 and 64.  The article will also discuss future directions and designs
  752. for the ACE environment.  ACE has a number of definite design advantages over
  753. other kernel replacements, and a few disadvantages as well.
  754.  
  755.