Newsgroups: comp.sys.apple2.programmer Path: news.uiowa.edu!chi-news.cic.net!brutus.bright.net!usenet.eel.ufl.edu!tank.news.pipex.net!pipex!news.mathworks.com!news.ultranet.com!news.sprintlink.net!in2.uu.net!comp.vuw.ac.nz!actrix.gen.nz!dempson From: dempson@atlantis.actrix.gen.nz (David Empson) Subject: Re: IIc+ & GS Timing & Speed Message-ID: Sender: news@actrix.gen.nz (News Administrator) Organization: Actrix - Internet Services Date: Thu, 28 Sep 1995 14:02:14 GMT References: <9509231801.D2292wp@prc.org> X-Nntp-Posting-Host: atlantis.actrix.gen.nz Lines: 331 In article <9509231801.D2292wp@prc.org>, wrote: > Two questions: > > First, on the IIc+, how can you change from 1 MHZ to 4 MHZ, and visa > versa, from software? You can't do it directly from BASIC. There are a few things you can do that might be sufficient: - Accessing location $C0D0 will slow the IIc+ down to 1 MHz for the next 50 milliseconds. - Accessing location $C070 (paddle trigger) will slow the IIc+ down to 1 MHz for the next 5 milliseconds. Also note that the WAIT routine at $FCA8 (not directly callable from BASIC) always runs at 1 MHz. For more advanced operations, you need an assembly language routine that makes use of a ROM routine. There is a 15 page appendix in the IIc Technical Reference Manual (2nd edition) that covers all the relevant details, including example code. Before making use of this facility, your program _must_ check that it is running on a IIc+. This requires checking several ROM ID bytes: $FBB3 = $06 $FBC0 = $00 $FBBF = $05 In addition, it is necessary to ensure that the main bank of the ROM is switched in (this is normally the case) and that read access to the language card is not enabled. Both of these conditions are OK if you are using a CALL statement from a BASIC program. The appendix has a large list of things you must not do to avoid software compatibility problems, which I don't want to type in. What I will do is give the required code for enabling and disabling the accelerator, which is safe. To enable the accelerator: lda #1 pha jsr $C7C7 To disable the accelerator: lda #2 pha jsr $C7C7 You might also need the commands to lock and unlock the accelerator. If the accelerator is locked, all commands except the unlock commands are ignored. I suggest that you unlock the accelerator, change the speed, then lock it again. To lock the accelerator: lda #3 pha jsr $C7C7 To unlock the accelerator: lda #4 pha jsr $C7C7 You will obviously have to add an RTS instruction to the end of of each routine if you want to call it from BASIC. A little background information: the IIc+ accelerator is based on the design of the ZIP CHIP, and appears to offer the same set of features. It is probably reasonable to assume that the accelerator responds to exactly the same direct hardware commands as the ZIP, but I have never even seen a IIc+, let alone experimented with one, so I can't be sure. > Second, how can I detect the start of the video blanking interval on > our IIc+ and/or ROM 3 IIGS? In both cases, it is probably best to use the mouse firmware. This improves compatibility, allowing the program to work on a IIe with mouse card, IIc, IIc+ or IIgs (with mouse firmware enabled or a IIe mouse card installed). To do this, you will need to write an interrupt handler, which can do a simple operation such as storing a value in an otherwise unused memory location. The BASIC program can then peek this location to detect the vertical blanking period. The safest method would be for the interrupt handler to increment the contents of the location, and the BASIC program simply reading it to look for a changed value. The first step is to locate the mouse firmware. The only supported method of doing this is a slot search for the mouse ID bytes. You should not assume that the mouse firmware is in any particular slot. Check for the following byte values in each slot (n is the slot number): $Cn05 = $38 $Cn07 = $18 $Cn0B = $01 $Cn0C = $20 $CnFB = $D6 If no slot contains these ID bytes, then there is no mouse, and the program should print an appropriate message and refuse to go any further. The second step is to set up and install your interrupt handler. This requires modifying some code in the handler to include the address of routines on the mouse card that are used to service the interrupt. The third step is to initialize the mouse firmware to the required mode and set up the parameters. I will assume for this example that you don't actually want to use the mouse, so only VBL interrupts have been enabled. Your program can then proceed as required. When it finishes, it _must_ disable the mouse firmware and remove the interrupt handler. If you break out of the program (e.g. with Ctrl-C or due to an error), the interrupt handler will still be installed, and a crash is likely if it gets overwritten. If you restart the program without first removing the interrupt handler, strange things may happen (for starters, the interrupt handler will be installed twice). Here is an assembly language routine which does most of the above. I have written this on the fly and haven't tested it, so it might need minor corrections to assemble properly or to fix any bugs (*gasp*). The syntax is for the Merlin assembler. Entering it in the mini-assembler will be a little tricky, as you need to know the addresses of several locations within the code. If you would like a machine code version, E-Mail me and I'll assemble it and send you a copy of a hex dump of it. As written, the code requires about 190 bytes, which will fit in the $0300-$03CF area with about 18 bytes to spare. I haven't made any particular attempt to squeeze the code, so you could save a few bytes. Quite a few could be saved by placing the mouseCN, mouseN0 and vblcount variables on zero page, but the locations chosen MUST NOT be modified by anything apart from these routines. Assuming the code is at location $0300, it can be used from BASIC as follows: To install the handler: CALL 768 To check if the handler is up and running after calling the install routine, PEEK location 774 (mouseCN). If it is zero, then no mouse was found or the interrupt handler could not be installed. To check for a VBL, PEEK location 776 (vblcount). It is increased by one for each VBL (wrapping around from 255 to 0). To remove the handler: CALL 771 The "install" routine must have been called before calling the "remove" routine (it is safe to call "remove" if mouseCN is set to zero). It is safe to call this routine more than once, as it sets mouseCN back to zero again. I'll be happy to answer any questions about this routine here or in E-Mail. * VBL interrupt handler for the IIe, IIc and IIgs, for use from * Applesoft BASIC. (untested at the time of posting) * * by David Empson (dempson@actrix.gen.nz) * * This program is hereby donated to the public domain. If you distribute * it, please include the full text of the relevant portion of the original * article. jmp install ; Entry point to install the handler jmp remove ; Entry point to remove the handler mouseCN dfb $00 ; Modified to hold mouse slot in $Cn format mouseN0 dfb $00 ; Modified to hold mouse slot in $n0 format vblcount dfb $00 ; Incremented for each VBL * Routine to do the installation steps install * Locate the mouse. lda #$C7 ; Start the search at slot 7 sta $3D lda #$00 sta $3C ; Set up a pointer for the slot search sta mouseCN ; Ensure our important variables are cleared sta vblcount slotlp ldx #4 ; Set up count for lookup table bytelp lda offsets,X ; Get offset into card tay lda ($3C),Y ; Get a byte from the card cmp values,X ; Does it match? bne notmouse ; If not, this slot isn't a mouse dex bpl bytelp ; Loop back around for next byte lda $3D sta mouseCN ; Store the slot number in $Cn format tax ; and save it in X asl asl asl asl sta mouseN0 ; Store the slot number in $n0 format bne gotmouse ; Branch is always taken notmouse ldx $3D dex stx $3D cpx #$C1 ; Done all slots yet? bcs slotlp ; Loop for the next slot nomouse rts ; Return to BASIC * We have found the mouse. Set up our interrupt handler. gotmouse ldy #$13 lda ($3C),Y ; Get the location of the SERVEMOUSE routine sta doservm+1 ; Patch the call into the interrupt handler stx doservm+2 iny lda ($3C),Y ; Get the location of the READMOUSE routine sta doreadm+1 ; Patch the call into the interrupt handler stx doreadm+2 * Set up the mouse firmware. ldy #$19 lda ($3C),Y ; Get the location of the INITMOUSE routine sta doinitm+1 stx doinitm+2 ; Patch our call ldy #$12 lda ($3C),Y ; Get the location of the SETMOUSE routine sta dosetm+1 stx dosetm+2 ; Patch our call ldy mouseN0 doinitm jsr $0000 ; Patched with location of INITMOUSE * Install the interrupt handler. jsr $BF00 ; Call ProDOS dfb $40 ; ALLOC_INTERRUPT call da allocpb ; Address of parameter block bcs nomouse ; If error, forget about it * Set up the appropriate mouse mode. lda #$09 ; Mode: enable mouse, VBL interrupt only * Fall through to our setmouse subroutine. It will return to BASIC. setmouse * Subroutine to set the mouse mode to the value in A. ldx mouseCN ldy mouseC0 dosetm jsr $0000 ; Patched with location of SETMOUSE rts ; Return to BASIC or caller * Routine to disable and remove the interrupt handler. remove * Check that the install routine has been called successfully. ldx mouseCN beq noremove * Disable the mouse lda #0 ; Disable the mouse and all interrupts jsr setmouse * Remove the interrupt handler lda aintnum sta dintnum ; Set up the parameter block jsr $BF00 ; Call ProDOS dfb $41 ; DEALLOC_INTERRUPT da deallpb ; address of parameter block lda #0 sta mouseCN ; Protect against this routine being called twice noremove rts * Lookup tables and parameter blocks. offsets dfb $05,$07,$0B,$0C,$FB values dfb $38,$18,$01,$20,$D6 allocpb dfb $02 ; parameter count aintnum dfb $00 ; interrupt number (returned by ProDOS) da inthand ; address of interrupt handler deallpb dfb $01 ; parameter count dintnum dfb $00 ; interrupt number (filled in later) * The interrupt handler. inthand cld ; Required by ProDOS doservm jsr $0000 ; Patched with location of SERVEMOUSE bcs notmine ; Carry set if it is not a mouse interrupt ldx mouseCN ldy mouseN0 lda $06B8,X ; Get the mouse status byte and #$08 ; Test for VBL interrupt beq doreadm ; If not VBL, don't touch our counter inc vblcount ; Update our VBL counter doreadm jsr $0000 ; Patched with location of READMOUSE clc ; Tell ProDOS we handled it notmine rts Share and enjoy! :-) -- David Empson dempson@actrix.gen.nz Snail mail: P.O. Box 27-103, Wellington, New Zealand