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

