M/C Part 8 INTERRUPTS ========== Essentially, there are two ways of getting information from peripherals. You can either get your software to go round and round scanning all the ports waiting for something to happen (this is called POLLING), or you can get the peripherals to tell you when they need servicing. This second method involves interrupts which will stop the processor doing its stuff, and will jump to a routine which will take care of it, and will then return to the CPU's previous action. Now, with the Z80 CPU, like the SAM's, things are simplified a bit. Fancy computers will have many different interrupts with a priority system allowing one interrupt to, erm, interrupt another, if you get my meaning. However, with a Z80 there is only one maskable interrupt line, and no maskable interrupt can over-ride another. Maskable interrupts? Let me explain... Right, there are two types of interrupt: maskable which can be ignored (masked) and non-maskable which can't. I'll deal with the NMI first, 'cos it's simpler. Okay, The coupe has one and one only non-maskable interrupt which is connected to the break button. If you press this button the CPU will stop what it's doing and will address #0066. With the ROM paged in this corresponds to the routine to escape from a BASIC program, the DOS or anything. If you can remember back to the issue about vectors, there is one which you can change to provide your own action for BREAK, or to disable it (effectively, anyway). That vector is NMIV=#5AE0, by ra way. Fine, got everything so far? Good. Now for the maskable jobbies. Well, there are three different modes on the Z80, but with the design of the coupe, we might as well just stick to MODE1 (not to be confused with screen modes). Okay, well, there are five different interrupts which go to the CPU acting under mode 1. These force it to address #0038. The only way to tell which of the interrupts requested the interrupt a read of the STATUS register is nescesary (port 249). The lower 5 bits of this byte act as follows:- bit 0 - When low (0) this means that the value in the LINE interrupt register (port 249 - write) matches the scan line of the TV about to occur. You could use this to change palette or screen mode part of te way down the screen. bit 1 - When low, this indicates the COMMS interrupt is requesting. In my version of the ATM it states that this is a mouse interrupt. It isn't - the mouse is scanned by the FRAME interrupt. bit 2 - When low, this means that the MIDI channel has a data byte to be read. bit 3 - When low, this means that the TV scan has just been completed. This is regulated at 50/second - useful for timing. bit 4 - When low, indicates that the MIDI out register has just completed its data transfer. There are three instructions to control maskable interupts: DI - Disable Interrupts (switches em off) EI - Enable Interrupts (switches em on) HALT - Waits for an interrupt to occur. Now, I cannae be bothered to write a complete interrupt handler for you, so I'll give you some snippets. Firstly, if you stick your program in 0-#7FFF (in place of the ROM), you can leave interrupts on, and by putting EI: RET at #0066 you can effectively disable the NMI. (By the way, interrupts are off during an service routine, so you must end with EI followed by RET). Remember, you must stack all the registers you're going to use, before your routine, and recover them before returning. Leave the states of LMPR and HMPR the same as on entry. Yer basic routine would be somink like: MASKABLE_INT PUSH AF IN A,(249) BIT 3,A CALL Z,FRAME_INT . . Other interupts . POP AF EI RET FRAME_INT PUSH AF CALL MOUSE_SCAN . . Maybe add a counter, or switch palettes . to flash them, or play some music (more . on this next month). POP AF RET MOUSE_SCAN PUSH BC PUSH DE PUSH HL LD BC,#FFFE IN A,(C) LD HL,MOUSE_SPACE ; Temporary storage area LD DE,#070F IN A,(C) AND E CP E JR NZ,MOUSE_END MS1 LD (HL),A INC HL IN A,(C) DEC D JR NZ,MS1 LD (HL),A LD HL,MOUSE_TABLE LD A,(HL) CPL ; CPL inverts all the bits of A AND 7 ; Isolate bits 0-2 LD (BUTTON_STATUS),A INC HL INC HL LD A,(HL) INC HL AND E RLCA RLCA RLCA RLCA LD D,A LD A,(HL) AND E OR D ***** NEG ; Add this if you want to number ***** ; your y axis from 0 at the top. ; Neg makes the accumulator negative ; ie. 1 becomes -1 (#FF) LD D,A LD A,(Y_COORD) ADD A,D CP 192 ; This is yer maximum y coordinate JR C,MS2 XOR A BIT 7,D JR NZ,MS2 LD A,191 ; Maximum y-1 MS2 LD (Y_COORD),A INC HL INC HL LD A,(HL) INC HL AND E RLCA RLCA RLCA RLCA LD D,A LD A,(HL) AND E OR D LD E,A RLA SBC A,A LD D,A LD HL,(X_COORD) ; 16 bit value ADD HL,DE LD A,(FATPIX) ; This is zero, if we are using LD B,3 ; MODE 3 with high-res pixels. AND A ; Otherwise, make it non-zero. JR Z,MS3 ; (ie. if in another mode or if DEC B ; fatpix is 1) MS3 LD A,H INC A JR Z,MS4 CP B JR C,MS5 LD H,B DEC H DEC H LD L,255 JR MS5 MS4 LD HL,0 MS5 LD (X_COORD),HL MOUSE_END POP HL POP DE POP BC RET X_COORD DW 0 Y_COORD DB 0 BUTTON DB 0 ; BITS 0 & 2 correspond to buttons on ; mouse FATPIX DB 0 ; see above. MOUSE_SPACE DS 8