home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / genie-commodore-file-library / Information / SLPRG.TXT < prev    next >
Encoding:
Text File  |  2019-04-13  |  35.7 KB  |  849 lines

  1. SwiftLink-232 Application Notes
  2. Revision T v1.0.0
  3.  
  4.  
  5. Introduction
  6.  
  7. The SwiftLink-232 ACIA cartridge replaces the Commodore Kernal RS-232 
  8. routines with a hardware chip. The chip handles all the bit level 
  9. processing now done in software by the Commodore Kernal. The ACIA may be 
  10. accessed by polling certain memory locations in the I/O block ($D000 - 
  11. $DFFF) or through interrupts. The ACIA may be programmed to generate 
  12. interrupts in the following situations:
  13.  
  14. 1) when a byte of data is received
  15. 2) when a byte of data may be transmitted (i. e. the data register is 
  16.    empty)
  17. 3) both (1) and (2)
  18. 4) never
  19.  
  20. The sample code below sets up the ACIA to generate an interrupt each 
  21. time a byte of data is received. For transmitting, two techniques are 
  22. shown. The first technique consists of an interrupt handler which 
  23. enables transmit interrupts when there are bytes ready to be sent from a 
  24. transmit buffer. There is a separate routine given that manages the 
  25. transmit buffer. In the second technique, which can be found at the very 
  26. end of the sample code, neither a transmit buffer or transmit interrupts 
  27. are used. Instead, bytes of data are sent to the ACIA directly as they 
  28. are generated by the terminal program.
  29.  
  30. Note:  The ACIA will always generate an interrupt when a change of state 
  31. occurs on either the DCD or DSR line (unless the lines are not connected 
  32. in the device's cable).
  33.  
  34. The 6551 ACIA was chosen for several reasons, including low cost and 
  35. compatibility with other Commodore (MOS) integrated circuits. Commodore 
  36. used the 6551 as a model for the Kernal software. Control, Command, and 
  37. Status registers in the Kernal routines partially mimic their hardware 
  38. counterparts in the ACIA.
  39.  
  40. Note: If you're using the Kernal software registers in your program, be 
  41. sure to review the enclosed 6551 data sheet carefully. Several of the 
  42. hardware register locations do not perform the same functions as their 
  43. software counterparts. You may need to make a few changes in your 
  44. program to accommodate the differences.
  45.  
  46.  
  47. Buffers
  48.  
  49. Bytes received are placed in "circular" or "ring" buffers by the sample 
  50. receive routine below, and also by the first sample transmit routine. To 
  51. keep things similar to the Kernal RS-232 implementation, we've shown 256 
  52. byte buffers. You may want to use larger buffers for file transfers or 
  53. to allow more screen processing time. Bypassing the Kernal routines 
  54. frees many zero page locations, which could improve performance of 
  55. pointers to larger buffers.
  56.  
  57. If your program already directly manipulates the Kernal RS-232 buffers, 
  58. you'll find it very easy to adapt to the ACIA. If you use calls to the 
  59. Kernal RS-232 file routines instead, you'll need to implement lower 
  60. level code to get and store buffer data.
  61.  
  62. Briefly, each buffer has a "head" and "tail" pointer. The head points to 
  63. the next byte to be removed from the buffer. The tail points to the next 
  64. free location in which to store a byte. If the head and tail both point 
  65. to the same location, the buffer is empty. If (tail + 1) = head, the 
  66. buffer is full.
  67.  
  68. The interrupt handler described below will place received bytes at the 
  69. tail of the receive buffer. Your program should monitor the buffer, 
  70. either by comparing the head and tail pointers (as the Commodore Kernal 
  71. routines do), or by maintaining a byte count through the interrupt 
  72. handler (as the attached sample does). When bytes are available, your 
  73. program can process them, move the head pointer to the next character, 
  74. and decrement the counter if you use one.
  75.  
  76. You should send a "Ctrl-S" (ASCII 19) to the host when the buffer is 
  77. nearing capacity. At higher baud rates, this "maximum size" point may 
  78. need to be lowered. We found 50 to 100 bytes worked fairly well at 9600 
  79. baud. You can probably do things more efficiently (we were using a very 
  80. rough implementation) and set a higher maximum size. At some "minimum 
  81. size", a "Ctrl-Q" (ASCII 17) can be sent to the host to resume 
  82. transmission.
  83.  
  84. To transmit a byte using the logic of the first transmit routine below, 
  85. first make sure that the transmit buffer isn't full. Then store the byte 
  86. at the tail of the transmit buffer, point the tail to the next available 
  87. location, and increment the transmit buffer counter (if used).
  88.  
  89. The 6551 transmit interrupt occurs when the transmit register is empty 
  90. and available for transmitting another byte. Unless there are bytes to 
  91. transmit, this creates unnecessary interrupts and wastes a lot of time. 
  92. So, when the last byte is removed from the buffer, the interrupt handler 
  93. in the first transmit routine below disables transmit interrupts.
  94.  
  95. Your program's code that stuffs new bytes into the transmit buffer must 
  96. re-enable transmit interrupts, or your bytes may never be sent. A model 
  97. for a main code routine for placing bytes in the transmit buffer follows 
  98. the sample interrupt handler.
  99.  
  100. Using a transmit buffer allows your main program to perform other tasks 
  101. while the NMI interrupt routine takes care of sending bytes to the ACIA. 
  102. If the buffer has more than a few characters, however, you may find that 
  103. most of the processor time is spent servicing the interrupt. Since the 
  104. ACIA generates NMI interrupts, you can't "mask" them from the processor, 
  105. and you may have timing difficulties in your program.
  106.  
  107. One solution is to eliminate the transmit buffer completely. Your 
  108. program can decide when to send each byte and perform any other 
  109. necessary tasks in between bytes as needed. A model for a main code 
  110. routine for transmitting bytes without a transmit buffer is also shown 
  111. following the sample interrupt handler code. Feedback from developers to 
  112. date is that many of them have better luck not using transmit interrupts 
  113. or a transmit buffer.
  114.  
  115. Although it's possible to eliminate the receive buffer also, we strongly 
  116. advise that you don't. The host computer, not your program, decides when 
  117. a new byte will arrive. Polling the ACIA for received bytes instead of 
  118. using an interrupt-driven buffer just wastes your program's time and 
  119. risks missing data.
  120.  
  121. For a thorough discussion of the use of buffers, the Kernal RS-232 
  122. routines, and the Commodore NMI handler, see "COMPUTE!'s VIC-20 and 
  123. Commodore 64 Tool Kit: Kernal", by Dan Heeb (COMPUTE! Books) and "What's 
  124. Really Inside the Commodore 64", by Milton Bathurst (distributed in the 
  125. US by Schnedler Systems).
  126.  
  127.  
  128. ACIA Registers 
  129.  
  130. The four ACIA registers are explained in detail in the enclosed data 
  131. sheets. The default location for them in our cartridge is addresses 
  132. $DE00 - $DE03 (56832 - 56836).
  133.  
  134. Data Register ($DE00)
  135.  
  136. This register has dual functionality: it is used to receive and transmit 
  137. all data bytes (i.e. it is a read/write register).
  138.  
  139. Data received by the ACIA is placed in this register. If receive 
  140. interrupts are enabled, an interrupt will be generated when all the bits 
  141. for a received byte have been assembled and the byte is ready to read.
  142.  
  143. Transmit interrupts, if enabled, are generated when this register is 
  144. empty (available for transmitting). A byte to be transmitted can then be 
  145. placed in this register.
  146.  
  147. Status Register ($DE01)
  148.  
  149. This register has dual functionality: it show the status of various ACIA 
  150. settings when read, but when written to (data = anything [i.e. don't 
  151. care]), this register triggers a reset of the chip.
  152.  
  153. As the enclosed data sheet shows (Figure 8), the ACIA uses bits in this 
  154. register to indicate data flow and errors.
  155.  
  156. If the ACIA generates an interrupt, bit #7 is set. There are four 
  157. possible sources of interrupts:
  158.  
  159. 1) receive (if programmed)
  160. 2) transmit (if programmed)
  161. 3) if a connected device changes the state of the DCD line
  162. 4) if a connected device changes the state of the DSR line
  163.  
  164. Some programmers have reported problems with using bit #7 to verify ACIA 
  165. interrupts. At 9600 bps and higher, the ACIA generates interrupts 
  166. properly, and bits #3-#6 (described below) are set to reflect the cause 
  167. of the interrupt, as they should. But, bit #7 is not consistently set. 
  168. At speeds under 9600 bps, bit #7 seems to work as designed. To avoid any 
  169. difficulties, the sample code below ignores bit #7 and tests the four 
  170. interrupt source bits directly.
  171.  
  172. Bit #5 indicates the status of the DSR line connected to the RS-232 
  173. device (modem, printer, etc.), while bit #6 indicates the status of the 
  174. DCD line. Note: The function of these two bits is reversed from the 
  175. standard implementation. Unlike many ACIA's, the 6551 was designed to 
  176. use the DCD (Data Carrier Detect) signal from the modem to activate the 
  177. receiver section of the chip. If DCD is inactive (no carrier detected), 
  178. the modem messages and echoes of commands would not appear on your 
  179. user's screen. We wanted the receiver active at all times. We also 
  180. wanted to give you access to the DCD signal from the modem. So, we 
  181. exchanged the DCD and DSR signals at the ACIA. Both lines are pulled 
  182. active internally by the cartridge if left unconnected by the user 
  183. (i.e., in a null-modem cable possibly).
  184.  
  185. Bit #4 is set if the transmit register is empty. Your program must 
  186. monitor this bit and not write to the data register until the bit is set 
  187. (see the sample XMIT code below).
  188.  
  189. Bit #3 is set if the receive register is full.
  190.  
  191. Bits #2, #1, and #0, when set, indicate overrun, framing, and parity 
  192. errors in received bytes. The next data byte received erases the error 
  193. information for the preceding byte. If you wish to use these bits, store 
  194. them for processing by your program. The sample code below does not 
  195. implement any error checking, but the Kernal software routines do, so 
  196. adding these features to your code might be a good idea.
  197.  
  198. Command Register ($DE02)
  199.  
  200. The Command register (Figure 6) controls parity checking, echo mode, and 
  201. transmit/receive interrupts. It is a read/write register, but reading 
  202. the register simply tells you what the settings of the various 
  203. parameters are.
  204.  
  205. You use bits #7, #6, and #5 to choose the parity checking desired.
  206.  
  207. Bit #4 should normally be cleared (i.e. no echo).
  208.  
  209. Bits #3 and #2 should reflect whether or not you are using transmit 
  210. interrupts, and if so, what kind. In the first sample transmit routine 
  211. below, bit #3 is set and bit #2 is cleared to disable transmit 
  212. interrupts (with RTS low [active]) on startup. However, when a byte is 
  213. placed in the transmit buffer, bit #3 is cleared and bit #2 is set to 
  214. enable transmit interrupts (with RTS low). When all bytes in the buffer 
  215. have been transmitted, the interrupt handler disables transmit 
  216. interrupts. Note: If you are connected to a RS-232 device that uses 
  217. CTS/RTS handshaking, you can tell the device to stop temporarily by 
  218. bringing RTS high (inactive): clear both bits #2 and #3.
  219.  
  220. Bit #1 should reflect whether or not you are using receive interrupts. 
  221. In the sample code below, it is set to enable receive interrupts.
  222.  
  223. Bit #0 acts as a "master control switch" for all interrupts and the chip 
  224. itself. It must be set to enable any interrupts-- if it is cleared, all 
  225. interrupts are turned off and the receiver section of the chip is 
  226. disabled. This bit also pulls the DTR line low to enable communication 
  227. with the connected RS-232 device. Clearing this bit causes most Hayes-
  228. compatible modems to hang up (by bringing DTR high). This bit should be 
  229. cleared when a session is over and the user exits the terminal program 
  230. to ensure no spurious interrupts are generated. One fairly elegant way 
  231. to do this is to perform a software reset of the chip (writing any value 
  232. to the Status register).
  233.  
  234. Note: In Figures 6, 7, and 8 on the 6551 data sheet, there are small 
  235. charts at the bottom of each that are labeled "Hardware Reset/Program 
  236. Reset". These charts indicate what values the bits of these registers 
  237. contain after a hardware reset (like toggling the computer's power) and 
  238. a program reset (a write to the Status register).
  239.  
  240. Control Register ($DE03)
  241.  
  242. You use this register to control the number of stop bits, the word 
  243. length, switch on the internal baud rate generator, and set the baud 
  244. rate. It is a read/write register, but reading the register simply tells 
  245. you what the settings of the various parameters are. See Figure 7 of the 
  246. data sheet for a complete list of the parameters.
  247.  
  248. Be sure that bit #4, the "clock source" bit, is always set to use the 
  249. on-chip crystal-controlled baud rate generator.
  250.  
  251. You use the other bits to choose the baud rate, word length, and number 
  252. of stop bits. Note that our cartridge uses a double-speed crystal, so 
  253. the values given in Figure 7 should be doubled (i.e. the minimum speed 
  254. is 100 bps and the maximum speed is 38,400 bps).
  255.  
  256.  
  257. ACIA Hardware Interfacing
  258.  
  259. The ACIA is mounted on a circuit board designed to plug into the 
  260. expansion (cartridge) port. The board is housed in a cartridge shell 
  261. with a male DB-9 connector at the rear. The "IBMN PC/ATTM standard" DB-
  262. 9 RS-232 pinout is implemented. Commercial DB-9 to DB-25 patch cords are 
  263. readily available, and are sold by us as well.
  264.  
  265. Eight of the nine lines from the AT serial port are implemented: TxD, 
  266. RxD, DTR, DSR, RTS, CTS, DCD, & GND. RI (Ring Indicator) is not 
  267. implemented because the 6551 does not have a pin to handle it. CTS and 
  268. RTS are not normally used by 2400 bps or slower Hayes-compatible modems, 
  269. but these lines are being used by several newer, faster modems (MNP 
  270. modems in particular). Note that although CTS is connected to the 6551, 
  271. there is no way to monitor what its state is-- the value does not appear 
  272. in any register. The 6551 handles CTS automatically: if it is pulled 
  273. high (inactive) by the connected RS-232 device, the 6551 stops 
  274. transmitting (clears the "transmit data register empty" bit [#4] in the 
  275. status register).
  276.  
  277. The output signals are standard RS-232 level compatible. We've tested 
  278. units with several commercial modems and with various computers using 
  279. null modem cables at up to 38,400 bps without difficulties. In addition, 
  280. there are pull-up resistors on three of the four input lines (DCD, DSR, 
  281. CTS) so that if these pins are not connected in a cable, those three 
  282. lines will pull to the active state. For example, if you happen to use a 
  283. cable that is missing the DCD line, the pull-up resistor would pull the 
  284. line active, so that bit #6 in the status register would be cleared (DCD 
  285. is active low).
  286.  
  287. An on-board crystal provides the baud rate clock signal, with a maximum 
  288. of 38.4 K baud, because we are using a double-speed crystal. If 
  289. possible, test your program at 38.4Kb as well as lower baud rates. Users 
  290. may find this helpful for local file transfers or using the C-64/C-128 
  291. as a dumb terminal on larger systems. And, after all, low cost 19.2 Kb 
  292. modems for the masses are just around the corner.
  293.  
  294. Default decoding for the ACIA addresses is done by the I/O #1 line (pin 
  295. 7) on the cartridge port. This line is infrequently used on either the 
  296. C-64 or C-128 and should allow compatibility with most other cartridge 
  297. products, including the REU. The circuit board also has pads for users 
  298. with special needs to change the decoding to I/O #2 (pin 10). This 
  299. change moves the ACIA base address to $DF00, making it incompatible with 
  300. the REU.
  301.  
  302. C-128 users may also elect to decode the ACIA at $D700 (this is a SID 
  303. chip mirror on the C-64). Since a $D700 decoding line is not available 
  304. at the expansion port, the user would need to run a clip lead into the 
  305. computer and connect to pin 12 of U3 (a 74LS138). We have tried this and 
  306. it works. $D700 is an especially attractive location for C-128 BBS 
  307. authors, because putting the SwiftLink there will free up the other two 
  308. memory slots for devices that many BBS sysops use: IEEE and hard drive 
  309. interfaces.
  310.  
  311. Although we anticipate relatively few people changing ACIA decoding, you 
  312. should allow your software to work with a SwiftLink at any of the three 
  313. locations. You could either (1) test for the ACIA automatically by 
  314. writing a value to the control register and then attempting to read it 
  315. back or (2) provide a user-configurable switch/ poke/menu option.
  316.  
  317. The Z80 CPU used for CP/M mode in the C-128 is not connected to the NMI 
  318. line, which poses a problem since the cleanest software interface for 
  319. C-64/C-128 mode programming is with this interrupt. We have added a 
  320. switch to allow the ACIA interrupt to be connected to either NMI or IRQ, 
  321. which the Z80 does use. The user can move this switch without opening 
  322. the cartridge.
  323.  
  324.  
  325. Sample Code
  326.  
  327.  
  328. ;Sample NMI interrupt handler for 6551 ACIA on Commodore 64/128.
  329.  
  330. ;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
  331. ;Geoduck Developmental Systems, and Dr. Evil Labs.
  332.  
  333.  
  334.  
  335. ;     ---=== EQUATES ===---
  336.  
  337. base     =     $DE00    ;base ACIA address
  338. data     =     base
  339. status   =     base+1
  340. command  =     base+2
  341. control  =     base+3
  342.  
  343.  
  344. ;Using the ACIA frees many addresses in zero page normally used by
  345. ;Kernal RS-232 routines.  The addresses for the buffer pointers were
  346. ;chosen arbitrarily. The buffer vector addresses are those used by
  347. ;the Kernal routines.
  348.  
  349. rhead     =     $A7      ;pointer to next byte to be removed from
  350.                          ;receive buffer
  351. rtail     =     $A8      ;pointer to location to store next byte 
  352. received
  353. rbuff     =     $F7      ;receive buffer vector 
  354.  
  355. thead     =     $A9      ;pointer to next byte to be removed from
  356.                          ;transmit buffer
  357. ttail     =     $AA      ;pointer to location to store next byte
  358.                          ;in transmit buffer
  359. tbuff     =     $F9      ;transmit buffer
  360.  
  361. xmitcount =     $AB      ;count of bytes remaining in transmit (xmit) 
  362. buffer 
  363. recvcount =     $B4      ;count of bytes remaining in receive buffer
  364.  
  365. errors    =     $B5      ;DSR, DCD, and received data errors information
  366.  
  367. xmiton    =     $B6      ;storage location for model of command register
  368.                          ;which turns both receive and transmit 
  369.                          ;interrupts on
  370. xmitoff   =     $BD      ;storage location for model of command register
  371.                          ;which turns the receive interrupt on and the
  372.                          ;transmit interrupts off
  373.  
  374. NMINV     =     $0318    ;Commodore Non-Maskable Interrupt vector
  375.  
  376.  
  377.  
  378. ;     ---=== INITIALIZATION ===---
  379.  
  380. ;Call the following code as part of system initialization.
  381.  
  382.  
  383. ;clear all buffer pointers, buffer counters, and errors location
  384.  
  385.       lda    #$00
  386.       sta    rhead
  387.       sta    rtail
  388.       sta    thead
  389.       sta    ttail
  390.  
  391.       sta    xmitcount
  392.       sta    recvcount
  393.       sta    errors
  394.  
  395. ;store the addresses of the buffers in the zero page vectors
  396.  
  397.       lda    #<TRANSMIT.BUFFER
  398.       sta    tbuff
  399.       lda    #>TRANSMIT.BUFFER
  400.       sta    tbuff + 1
  401.  
  402.       lda    #<RECEIVE.BUFFER
  403.       sta    rbuff
  404.       lda    #>RECEIVE.BUFFER
  405.       sta    rbuff + 1
  406.  
  407.  
  408. ;The next four instructions initialize the ACIA to arbitrary values.
  409. ;These could be program defaults, or replaced by code that picks up
  410. ;the user's requirements for baud rate, parity, etc.
  411.  
  412. ;The ACIA "control" register controls stop bits, word length, the
  413. ;choice of internal or external baud rate generator, and the baud
  414. ;rate when the internal generator is used. The value below sets the
  415. ;ACIA for one stop bit, eight bit word length, and 4800 baud using the
  416. ;internal generator.
  417. ;              .------------------------- 0 = one stop bit
  418. ;              :
  419. ;              :.-------------------- word length, bits 6-7
  420. ;              ::.------------------- 00 = eight bit word
  421. ;              :::
  422. ;              :::.------------ clock source, 1 = internal generator
  423. ;              ::::
  424. ;              :::: .----- baud
  425. ;              :::: :.---- rate
  426. ;              :::: ::.--- bits
  427. ;              :::: :::.-- 0-3
  428.       lda    #%0001 1010
  429.       sta    control
  430.  
  431.  
  432. ;The ACIA "command" register controls the parity, echo mode, transmit 
  433. ;and receive interrupt enabling, hardware "BRK", and (indirectly) the 
  434. ;"RTS" and "DTR" lines. The value below sets the ACIA for no parity 
  435. ;check, no echo, disables transmit interrupts, and enables receive 
  436. ;interrupts (RTS and DTR low).
  437. ;              .------------------------- parity control,
  438. ;              :.------------------------ bits 5-7
  439. ;              ::.----------------------- 000 = no parity
  440. ;              :::
  441. ;              :::.----------------- echo mode, 0 = normal (no echo)
  442. ;              ::::
  443. ;              :::: .------------ transmit interrupt control, bits 2-3
  444. ;              :::: :.----------- 10 = xmit interrupt off, RTS low 
  445. ;              :::: ::
  446. ;              :::: ::.------- receive interrupt control, 0 = enabled
  447. ;              :::: :::
  448. ;              :::: :::.--- DTR control, 1 = DTR low
  449.       lda    #%0000 1001
  450.       sta    command
  451.  
  452. ;Besides initialization, also call the following code whenever the user
  453. ;changes parity or echo mode.
  454. ;It creates the "xmitoff" and "xmiton" models used by the interrupt
  455. ;handler and main program transmit routine to control the ACIA
  456. ;interrupt enabling. If you don't change the models' parity bits,
  457. ;you'll revert to "default" parity on the next NMI.
  458.  
  459.                          ;initialize with transmit interrupts off since
  460.                          ;buffer will be empty
  461.  
  462.       sta    xmitoff     ;store as a model for future use
  463.       and    #%1111 0000 ;mask off interrupt bits, keep parity/echo bits
  464.       ora    #%0000 0101 ;and set bits to enable both transmit and
  465.                          ;receive interrupts
  466.       sta    xmiton      ;store also for future use
  467.  
  468.  
  469. ;The standard NMI routine tests the <RESTORE> key, CIA #2, and checks
  470. ;for the presence of an autostart cartridge.
  471.  
  472. ;You can safely bypass the normal routine unless:
  473. ;       *  you want to keep the user port active
  474. ;       *  you want to use the TOD clock in CIA #2
  475. ;       *  you want to detect an autostart cartridge
  476. ;       *  you want to detect the RESTORE key
  477. ;
  478. ;If you need any of these functions, you can wedge the ACIA
  479. ;interrupt handler in ahead of the Kernal routines. It's probably
  480. ;safer to replicate in your own program only the Kernal NMI functions
  481. ;that you need. We'll illustrate bypassing all the Kernal tests.
  482.  
  483. ;BE SURE THE "NEWNMI" ROUTINE IS IN PLACE BEFORE EXECUTING THIS CODE!
  484. ;A "stray" NMI that occurs after the vector is changed to NEWNMI's 
  485. ;address will probably cause a system crash if NEWNMI isn't there. Also, 
  486. ;it would be best to initialize the ACIA to a "no interrupts" state 
  487. ;until the new vector is stored. Although a power-on reset should 
  488. ;disable all ACIA interrupts, it pays to be sure.
  489.  
  490. ;If the user turns the modem off and on, an interrupt will probably be
  491. ;generated. At worst, this may leave a stray character in the receive
  492. ;buffer, unless you don't have NEWNMI in place.
  493.  
  494. NEWVEC
  495.       sei               ;A stray IRQ shouldn't cause problems
  496.                         ;while we're changing the NMI vector, but
  497.                         ;why take chances?
  498.  
  499. ;If you want all the normal NMI tests to occur after the ACIA check,
  500. ;save the old vector. If you don't need the regular stuff, you can
  501. ;skip the next four lines. Note that the Kernal NMI routine pushes
  502. ;the CPU registers to the stack. If you call it at the normal address,
  503. ;you should pop the registers first (see EXITINT below).
  504.       
  505. ;     lda    NMINV      ;get low byte of present vector
  506. ;     sta    OLDVEC     ;and store it for future use
  507. ;     lda    NMINV+1    ;do the same
  508. ;     sta    OLDVEC+1   ;with the high byte
  509.  
  510.                         ;come here from the SEI if you're not saving
  511.                         ;the old vector
  512.       lda    #$<NEWNMI  ;get low byte of new NMI routine
  513.       sta    NMINV      ;store in vector
  514.       lda    #$>NEWNMI  ;and do the same with
  515.       sta    NMINV+1    ;the high byte
  516.  
  517.       cli               ;allow IRQs again
  518.  
  519. ;continue initializing your program
  520.  
  521.       :::    :::::::    ;program initialization continues
  522.  
  523.  
  524. ;Save two bytes to store the old vector only if you need it
  525.  
  526. OLDVEC
  527. ;     dfb    2          ;reserve two bytes to hold old NMI vector
  528.  
  529.  
  530.  
  531. ;   ---=== New NMI Routine Starts Here ===---
  532.  
  533.  
  534. ;The code below is a sample interrupt patch to control the ACIA. When
  535. ;the ACIA generates an interrupt, this routine examines the status 
  536. ;register which contains the following data.
  537.  
  538. ;              .------------------ high if ACIA caused interrupt;
  539. ;              :                   not used in code below
  540. ;              :
  541. ;              :.---------------- reflects state of DCD line
  542. ;              ::  
  543. ;              ::.-------------- reflects state of DSR line
  544. ;              :::
  545. ;              :::.------------ high if xmit data register is empty
  546. ;              ::::
  547. ;              :::: .--------- high if receive data register full
  548. ;              :::: :
  549. ;              :::: :.------- high if overrun error
  550. ;              :::: ::
  551. ;              :::: ::.----- high if framing error   
  552. ;              :::: :::
  553. ;              :::: :::.--- high if parity error
  554. ;      status  xxxx xxxx
  555.  
  556. NEWNMI
  557. ;     sei               ;the Kernal routine already does this before 
  558.                         ;jumping through the NMINV vector
  559.  
  560.       pha               ;save A register
  561.       txa
  562.       pha               ;save X register
  563.       tya
  564.       pha               ;and save Y register
  565.  
  566. ;As discussed above, the ACIA can generate an interrupt from one of four
  567. ;different sources. We'll first check to see if the interrupt was
  568. ;caused by the receive register being full (bit #3) or the transmit
  569. ;register being empty (bit #4) since these two activities should receive
  570. ;priority. A BEQ (Branch if EQual) tests the status register and 
  571. ;branches if the interrupt was not caused by the data register.
  572.  
  573. ;Before testing for the source of the interrupt, we'll prevent more
  574. ;interrupts from the ACIA by disabling them at the chip. This prevents
  575. ;another NMI from interrupting this one. (SEI won't work because the
  576. ;CPU can't disable non-maskable interrupts.)
  577.  
  578. ;At lower baud rates (2400 baud and lower) this may not be necessary. 
  579. ;But, it's safe and doesn't take much time, either.
  580.  
  581. ;The same technique should be used in any parts of your program where 
  582. ;timing is critical. Disk access, for example, uses SEI to mask IRQ 
  583. ;interrupts. You should turn off the ACIA interrupts during disk access 
  584. ;also to prevent disk errors and system crashes.
  585.  
  586. ;First, we'll load the status register which contains all the interrupt
  587. ;and any received data error information in the 'A' register.
  588.  
  589.       lda     status
  590.  
  591. ;Now prevent any more NMIs from the ACIA
  592.  
  593.       ldx     #%0000 0011   ;disable all interrupts, bring RTS inactive, 
  594.                             ;and leave DTR active
  595.       stx     command       ;send to ACIA-- code at end of interrupt 
  596.                             ;handler will re-enable interrupts
  597.  
  598. ;Store the status register data only if needed for error checking.
  599. ;The next received byte will clear the error flags.
  600.  
  601. ;     sta    errors         ;only if error checking implemented
  602.  
  603.       and    #%0001 1000    ;mask out all but transmit and
  604.                             ;receive interrupt indicators
  605.  
  606. ;If you don't use a transmit buffer you can use
  607. ;
  608. ;     and    #%0000 1000
  609. ;
  610. ;to test for receive interrupts only and skip the receive test shown
  611. ;below.
  612.  
  613.       beq    TESTDCDDSR
  614.  
  615. ;if the 'A' register=0, either the interrupt was not caused by the
  616. ;ACIA, or the ACIA interrupt was caused by a change in the DCD or
  617. ;DSR lines, so we'll branch to check those sources.
  618.  
  619. ;If your program ignores DCD and DSR, you can branch to
  620. ;the end of the interrupt handler instead:
  621. ;
  622. ;     beq    NMIEXIT
  623. ;
  624.  
  625.  
  626. ;Test the status register information to see if a received byte is ready
  627. ;If you don't use a transmit buffer, skip the next two lines.
  628.  
  629. RECEIVE                    ;process received byte
  630.       and    #%0000 1000   ;mask all but bit #3
  631.       beq    XMITCHAR      ;if not set, no received byte - if you're 
  632.                            ;using a transmit buffer, the interrupt must 
  633.                            ;have been caused by transmit. So, branch to 
  634.                            ;handle.
  635.       lda    data          ;get received byte
  636.       ldy    rtail         ;index to buffer
  637.       sta    (rbuff),y     ;and store it
  638.       inc    rtail         ;move index to next slot
  639.       inc    recvcount     ;increment count of bytes in receive buffer
  640.                            ;(if used by your program)
  641.  
  642. ;Skip the "XMIT" routines below if you decide not to use a transmit 
  643. ;buffer. In that case, the next code executed starts at TESTDCDDSR or 
  644. ;NMIEXIT.
  645.  
  646.  
  647. ;After processing a received byte, this sample code tests for bytes
  648. ;in the transmit buffer, and sends one if present. Note that, in this
  649. ;sample, receive interrupts take precedence. You may want to reverse the
  650. ;order in your program.
  651.  
  652. ;If the ACIA generated a transmit interrupt and no received byte was
  653. ;ready, status bit #4 is already set. The ACIA is ready to accept
  654. ;the byte to be transmitted and we've branched directly to XMITCHAR 
  655. ;below.
  656.  
  657. ;If only bit #3 was set on entry to the interrupt handler, the ACIA may 
  658. ;have been in the process of transmitting the last byte, and there may 
  659. ;still be characters in the transmit buffer. We'll check for that now, 
  660. ;and send the next character if there is one. Before sending a character 
  661. ;to the ACIA to be transmitted, we must wait until bit #4 of the status 
  662. ;register is set.
  663.  
  664. XMIT
  665.       lda    xmitcount     ;if not zero, characters still in buffer
  666.                            ;fall through to process xmit buffer
  667.       beq    TESTDCDDSR  ;no characters in buffer-- go to next check
  668. ;or
  669. ;
  670. ;     beq    NMIEXIT
  671. ;
  672. ;if you don't check DCD or DSR in your program.
  673.  
  674.  
  675. XMITBYTE
  676.       lda    status     ;test bit #4
  677.       and    #%00010000
  678.       beq    XMITBYTE   ;wait for bit #4 to be set
  679.  
  680.  
  681. XMITCHAR                ;transmit a character
  682.       ldy    thead
  683.       lda    (tbuff),y  ;get character at head of buffer
  684.       sta    data       ;place in ACIA for transmit
  685.  
  686.                         ;point to next character in buffer
  687.       inc    thead      ;and store new index
  688.       dec    xmitcount  ;subtract one from count of bytes
  689.                         ;in xmit buffer
  690.  
  691.       lda    xmitcount
  692.       beq    TESTDCDDSR
  693. ;or
  694. ;
  695. ;     beq    NMIEXIT
  696. ;
  697. ;if you don't check DCD or DSR in your program
  698.  
  699. ;If xmitcount decrements to zero, there are no more characters to
  700. ;transmit. The code at NMIEXIT turns ACIA transmit interrupts off.
  701.  
  702. ;If there are more bytes in the buffer, set up the 'A' register with
  703. ;the model that turns both transmit and receive interrupts on. We felt
  704. ;that was safer, and not much slower, than EORing bits #3 and #4. Note
  705. ;that the status of the parity/echo bits is preserved in the way 
  706. ;"xmiton" and "xmitoff" were initialized earlier.
  707.  
  708.       lda    xmiton     ;model to leave both interrupts enabled
  709.  
  710. ;If you don't use DCD or DSR  
  711.  
  712.       bne    NMICOMMAND ;branch always to store model in command 
  713.                         ;register
  714.  
  715.  
  716. ;If your program uses DCD and/or DSR, you'll want to know when the state
  717. ;of those lines changes. You can do that outside the interrupt handler
  718. ;by polling the ACIA status register, but if either of the lines 
  719. ;changes, the chip will generate an NMI anyway. So, you can let the 
  720. ;interrupt handler do the work for you. The cost is the added time 
  721. ;required to execute the DCRDSR code on each NMI.
  722.  
  723. TESTDCDDSR
  724.  
  725. ;     pha                ;only if you use a transmit buffer, 'A' holds
  726.                          ;the proper mask to re-enable interrupts on
  727.                          ;the ACIA
  728.  
  729.       ::
  730.       ::                 ;appropriate code here to compare bit #6 (DCD)
  731.       ::                 ;and/or bit #5 (DSR) with their previous states
  732.       ::                 ;which you've already stored in memory and take
  733.       ::                 ;appropriate action
  734.       ::
  735.  
  736. ;     pla                ;only if you pushed it at the start of the
  737. ;                        ;DCD/DSR routine
  738. ;     bne    NMICOMMAND  ;'A' holds the xmiton mask if it's not zero,
  739.                          ;implying that we arrived here from xmit 
  740.                          ;routine not used if you're not using a 
  741.                          ;transmit buffer.
  742.  
  743.  
  744. ;If the test for ACIA interrupt failed on entry to the handler, we 
  745. ;branch directly to here. If you don't use additional handlers, the 
  746. ;RESTORE key (for example) will fall through here and have no effect on 
  747. ;your program or the machine, except for some wasted cycles.
  748.  
  749. NMIEXIT
  750.       lda    xmitoff    ;load model to turn transmit interrupts off
  751.  
  752.  
  753. ;and this line sets the interrupt status to whatever is in the 'A' 
  754. ;register.
  755.  
  756. NMICOMMAND
  757.       sta    command
  758.  
  759. ;That's all we need for the ACIA interrupt handler. Since we've pushed 
  760. ;the CPU registers to the stack, we need to pop them off. Note that we 
  761. ;must do this EVEN IF YOU JUMP TO THE KERNAL HANDLER NEXT, since it will 
  762. ;push them again immediately. You can skip this step only if you're 
  763. ;proceeding to a custom handler.
  764.  
  765. EXITINT                 ;restore things and exit
  766.       pla               ;restore 'Y' register
  767.       tay
  768.       pla               ;restore 'X' register
  769.       tax
  770.       pla               ;restore 'A' register
  771.  
  772. ;If you want to continue processing the interrupt with the Kernal 
  773. ;routines,
  774.  
  775. ;     jmp    (OLDVEC)   ;continue processing interrupt with Kernal
  776.                         ;handler
  777.  
  778. ;Or, if you add your own interrupt routine,
  779.  
  780. ;     jmp    YOURCODE   ;continue with your own handler 
  781.  
  782. ;If you use your own routine, or if you don't add anything, BE SURE to 
  783. ;do this last:
  784.  
  785.       rti               ;return from interrupt instruction
  786.  
  787. ;to restore the flags register the CPU pushes to the stack before 
  788. ;jumping to the Kernal code. It also returns you to the interrupted part 
  789. ;of your program.
  790. ------------------------------------------------------------------------
  791. ;Sample routine to store a character in the buffer to be transmitted
  792. ;by the ACIA.
  793.  
  794. ;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
  795. ;Geoduck Developmental Systems, and Dr. Evil Labs. 
  796.  
  797.  
  798. ;Assumes the character is in the 'A' register on entry. Destroys 'Y'--
  799. ;push to stack if you need to preserve it.
  800.  
  801. SENDBYTE                ;adds a byte to the xmit buffer and sets
  802.                         ;the ACIA to enable transmit interrupts (the
  803.                         ;interrupt handler will disable them again
  804.                         ;when the buffer is empty)
  805.  
  806.       lda    xmitcount  ;count of bytes in transmit buffer
  807.       cmp    255        ;max buffer size
  808.       beq    NOTHING    ;buffer is full, don't add byte
  809.  
  810.       ldy    ttail      ;pointer to end of buffer
  811.       sta    (tbuff),y  ;store byte in 'A' at end of buffer
  812.       inc    ttail      ;point to next slot in buffer
  813.       inc    xmitcount  ;and add one to count of bytes in buffer
  814.  
  815.       lda    xmiton     ;get model for turning on transmit interrupts
  816.       sta    command    ;and tell ACIA to do it
  817.  
  818.       rts               ;return to your program
  819.  
  820.  
  821. NOTHING
  822.       lda    #$00       ;or whatever flag your program uses to tell that 
  823.                         ;the byte was not transmitted
  824.       rts               ;and return
  825. ------------------------------------------------------------------------
  826. ;Sample routine to transmit a character from main program when not
  827. ;using a transmit buffer.
  828.  
  829. ;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
  830. ;Geoduck Developmental Systems, and Dr. Evil Labs.
  831.  
  832.  
  833. ;Assumes the character to be transmitted is in the 'A' register on 
  834. ;entry. Destroys 'Y', push to stack if you need to preserve it.
  835.  
  836. SENDBYTE
  837.         tay                 ;remember byte to be transmitted
  838.  
  839.  
  840. TESTACIA
  841.         lda     status      ;bit #4 of the status register is set if
  842.                             ;the ACIA is ready to transmit another byte,
  843.                             ;even if transmit interrupts are disabled
  844.         and     #%0001 0000 
  845.         beq     TESTACIA    ;wait for bit #4 to be set
  846.  
  847.         sty     data        ;give byte to ACIA 
  848.         rts                 ;and exit
  849.