BORDER FX by Graham Mason [The TABLE label in the assembler listing was undefined, but it was] [pretty obvious where it should go. JimG] Graham Mason's Border Effects routine is a rather good example of effective illusion. And it gives a superb impression of how fast machine code really is. Using interrupts, the routine changes the border colour in sequence every 50th of a second. The result is a "solid" bar effect, right in the border. Take it from me, it's stunning. I've taken the program apart, split it into sections, and disembowelled it for your use. I hope it helps you or at least gives a rough idea of Z80 assembly language. You'll need an assembler to type in the listing. Any will do. But note that the '#' before some numbers indicates hexadecimal numbers. Some assemblers differ in notation. It's best to check the manual first. This instruction (used in all assemblers) designates the ORiGin address of your code. In this case it's 60000, although it can be anything between 16384 and 65535. 0000 00000 org 60000 Disables all maskable interrupts and makes the program run slightly faster. EA60 F3 00000 di Creates a vector table at 32768 which contains the address the interrupts jump to every 50th of a second (#9090). EA61 210080 00000 ld hl,#8000 EA64 110180 00000 ld de,#8001 EA67 010101 00000 ld bc,#0101 EA6A 3690 00000 ld (hl),#90 EA6C EDB0 00000 ldir Places a jump statement at this address. EA6E 3EC3 00000 ld a,#c3 EA70 329090 00000 ld (#9090),a Now at #9090 the interrupt routine is told to jump to the border effects routine. EA73 2182EA 00000 ld hl,INTER EA76 229190 00000 ld (#9091),hl Points the interrupt register to the high byte of the vector table. EA79 3E80 00000 ld a,#80 EA7B ED47 00000 ld i,a Selects interrupt mode two and enables interrupts. The border effects will start working at this point. IM 2 is the mode allowing you to use your own interrupting programs in preference to the ROM's. EA7D ED5E 00000 im 2 EA7F FB 00000 GRAY ei EA80 18FD 00000 jr GRAY Saves all registers used on the stack. This must be done at the start of every routine to prevent corruption. EA82 F5 00000 INTER push af EA83 C5 00000 push bc EA84 E5 00000 push hl EA85 D5 00000 push de Border black. EA86 AF 00000 xor a EA87 D3FE 00000 out (#fe),a This delay here is the amount of time the border is off between lines. EA89 0B 00000 DELAY dec bc EA8A 78 00000 ld a,b EA8B B1 00000 or c EA8C 20FB 00000 jr nz,DELAY Points HL to the colour table. EA8E 21F8EA 00000 ld hl,TABLE Register A holds the contents [pointed to by] HL (that's the next byte from the table). EA91 7E 00000 COLLEC ld a,(hl) Checks to see if the end of the table has been reached (marked by #FF), if so then branch off to STDATA. EA92 FEFF 00000 cp #ff EA94 CAA8EA 00000 jp z,STDATA Change the border to the colour specified by the table. EA97 D3FE 00000 out (#fe),a Register BC holds the amount of time the border colours remain on the screen. Increase the value for thicker lines. EA99 010600 00000 ld bc,6 EA9C 0B 00000 DELAY1 dec bc EA9D 78 00000 ld a,b EA9E B1 00000 or c EA9F C29CEA 00000 jp nz,delay1 Clear the Carry flag and loops back until done. EAA2 E6FF 00000 and #ff EAA4 23 00000 inc hl EAA5 C391EA 00000 jp COLLEC Points HL to the start of the table again. EAA8 21F8EA 00000 STDATA ld hl,TABLE Another delay controlling the distance between the top and bottom bars. The longer the delay the further apart and vice versa. EAAB 016E07 00000 ld bc,#76e EAAE 0B 00000 DELAY2 dec bc EAAF 78 00000 ld a,b EAB0 B1 00000 or c EAB1 20FB 00000 jr nz,DELAY2 Register A holds the contents [pointed to by] HL in preparation for "printing" the second bar. If the end marker appears this time then a key scanning routine is activated. EAB3 7E 00000 DATA ld a,(hl) EAB4 FEFF 00000 cp #ff EAB6 CACAEA 00000 jp z,KESCAN Change border. EAB9 D3FE 00000 out (#fe),a Another delay, this time for bar two. A JP instruction is quicker than a JR instruction. EABB 010600 00000 ld bc,6 EABE 0B 00000 DELAY3 dec bc EABF 78 00000 ld a,b EAC0 B1 00000 or c EAC1 C2BEEA 00000 jp nz,DELAY3 Loop back round until finished. EAC4 E6FF 00000 and #ff EAC6 23 00000 inc hl EAC7 C3B3EA 00000 jp DATA Scan for SPACE, along the bottom left five keys of the keyboard (coded #7F). Jump to the rotate routine if space is not pressed. EACA 3E7F 00000 KESCAN ld a,#7f EACC DBFE 00000 in a,(#fe) EACE F6E0 00000 or #e0 EAD0 FEFE 00000 cp #fe EAD2 200E 00000 jr nz,BACKIN Turn off the border effect. EAD4 F3 00000 di POP the registers off the stack in the reverse order to which they were PUSHED. EAD5 D1 00000 pop de EAD6 E1 00000 pop hl EAD7 C1 00000 pop bc Set the I register back to normal, in tune with BASIC. EAD8 3E3F 00000 ld a,#3f EADA ED47 00000 ld i,a Re-select the ROM's interrupt mode. EADC ED56 00000 im 1 Restore A and the flags (F). EADE F1 00000 pop af Enable interrupts. Very important when returning to BASIC to prevent "hanging". EADF FB 00000 ei Use the ROM error routine, returning with OK 0:1. EAE0 CF 00000 rst #8 EAE1 FF 00000 defb #ff This useful routine shifts the contents of the table so that on every re-print the bars appear to rotate round. EAE2 3AF8EA 00000 BACKIN ld a,(TABLE) EAE5 21F9EA 00000 ld hl,TABLE+1 EAE8 11F8EA 00000 ld de,TABLE EAEB 010D00 00000 ld bc,#d EAEE EDB0 00000 ldir EAF0 2B 00000 dec hl EAF1 77 00000 ld (hl),a Restore all stacked registers. EAF2 D1 00000 pop de EAF3 E1 00000 pop hl EAF4 C1 00000 pop bc EAF5 F1 00000 pop af Return to BASIC with interrupts still running. EAF6 ED4D 00000 reti EAF8 06070605 00000 TABLE defb 6,7,6,5,4,3,2,1,1 EAFC 04030201 EB00 01 EB01 01020304 00000 defb 1,2,3,4,5,0,#ff EB05 0500FF