home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / genie-commodore-file-library / Information / CHACK7.TXT1.SFX / chack7.txt1
Encoding:
Text File  |  1990-02-12  |  40.0 KB  |  909 lines

  1.  
  2.  C000   RAM     RAM     RAM     RAM     RAM     RAM     RAM     RAM      -
  3. -----------------------------------------------------------------------------
  4.  B000
  5.         BASIC   RAM     RAM     RAM     RAM     BASIC   ROMH    ROMH     -
  6.  A000
  7. -----------------------------------------------------------------------------
  8.  9000
  9.         RAM     RAM     RAM     RAM     RAM     ROML    RAM     ROML    ROML(*
  10.  8000
  11. -----------------------------------------------------------------------------
  12.  7000
  13.  
  14.  6000
  15.         RAM     RAM     RAM     RAM     RAM     RAM     RAM     RAM      -
  16.  5000
  17.  
  18.  4000
  19. -----------------------------------------------------------------------------
  20.  3000    
  21.  
  22.  2000   RAM     RAM     RAM     RAM     RAM     RAM     RAM     RAM      -
  23.  
  24.  1000
  25. -----------------------------------------------------------------------------
  26.  0000   RAM     RAM     RAM     RAM     RAM     RAM     RAM     RAM     RAM
  27. -----------------------------------------------------------------------------
  28.  
  29.     *) Internal memory does not respond to write accesses to these areas.
  30.  
  31.  
  32.     Legend: Kernal      E000-FFFF       Kernal ROM.
  33.  
  34.             IO/C        D000-DFFF       I/O address space or Character
  35.                                         generator ROM, selected by -CHAREN.
  36.                                         If the CHAREN bit is clear,
  37.                                         the character generator ROM is
  38.                                         chosen. If it is set, the
  39.                                         I/O chips are accessible.
  40.  
  41.             IO/RAM      D000-DFFF       I/O address space or RAM,
  42.                                         selected by -CHAREN.
  43.                                         If the CHAREN bit is clear,
  44.                                         the character generator ROM is
  45.                                         chosen. If it is set, the
  46.                                         internal RAM is accessible.
  47.  
  48.             I/O         D000-DFFF       I/O address space.
  49.                                         The -CHAREN line has no effect.
  50.  
  51.             BASIC       A000-BFFF       BASIC ROM.
  52.  
  53.             ROMH        A000-BFFF or    External ROM with the -ROMH line
  54.                         E000-FFFF       connected to its -CS line.
  55.  
  56.             ROML        8000-9FFF       External ROM with the -ROML line
  57.                                         connected to its -CS line.
  58.  
  59.             RAM         various ranges  Commodore 64's internal RAM.
  60.  
  61.             -           1000-7FFF and   Open address space. 
  62.                         A000-CFFF       The Commodore 64's memory chips
  63.                                         do not detect any memory accesses
  64.                                         to this area except the VIC-II's
  65.                                         DMA and memory refreshes.
  66.  
  67.     NOTE:   Whenever the processor tries to write to any ROM area
  68.             (Kernal, BASIC, CHAROM, ROML, ROMH), the data will get
  69.             "through the ROM" to the C64's internal RAM.
  70.  
  71.             For this reason, you can easily copy data from ROM to RAM,
  72.             without any bank switching. But implementing external
  73.             memory expansions without DMA is very hard, as you have to
  74.             use the Ultimax memory configuration, or the data will be
  75.             written both to internal and external RAM.
  76.  
  77.             However, this is not true for the Ultimax game
  78.             configuration. In that mode, the internal RAM ignores all
  79.             memory accesses outside the area $0000-$0FFF, unless they are
  80.             performed by the VIC, and you can write to external memory
  81.             at $1000-$CFFF and $E000-$FFFF, if any, without changing
  82.             the contents of the internal RAM.
  83.  
  84.  
  85. _A note concerning the I/O area_
  86.  
  87.   The I/O area is divided as follows:
  88.  
  89.      Address range  Owner
  90.      -------------  -----
  91.        D000-D3FF    MOS 6567/6569 VIC-II Video Interface Controller
  92.        D400-D7FF    MOS 6581 SID Sound Interface Device
  93.        D800-DBFF    Color RAM (only lower nybbles are connected)
  94.        DC00-DCFF    MOS 6526 CIA Complex Interface Adapter #1
  95.        DD00-DDFF    MOS 6526 CIA Complex Interface Adapter #2
  96.        DE00-DEFF    User expansion #1 (-I/O1 on Expansion Port)
  97.        DF00-DFFF    User expansion #2 (-I/O2 on Expansion Port)
  98.  
  99.   As you can see, the address ranges for the chips are much larger
  100. than required. Because of this, you can access the chips through
  101. multiple memory areas. The VIC-II appears in its window every $40
  102. addresses. For instance, the addresses $D040 and $D080 are both mapped
  103. to the Sprite 0 X co-ordinate register. The SID has one register
  104. selection line less, thus it appears at every $20 bytes. The CIA
  105. chips have only 16 registers, so there are 16 copies of each in their
  106. memory area.
  107.  
  108.   However, you should not use other addresses than those specified by
  109. Commodore. For instance, the Commodore 128 mapped its additional I/O
  110. chips to this same memory area, and the SID responds only to the
  111. addresses D400-D4FF, also when in C64 mode. And the Commodore 65,
  112. which unfortunately did not make its way to the market, could narrow
  113. the memory window reserved for the MOS 6569/6567 VIC-II (or CSG 4567
  114. VIC-III in that machine).
  115.  
  116.  
  117. _The video chip_
  118.  
  119.   The MOS 6567/6569 VIC-II Video Interface Controller has access to
  120. only 16 kilobytes at a time. To enable the VIC-II to access the whole
  121. 64 kB memory space, the main memory is divided to four banks of 16 kB
  122. each. The lines PA0 and PA1 of the second CIA are the inverse of the
  123. virtual VIC-II address lines VA14 and VA15, respectively. To select a
  124. VIC-II bank other than the default, you must program the CIA lines to
  125. output the desired bit pair. For instance, the following code selects
  126. the memory area $4000-$7FFF (bank 1) for the video controller:
  127.  
  128.     LDA $DD02 ; Data Direction Register A
  129.     ORA #$03  ; Set pins PA0 and PA1 to outputs
  130.     STA $DD02
  131.     LDA $DD00
  132.     AND #$FC  ; Mask the lowmost bit pair off
  133.     ORA #$02  ; Select VIC-II bank 1 (the inverse of binary 01 is 10)
  134.     STA $DD00
  135.  
  136.   Why should you set the pins to outputs? Hardware RESET resets all
  137. I/O lines to inputs, and thanks to the CIA's internal pull-up
  138. resistors, the inputs actually output logical high voltage level. So,
  139. upon -RESET, the video bank 0 is selected automatically, and older
  140. Kernals could leave it uninitialized.
  141.  
  142.   Note that the VIC-II always fetches its information from the
  143. internal RAM, totally ignoring the memory configuration lines. There
  144. is only one exception to this rule: The character generator ROM.
  145. Unless the Ultimax mode is selected, VIC-II "sees" character generator
  146. ROM in the memory areas 1000-1FFF and 9000-9FFF. If the Ultimax
  147. configuration is active, the VIC-II will fetch all data from the
  148. internal RAM.
  149.  
  150.  
  151. _An application: Making an operating system extension_
  152.  
  153.   If you are making a memory resident program and want to make it as
  154. invisible to the system as possible, probably the best method is
  155. keeping most of your code under the I/O area (in the RAM at
  156. $D000-$DFFF). This area is very safe, since programs utilizing it are
  157. rare, since they are very difficult to implement and to debug. You
  158. need only a short routine in the normally visible RAM that pushes the
  159. current value of the processor's I/O register $01 on stack, switches
  160. RAM on to $D000-$DFFF and jumps to this area. Returning from the
  161. $D000-$DFFF area is possible even without any routine in the normally
  162. visible RAM area. Just write an RTS or an RTI to an I/O register and
  163. return through it.
  164.  
  165.   But what if your program needs to use I/O? And how can you write the
  166. return instruction to an I/O register while the I/O area is switched
  167. off? You need a swap area for your program in normally visible memory.
  168. The first thing your routine at $D000-$DFFF does is copying the I/O
  169. routines (or the whole program) to normally visible memory, swapping
  170. the bytes. For instance, if your I/O routines are initially being
  171. stored at $D200-$D3FF, exchange the bytes in $D200-$D3FF with the
  172. contents of $C000-$C1FF. Now you can call the I/O routines from your
  173. routine at $D000-$DFFF, and the I/O routines can switch the I/O area
  174. temporarily on to access the I/O chips. And right before exiting your
  175. program at $D000-$DFFF swaps the old contents of that I/O routine area
  176. in, e.g. exchanges the memory areas $D200-$D3FF and $C000-$C1FF
  177. again.
  178.  
  179.   What I/O registers can you use for the return instruction? There are
  180. basically two alternatives: 8-bit VIC sprite registers or either CIA's
  181. serial port register. The VIC registers are easiest to use, as they
  182. act precisely like memory places: you can easily write the desired
  183. value to a register. But the CIA register is usually better, as
  184. changing the VIC registers might change the screen layout.
  185.  
  186.   However, also the SP register has some drawbacks: If the machine's
  187. CNT1 and CNT2 lines are connected to a frequency source, you must stop
  188. either CIA's Timer A to use the SP register method. Normally the 1st
  189. CIA's Timer A is the main hardware interrupt source. And if you use
  190. the Kernal's RS232, you cannot stop the 2nd CIA's Timer A either. Also,
  191. if you don't want to lose any CIA interrupts, you might want to know
  192. that executing the RTS or RTI at SP register has the side effect of
  193. reading the Interrupt Control Register, thus acknowledging an interrupt
  194. that might have been waiting.
  195.  
  196.   If you can't use either method, you can use either CIA's ToD seconds
  197. or minutes or ToD alarm time for storing an RTI. Or, if you don't want
  198. to alter any registers, use the VIC-II's light pen register. Before
  199. exiting, wait for appropriate raster line and trig the light pen latch
  200. with CIA1's PB4 bit. However, this method assumes that the control
  201. port 1's button/light pen line remains up for that frame. After
  202. trigging the light pen, causing the light pen Y co-ordinate register
  203. ($D014) to be $40 or $60, you have more than half a frame time to
  204. restore the state of the I/O chips and return through the register.
  205.  
  206.   You can also use the SID to store an RTI or RTS command. How is this
  207. possible, you might ask. After all, the chip consists of read only or
  208. write only registers. However, there are two registers that can be
  209. controlled by program, the envelope generator and oscillator outputs
  210. of the third voice. This method requires you to change the frequency
  211. of voice 3 and to select a waveform for it. This will affect on the
  212. voice output by turning the voice 3 off, but who would keep the voice
  213. 3 producing a tone while calling an operating system routine?
  214.  
  215.   Also keep in mind that the user could press RESTORE while the Kernal
  216. ROM and I/O areas are disabled. You could write your own non-maskable
  217. interrupt (NMI) handler (using the NMI vector at $FFFA), but a fast
  218. loader that uses very tight timing would still stop working if the
  219. user pressed RESTORE in the middle of a data block transfer. So, to
  220. make a robust program, you have to disable NMI interrupts. But how is
  221. this possible? They are Non-Maskable after all. The NMI interrupt is
  222. edge-sensitive, the processor jumps to NMI handler only when the -NMI
  223. line drops from +5V to ground. To disable the interrupt, simply cause
  224. an NMI with CIA2's timer, but don't read the Interrupt Control
  225. register. If you need to read $DD0D in your program, you must add a
  226. NMI handler just in case the user presses RESTORE. And don't forget to
  227. raise the -NMI line upon exiting the program.  Otherwise the RESTORE
  228. key does not work until the user issues a -RESET or reads the ICR
  229. register explicitly. (The Kernal does not read $DD0D, unless it is
  230. handling an interrupt.) This can be done automatically by the two
  231. following SP register examples due to one of the 6510's undocumented
  232. features (refer to the descriptions of RTS and RTI below).
  233.  
  234.         ; Returning via VIC sprite 7 X co-ordinate register
  235.  
  236.         Initialization:   ; This is executed when I/O is switched on
  237.                 LDA #$60
  238.                 STA $D015 ; Write RTS to VIC register $15.
  239.  
  240.         Exiting:          ; NOTE: This procedure must start at VIC register
  241.                           ; $12. You have multiple alternatives, as the VIC
  242.                           ; appears in memory at $D000+$40*n, where $0<=n<=$F.
  243.  
  244.                 PLA       ; Pull the saved 6510 I/O register state from stack
  245.                 STA $01   ; Restore original memory bank configuration
  246.                           ; Now the processor fetches the RTS command from the
  247.                           ; VIC register $15.
  248.  
  249.  
  250.         ; Returning via CIA 2's ToD or ToD alarm seconds register
  251.  
  252.         Initialization:   ; This is executed when I/O is switched on
  253.                 LDA #$40  
  254.                 STA $DD08 ; Set ToD tenths of seconds
  255.                           ; (clear it so that the seconds register
  256.                           ; would not overflow)
  257.                           ; If ToD alarm register is selected, this
  258.                           ; instruction will be unnecessary.
  259.                 STA $DD09 ; Set ToD seconds
  260.                 LDA $DD0B ; Read ToD hours (freeze ToD display)
  261.  
  262.         Exiting:          ; NOTE: This procedure must start at CIA 2 register
  263.                           ; $6. As the CIA 2 appears in memory at $DD00+$10*n,
  264.                           ; where 0<=n<=$F, you have sixteen alternatives.
  265.                 PLA
  266.                 STA $01   ; Restore original memory bank configuration
  267.                           ; Now the processor fetches the RTS command from
  268.                           ; the CIA 2 register $9.
  269.  
  270.  
  271.         ; Returning via CIA 2's SP register (assuming that CNT2 is stable)
  272.  
  273.         Initialization:   ; This is executed when I/O is switched on
  274.                 LDA $DD0E ; CIA 2's Control Register A
  275.                 AND #$BF  ; Set Serial Port to input
  276.                 STA $DD0E ; (make the SP register to act as a memory place)
  277.                 LDA #$60
  278.                 STA $DD0C ; Write RTS to CIA 2 register $C.
  279.  
  280.         Exiting:          ; NOTE: This procedure must start at CIA 2 register
  281.                           ; $9. As the CIA 2 appears in memory at $DD00+$10*n,
  282.                           ; where 0<=n<=$F, you have sixteen alternatives.
  283.                 PLA
  284.                 STA $01   ; Restore original memory bank configuration
  285.                           ; Now the processor fetches the RTS command from
  286.                           ; the CIA 2 register $C.
  287.  
  288.  
  289.         ; Returning via CIA 2's SP register, stopping the Timer A
  290.         ; and forcing SP2 and CNT2 to output
  291.  
  292.         Initialization:   ; This is executed when I/O is switched on
  293.                 LDA $DD0E ; CIA 2's Control Register A
  294.                 AND #$FE  ; Stop Timer A
  295.                 ORA #$40  ; Set Serial Port to output
  296.                 STA $DD0E ; (make the SP register to act as a memory place)
  297.                 LDA #$60
  298.                 STA $DD0C ; Write RTS to CIA register $C.
  299.  
  300.         Exiting:          ; NOTE: This procedure must start at CIA 2 register
  301.                           ; $9. As the CIA 2 appears in memory at $DD00+$10*n,
  302.                           ; where 0<=n<=$F, you have sixteen alternatives.
  303.                 PLA
  304.                 STA $01   ; Restore original memory bank configuration
  305.                           ; Now the processor fetches the RTS command from
  306.                           ; the CIA 2 register $C.
  307.  
  308.         ; Returning via SID oscillator 3 output register
  309.  
  310.         Initialization:   ; This is executed when I/O is switched on
  311.                 LDA #$20  ; Select sawtooth waveform
  312.                 STA $D412 ; but do not enable the sound
  313.                 LDY #$00  ; Select frequency
  314.                 STY $D40E ; (system clock)/$FF00,
  315.                 LDA #$FF  ; causing the OSC3 output to increment by one
  316.                 STY $D40F ; every $10000/$FF00 cycles.
  317.  
  318.                 LDA #$0E
  319.                 LDX #$60
  320.  
  321.                 BIT $D41B ; Wait for the oscillator 3 output
  322.                 BMI *-3   ; to be in the range
  323.                 BVS *-5   ; $00-$3F.
  324.                 BIT $D41B ; Wait for the oscillator 3 output
  325.                 BVC *-3   ; to be at least $40.
  326.  
  327.                 STA $D40F ; Slow down the frequency to (system clock)/$0E00.
  328.                 CPX $D41B ; Wait for the oscillator 3
  329.                 BNE *-3   ; output to reach $60 (RTS)
  330.  
  331.                 STY $D40F ; Reset the frequency of voice 3
  332.                           ; (stop the OSC3 register from increasing)
  333.  
  334.         Exiting:          ; NOTE: This procedure must start at SID register
  335.                           ; $18. As the SID appears in memory at $D400+$20*n,
  336.                           ; where 0<=n<=$20, you have thirty-two alternatives.
  337.                           ; However, in C128 there are only eight alternatives,
  338.                           ; as the SID is only at $D400-$D4FF.
  339.  
  340.                 PLA
  341.                 STA $01   ; Restore original memory bank configuration
  342.                           ; Now the processor fetches the RTS command from
  343.                           ; the SID register $1B.
  344.  
  345.  
  346.   For instance, if you want to make a highly compatible fast loader,
  347. make the ILOAD vector ($0330) point to the beginning of the stack
  348. area. Remember that the BASIC interpreter uses the first bytes of
  349. stack while converting numbers to text. A good address is $0120.
  350. Robust programs practically never use so much stack that it could
  351. corrupt this routine. Usually only crunched programs (demos and alike)
  352. use all stack in the decompression phase. They also make use of the
  353. $D000-$DFFF area.
  354.  
  355.   This stack routine will jump to your routine at $D000-$DFFF, as
  356. described above. For performance's sake, copy the whole byte transfer
  357. loop to the swap area, e.g. $C000-$C1FF, and call that subroutine
  358. after doing the preliminary work. But what about files that load over
  359. $C000-$C1FF? Wouldn't that destroy the transfer loop and jam the
  360. machine? Not necessarily. If you copy those bytes to your swap area at
  361. $D000-$DFFF, they will be loaded properly, as your program restores
  362. the original $C000-$C1FF area.
  363.  
  364.   If you want to make your program user-friendly, put a vector
  365. initialization routine to the stack area as well, so that the user can
  366. restore the fast loader by issuing a SYS command, rather than loading
  367. it each time he has pressed RESET.
  368.  
  369.  
  370. _An example: A "hello world" program_
  371.  
  372.   To help you in getting started, I have written a small example
  373. program that echoes the famous message "hello, world!" to standard
  374. output (normally screen) using the Kernal's CHROUT subroutine. After
  375. the initialization routine has been run, the program can be started by
  376. commanding SYS 300. I used the Commodore 128's machine language
  377. monitor to put it up, but it was still pretty difficult to debug the
  378. program. Here it is in uuencoded format:
  379.  
  380. begin 644 hello
  381. M`0@+",D'GC(P-C$```!XI0%(*?B%`:(,O3`(G2P!RA#WHHN]/`B=8]W*T/=H
  382. MA0%88*4!JBGX"01XA0%,I-WF`:*!C@W=H@".!=WHC@3=HMV.#MVB0(X,W<8!
  383. M8*4!2`D#A0&@#+DSP"#2_X@0]VB%`6`A1$Q23U<@+$],3$5(BDBM^O](K?O_
  384. M2*D6C?K_J<"-^_\@W-T@`,!HC?O_:(WZ_R`=P"#<W6BHJ0!(NOX"`=`#_@,!
  385. 5A`&@/[X`P+EDW9D`P(J99-V($/!@
  386. `
  387. end
  388.  
  389.   In order to fully understand the operation of this program, you need
  390. to know how the instructions RTI, RTS and PHA work. There is some work
  391. going on to reverse engineer the NMOS 6502 microprocessor to large
  392. extent, and it is now known for most instructions what memory places
  393. they access during their execution and for what purpose. The internal
  394. procedures haven't been described in detail yet, but these
  395. descriptions should be easier to read anyway.
  396.  
  397.   For curiosity, I quote here the description of all instructions that
  398. use the stack. The descriptions of internal operations are yet
  399. inaccurate, but the memory accesses have been verified with an
  400. oscilloscope. I will mail copies the whole document upon request. When
  401. finished, the document will be put on an FTP site.
  402.  
  403.  
  404.      JSR
  405.  
  406.         #  address R/W description
  407.        --- ------- --- -------------------------------------------------
  408.         1    PC     R  fetch opcode, increment PC
  409.         2    PC     R  fetch address's low byte to latch, increment PC
  410.         3  $0100,S  R
  411.         4  $0100,S  W  push PCH on stack, decrement S
  412.         5  $0100,S  W  push PCL on stack, decrement S
  413.         6    PC     R  copy latch to PCL, fetch address's high byte to
  414.                        latch, copy latch to PCH
  415.  
  416.  
  417.      RTS
  418.  
  419.         #  address R/W description
  420.        --- ------- --- -----------------------------------------------
  421.         1    PC     R  fetch opcode, increment PC
  422.         2    PC     R  read next instruction byte (and throw it away),
  423.                        increment PC
  424.         3  $0100,S  R  increment S
  425.         4  $0100,S  R  pull PCL from stack, increment S
  426.         5  $0100,S  R  pull PCH from stack
  427.         6    PC     R  increment PC
  428.  
  429.  
  430.      BRK
  431.  
  432.         #  address R/W description
  433.        --- ------- --- -----------------------------------------------
  434.         1    PC     R  fetch opcode, increment PC
  435.         2    PC     R  read next instruction byte (and throw it away),
  436.                        increment PC
  437.         3  $0100,S  W  push PCH on stack, decrement S
  438.         4  $0100,S  W  push PCL on stack, decrement S
  439.         5  $0100,S  W  push P on stack (with B flag set), decrement S,
  440.                        set I flag
  441.         6   $FFFE   R  fetch PCL
  442.         7   $FFFF   R  fetch PCH
  443.  
  444.  
  445.      RTI
  446.  
  447.         #  address R/W description
  448.        --- ------- --- -----------------------------------------------
  449.         1    PC     R  fetch opcode, increment PC
  450.         2    PC     R  read next instruction byte (and throw it away),
  451.                        increment PC
  452.         3  $0100,S  R  increment S
  453.         4  $0100,S  R  pull P from stack, increment S
  454.         5  $0100,S  R  pull PCL from stack, increment S
  455.         6  $0100,S  R  pull PCH from stack
  456.  
  457.  
  458.      PHA, PHP
  459.  
  460.         #  address R/W description
  461.        --- ------- --- -----------------------------------------------
  462.         1    PC     R  fetch opcode, increment PC
  463.         2    PC     R  read next instruction byte (and throw it away),
  464.                        increment PC
  465.         3  $0100,S  W  push register on stack, decrement S
  466.  
  467.  
  468.      PLA, PLP
  469.  
  470.         #  address R/W description
  471.        --- ------- --- -----------------------------------------------
  472.         1    PC     R  fetch opcode, increment PC
  473.         2    PC     R  read next instruction byte (and throw it away),
  474.                        increment PC
  475.         3  $0100,S  R  increment S
  476.         4  $0100,S  R  pull register from stack
  477.  
  478.  
  479.   The example program consists of three parts. The first part
  480. transfers the other parts to appropriate memory areas. The second part
  481. is located in stack area (300-312), and it invokes the third part, the
  482. main module.
  483.  
  484.   The loader part ($0801-$08C7) is as follows:
  485.  
  486.         1993 SYS2061
  487.  
  488.         080D SEI          Disable interrupts.
  489.         080E LDA $01
  490.         0810 PHA          Store the state of the processor's I/O lines.
  491.         0811 AND #$F8
  492.         0813 STA $01      Select 64 kB RAM memory configuration.
  493.  
  494.         0815 LDX #$0C     Copy the invoking part to 300-312.
  495.         0817 LDA $0830,X
  496.         081A STA $012C,X
  497.         081D DEX
  498.         081E BPL $0817
  499.  
  500.         0820 LDX #$8B     Copy the main part to $DD64-$DDEE.
  501.         0822 LDA $083C,X
  502.         0825 STA $DD63,X
  503.         0828 DEX
  504.         0829 BNE $0822
  505.  
  506.         082B PLA          Restore original memory configuration.
  507.         082C STA $01
  508.         082E CLI          Enable interrupts.
  509.         082F RTS          Return.
  510.  
  511.   The user invokes the following part by issuing SYS 300. This part
  512. changes the memory configuration and jumps to the main part.
  513.  
  514.         012C LDA $01
  515.         012E TAX          Store original memory configuration to X register.
  516.         012F AND #$F8
  517.         0131 ORA #$04
  518.         0133 SEI          Disable interrupts.
  519.         0134 STA $01      Select 64 kB RAM memory configuration.
  520.         0136 JMP $DDA4    Jump to the main part.
  521.  
  522.   The main part actually consists of two parts. It may be a bit
  523. complicated, and it might teach new tricks to you.
  524.  
  525.         DDA4 TXA
  526.         DDA5 PHA          Push original memory configuration on stack.
  527.         DDA6 LDA $FFFA
  528.         DDA9 PHA
  529.         DDAA LDA $FFFB
  530.         DDAD PHA          Store the original values of $FFFA and $FFFB.
  531.         DDAE LDA #$16
  532.         DDB0 STA $FFFA    Set ($FFFA) to point to RTI.
  533.         DDB3 LDA #$C0
  534.         DDB5 STA $FFFB
  535.         DDB8 JSR $DDDC    Swap the auxiliary routines in.
  536.         DDBB JSR $C000    Disable NMI's and initialize CIA2.
  537.         DDBE PLA
  538.         DDBF STA $FFFB    Restore original values to $FFFA and $FFFB.
  539.         DDC2 PLA
  540.         DDC3 STA $FFFA
  541.         DDC6 JSR $C01D    Print the message.
  542.         DDC9 JSR $DDDC    Swap the auxiliary routines out.
  543.         DDCC PLA
  544.         DDCD TAY          Load original memory configuration to Y register.
  545.         DDCE LDA #$00     Push desired stack register value on stack
  546.         DDD0 PHA          (clear all flags, especially the I flag).
  547.         DDD1 TSX
  548.         DDD2 INC $0102,X  Increment the return address.
  549.         DDD5 BNE $DDDA    (RTS preincrements it, but RTI does not.)
  550.         DDD7 INC $0103,X
  551.         DDDA STY $01      Restore original memory configuration.
  552.  
  553.         (The 6510 fetches the next instruction from $DDDC, which is now
  554.         connected to the CIA2's register $C, the Serial Port register.
  555.         The initialization routine wrote an RTI to it. The processor also
  556.         reads from $DDDD as a side effect of the instruction fetch,
  557.         thus re-enabling NMI's.)
  558.  
  559.         DDDC LDY #$3F     Subroutine: Swap the memory areas $C000-$C03F
  560.         DDDE LDX $C000,Y              and $DD64-$DDA3 with each other.
  561.         DDE1 LDA $DD64,Y
  562.         DDE4 STA $C000,Y
  563.         DDE7 TXA
  564.         DDE8 STA $DD64,Y
  565.         DDEB DEY
  566.         DDEC BPL $DDDE 
  567.         DDEE RTS
  568.  
  569.         C000 INC $01      Enable the I/O area.
  570.         C002 LDX #$81
  571.         C004 STX $DD0D    Enable Timer A interrupts of CIA2.
  572.         C007 LDX #$00
  573.         C009 STX $DD05
  574.         C00C INX
  575.         C00D STX $DD04    Prepare Timer A to count from 1 to 0.
  576.         C010 LDX #$DD
  577.         C012 STX $DD0E    Cause an interrupt.
  578.  
  579.         (The instruction sets SP to output, makes Timer A to count
  580.         system clock pulses, forces the CIA to load the initial value
  581.         to the counter, selects one-shot counting and starts the timer.)
  582.  
  583.         C015 LDX #$40
  584.  
  585.         (The processor now jumps to the NMI handler ($C016), and
  586.         the SP register starts to act as a memory place.)
  587.  
  588.         C017 STX $DD0C    Write an RTI to Serial Port register.
  589.         C01A DEC $01      Disable the I/O area.
  590.         C01C RTS          Return.
  591.  
  592.         C01D LDA $01
  593.         C01F PHA
  594.         C020 ORA #$03     Enable I/O and ROMs.
  595.         C022 STA $01
  596.         C024 LDY #$0C     Print the message.
  597.         C026 LDA $C033,Y
  598.         C029 JSR $FFD2
  599.         C02C DEY
  600.         C02D BPL $C026
  601.         C02F PLA
  602.         C030 STA $01      Restore the 64 kB memory configuration.
  603.         C032 RTS
  604.  
  605.         C033 "!DLROW ,OLLEH"
  606.  
  607.         (The string is backwards in memory, since I don't want to
  608.         waste cycles in explicit comparisons. This method results in
  609.         more readable code than doing a forward loop with an index
  610.         value $100-(number of characters).)
  611.  
  612.   This program is not excellent. It has the following bugs:
  613.  
  614.    o The 6510's memory management lines P0 and P1 (LORAM and HIRAM,
  615.      respectively) are assumed to be outputs. If you issued the
  616.      command POKE0,PEEK(0)AND252, this program would not work.
  617.      This could be easily corrected by setting the P0 and P1 lines
  618.      to output in the beginning of the interfacing routine (300 - 312):
  619.  
  620.         LDA $00
  621.         ORA #$02
  622.         STA $00
  623.  
  624.    o The program does not restore the original state of the CIA2
  625.      Control Register A or Interrupt Control Register. It might be
  626.      impossible to start using the Kernal's RS-232 routines after
  627.      running this.
  628.  
  629.    o If the user redirected output to cassette or RS-232, interrupts
  630.      would be required. However, they are completely disabled.
  631.  
  632.    o If a non-maskable interrupt occurs while the loader part is being
  633.      executed, the program will screw up. This will happen also in the
  634.      main part, if an NMI is issued after disabling ROMs and I/O in
  635.      $0134 but before exchanging the contents of the memory places
  636.      $C016 and $DD7A.
  637.  
  638.  
  639. _Freezer cartridges_
  640.  
  641. There are many cartridges that let you to stop almost any program for
  642. "back-up" purposes. One of the most popular of these freezer
  643. cartridges is the Action Replay VI made by Datel Electronics back in
  644. 1989. The cartridge has 8 kilobytes RAM and 32 kilobytes ROM on board,
  645. and it has a custom chip for fiddling with the C64 cartridge port
  646. lines -EXROM, -GAME, -IRQ, -NMI and BA.
  647.  
  648. If the -NMI line is not asserted (the NMI interrupts are enabled), all
  649. freezer cartridges should be able to halt any program. When the user
  650. presses the "freeze" button, the cartridges halt the processor by
  651. dropping the BA line low. Then they switch some of their own ROM to
  652. the $E000 - $FFFF block by selecting the UltiMax configuration with
  653. the -EXROM and -GAME lines. After this, they assert the -NMI line and
  654. release the BA line. After completing the current instruction, the
  655. processor will take the NMI interrupt and load the program counter
  656. from the vector at $FFFA, provided that the NMI line was not asserted
  657. already.
  658.  
  659. This approach is prone to many flaws. Firstly, if the processor is
  660. executing a write instruction when the program is being halted, and if
  661. the write occurred outside the area $0000 - $0FFF, the data would get
  662. lost, if the UltiMax configuration was asserted too early. This can be
  663. corrected to some extent by waiting at least two cycles after
  664. asserting the BA line, as the processor will not stop during write
  665. cycles. However, this is of no help if the processor has not gotten to
  666. the write stage yet.
  667.  
  668. Secondly, if the instruction being executed is outside the area
  669. $0000 - $0FFF, or if it accesses any data outside that area, the
  670. processor will fetch either wrong parameters or incorrect data, or
  671. both. If the instruction does not write anything, will only corrupt
  672. one processor register.
  673.  
  674. Thirdly, if the NMI interrupts are disabled, pressing the "freeze"
  675. button does not have any other immediate effect than leaving the
  676. UltiMax mode asserted, which makes any system RAM outside the area
  677. $0000 - $0FFF unavailable. It also forces the I/O area ($D000 - $DFFF)
  678. on. If the program has any instructions or data outside the lowmost
  679. four kilobytes, it will eventually jam, as that data will be something
  680. else than the program expects.
  681.  
  682. One might except that reading from open address space should return
  683. random bytes. But, in at least two C64's, the bytes read are mostly
  684. $BD, which is the opcode for LDA absolute,X. So, if the processor has
  685. a "good luck", it will happily execute only LDA $BDBD,X commands, and
  686. it might survive to the cartridge ROM area without jamming. Or it
  687. could eventually fetch a BRK and jump to the cartridge ROM via the
  688. IRQ/BRK vector at $FFFE. The Action Replay VI has the familiar
  689. autostart data in the beginning of both the ROML and ROMH blocks by
  690. default, and that data could be interpreted as sensible commands. The
  691. Action Replay VI was indeed able to freeze my test program, even
  692. though I had covered its -RESET, -IRQ and -NMI lines with a piece of
  693. tape, until I relocated the program to the first 4 kilobyte block.
  694.  
  695.  
  696. _Building an unbeatable freezer circuit_
  697.  
  698. As you can see, it is totally impossible to design a freezer cartridge
  699. that freezes any program. If the program to be freezed has disabled
  700. the NMI interrupts, and if its code runs mostly at $0000 - $0FFF or
  701. $D000 - $DFFF, the computer will more probably hang than succeed in
  702. freezing the program.
  703.  
  704. However, it is possible to make some internal modifications to a C64,
  705. so that it can freeze literally any program. You need to expand your
  706. machine to 256 kilobytes following the documents on ftp.funet.fi in
  707. the /pub/cbm/hardware/256kB directory. It will let you to reset the
  708. computer so that all of the 64 kilobytes the previous program used,
  709. will remain intact. If you add a switch to one of the memory expansion
  710. controller's chip selection lines, the program being examined will
  711. have no way to screw the machine up, as the additional memory management
  712. registers will not be available.
  713.  
  714. A few enhancements to this circuit are required so that you can freeze
  715. the programs without losing the state of the I/O chips. You will also
  716. need to replace the Kernal ROM chip with your own code, if you do not
  717. want to lose the state of the A, X, P and S registers. Unfortunately
  718. this circuit will not preserve the state of the processor's Peripheral
  719. lines (its built-in I/O port mapped to the memory addresses 0 and 1),
  720. nor does it record the program counter (PC). I have a partial solution
  721. to the PC problem, though.
  722.  
  723. If you are interested in this project, contact me. I will design the
  724. additional hardware, and I will program the startup routines, but I
  725. certainly do not have the time to program all of the freezer software.
  726. Most of the freezer software could be in RAM, so it would be very easy
  727. to develop it, and you could even use existing tools by patching them
  728. slightly.
  729.  
  730. =============================================================================
  731. FLD - Scrolling the screen
  732. by Marek Klampar (klampar@elf.stuba.sk)
  733.  
  734.  
  735.                  Scrolling the screen
  736.                  --------------------
  737.       [inspirated by Pasi Ojala article 'Opening the borders' from issue#6]
  738.  
  739. From Pasi 'Albert' Ojala's (po87553@cs.tut.fi or albert@cc.tut.fi) article:
  740.  
  741.   _Scrolling the screen_
  742.  
  743.   VIC begins to draw the screen from the first bad line. VIC will know
  744.   what line is a bad line by comparing its scan line counter to the
  745.   vertical scroll register : when they match, the next line is a bad
  746.   line. If we change the vertical scroll register ($d011), the first bad
  747.   line will move also. If we do this on every line, the line counter in
  748.   VIC will never match with it and the drawing never starts (until it is
  749.   allowed to do so).
  750.  
  751.   When we don't have to worry about bad lines, we have enough time to
  752.   open the borders and do some other effects too. It is not necassary to
  753.   change the vertical scroll on every line to get rid of the bad lines,
  754.   just make sure that it never matches the line counter (or actually the
  755.   least significant 3 bits).
  756.  
  757.   You can even scroll the bad lines independently and you have FLD -
  758.   Flexible Line Distance. You just allow a bad line when it is time to
  759.   display the next character row. With this you can bounce the lines or
  760.   scroll a hires picture very fast down the screen.
  761.  
  762. (*** end of Albert's paragraph ***)
  763.  
  764.   Well, everything important was written. I'm just adding this:
  765.  
  766. For moving hires picture replace ORA #$10 by ORA #$30.
  767.  
  768. For another FX try to replace part of irq routine begining with ORA #$10 by:
  769.     ORA #$C0
  770.     STA $D016,
  771. remove  JSR CHOFS,
  772. replace    LDX OFSET
  773. by    LDX #$ff
  774. and enjoy =)
  775.  
  776.  
  777. The demonstartion program for FLD application
  778. ;---------------------------------------
  779. ; Commodore Cracker 1993
  780. ;---------------------------------------
  781. FROM     = $32
  782. TO       = $FA
  783. ;---------------------------------------
  784.       *= $C000
  785. ;---------------------------------------
  786. INIT    LDA #0
  787.       STA DIR     ; Direction
  788.       LDA #$FF    ; Set garbage
  789.       STA $3FFF
  790.       LDA #FROM
  791.       STA OFSET   ; Set ofset
  792.       SEI         ; Disable interrupt
  793.       LDA #$7F    ; Disable timer interrupt
  794.       STA $DC0D
  795.       LDA #1      ; Enable raster interrupt
  796.       STA $D01A
  797.       LDA #<IRQ   ; Set irq vector
  798.       STA $0314
  799.       LDA #>IRQ
  800.       STA $0315
  801.       LDA #0      ; To evoke our irq routine on 0th line
  802.       STA $D012
  803.       CLI         ; Enable interrupt
  804.       RTS
  805. ;---------------------------------------
  806. IRQ     LDX OFSET
  807. L2    LDY $D012   ; Moving 1st bad line
  808. L1    CPY $D012
  809.       BEQ L1      ; Wait for begin of next line
  810.       DEY         ; IY - bad line
  811.       TYA
  812.       AND #$07    ; Clear higher 5 bits
  813.       ORA #$10    ; Set text mode
  814.       STA $D011
  815.       DEX
  816.       BNE L2
  817.       INC $D019   ; Acknowledge the raster interrupt
  818.       JSR CHOFS
  819.       JMP $EA31   ; Do standard irq routine
  820. ;---------------------------------------
  821. OFSET .BYTE FROM
  822. DIR   .BYTE 0
  823. ;---------------------------------------
  824. CHOFS LDA DIR     ; Change OFSET of screen
  825.       BNE UP
  826.       INC OFSET   ; Down
  827.       LDA OFSET
  828.       CMP #TO
  829.       BNE SKIP
  830.       STA DIR
  831. SKIP    RTS
  832. ;---------------------------------------
  833. UP    DEC OFSET   ; Up
  834.       LDA OFSET
  835.       CMP #FROM
  836.       BNE SKIP
  837.       LDA #0
  838.       STA DIR
  839.       RTS
  840.  
  841. =============================================================================
  842. Tech-tech - more resolution to vertical shift.
  843. by Pasi 'Albert' Ojala (po87553@cs.tut.fi _or_ albert@cc.tut.fi)
  844. Written on 16-May-91  Translation 02-Jun-92
  845.  
  846. (All timings are in PAL, principles will apply to NTSC too)
  847.  
  848. One time half of the demos had pictures waving horizontally on the
  849. width of the whole screen. This effect is named tech-tech, and the
  850. audience was puzzled. You can move the screen only eight pixels using
  851. the horizontal scroll register. This effect was done using character
  852. graphics. How exactly and is the same possible with sprites ?
  853.  
  854.  
  855. Horizontal scroll register can move the screen by eight pixels. This
  856. isn't even nearly enough to produce a really stunning effect. You have
  857. to move the graphics itself, fortunately with a resolution of one
  858. character position (one byte) only, the rest can be done with the scroll
  859. register. During one scan line there is no time to move the actual data,
  860. you can only move a pointer. Changing the video matrix pointer won't
  861. help, because VIC (video interface controller) will fetch the character
  862. codes only at certain times, called bad lines. You can change the
  863. character set pointer instead, because VIC reads the data it displays
  864. directly from the character set memory.
  865.  
  866.  
  867. Character set-implementation has its restrictions
  868.  
  869. Because horizontal movement is done by changing the character sets, the
  870. picture or text must be pure graphic and the character codes in the
  871. video matrix must be in a numerical order. The normal picture is in the
  872. first character memory and in the next one it is shifted one character
  873. position to the right. One video bank can hold only seven full character
  874. memories besides the video matrix. This limits the movement of the
  875. picture to 56 pixels. It is possible to get more movement if you use
  876. smaller picture or another video bank.
  877.  
  878. The shift is done so that on each scan line we update the horizontal
  879. scroll register ($D016) with the three lowest bits of the shift value.
  880. We use the other bits to select the right character set ($D018). In a
  881. tech-tech the shift value changes during the display of the whole
  882. picture, and the values are stored in a table. In addition to that, the
  883. shift values should be put into two tables, one for the horizontal
  884. scroll register and another for the character set select. This is
  885. necessary, because there is no time for extra calculations on a bad
  886. line.
  887.  
  888. Because we have to change the character set and x-scroll dynamically, we
  889. also need a raster routine to show a tech-tech. A raster routine is a
  890. routine which is synchronized to the electron beam. This eats up the
  891. processor time: the bigger the picture, the less time is left over for
  892. other activities. On other than bad lines you can do other funny things,
  893. like change the color of the background or border.
  894.  
  895.  
  896. An example program
  897.  
  898. The demo program uses video bank 2, memory addesses $4000-7fff. The
  899. video matrix is in the beginning of the bank. Only inverted chars are
  900. used for the graphics, this way we have all eight character memories
  901. available and the maximum shift is 64 pixels. The area for the tech-tech
  902. in the video matrix is eight character rows high, but it has identical
  903. graphics on every line. This is why we use only 320 bytes from each
  904. character set.
  905.  
  906. You can use a joystick to control the movement of the tech-tech. The
  907. stick decreases or increases the shift add value in a resolution of a
  908. half pixel. When the shift reaches its highest/lowest value, the
  909. direction of the add is reversed. Just experiment with it.
  910.