;--------------------------------------------------------------- ; PONG for Altair front panel. ; May 2014, Mike Douglas ; ; This version has been modified to load under CP/M and ; then relocate itself to zero as required to run. CP/M ; must be cold-booted to restart. ; ; Left player quickly toggles A15 to hit the "ball." Right ; player toggles A8. Score is kept in memory locations ; 80h and 81h (left and right). Score is missed balls, so ; the lower number wins. ;--------------------------------------------------------------- ; Parameters: ; SPEED determines how fast the ball moves. Higher values ; move faster. Speed can easily be patched at address 1. ; ; HITMSK, HITEDG determines how easy it is to hit the ball. ; These are best changed by re-assembling the program. ; Frankly, even the medium setting is too easy. Probably ; best to stick with "hard" and change difficulty by ; adjusting SPEED. ; ; DEMO mode can be set by patching 35h and 65h to zero ; and raising A15 and A8. 000E = SPEED equ 0eh ;higher value is faster 0001 = HITMSKR equ 01h ;01h=hard, 03h=med, 07h=easy 0002 = HITEDGR equ 02h ;02h=hard, 04h=med, 08h=easy ;00h=demo with A15,A8 up 0010 = HITMSKL equ 10h ;10h=hard, 18h=med, 1ch=easy 0008 = HITEDGL equ 08h ;08h=hard, 04h=med, 02h=easy ;00h=demo with A15,A8 up 0100 org 0100h ;CP/M TPA area ;---------------------------------------------------------------- ; CP/M entry point ;---------------------------------------------------------------- 0100 210000 entry lxi h,0 ;HL=destination address 0103 111301 lxi d,pong ;DE=source address 0106 067B mvi b,length ;B=number of bytes to move 0108 1A moveLp ldax d ;move pong down to zero 0109 77 mov m,a 010A 23 inx h 010B 13 inx d 010C 05 dcr b 010D C20801 jnz moveLp ; Pong moved to zero. Jump to it. 0110 C30000 jmp 0 ;---------------------------------------------------------------- ; pong - initialize ;---------------------------------------------------------------- 0113 010E00 pong lxi b,SPEED ;BC=adder for speed 0116 317D00 lxi sp,stack-pong ;init stack pointer 0119 210000 lxi h,0 ;zero the score 011C 228000 shld scoreL 011F 110080 lxi d,8000h ;D=ball bit, E=switch status 0122 C31E00 jmp rLoop-pong ;begin moving right ;------------------------------------------------------------------ ; ledOut - Write D to LEDs A15-A8. ; Loop accessing the address in DE which causes the proper LED ; to light on the address lights. This routine is placed low ; in memory so that address light A7-A5 remain off to make ; A15-A8 look better. ;------------------------------------------------------------------ 0125 210000 ledOut lxi h,0 ;HL=16 bit counter 0128 1A ledLoop ldax d ;display bit pattern on 0129 1A ldax d ;...upper 8 address lights 012A 1A ldax d 012B 1A ldax d 012C 09 dad b ;increment display counter 012D D21500 jnc ledLoop-pong 0130 C9 ret ;---------------------------------------------------------------- ; Moving Right ;---------------------------------------------------------------- 0131 CD1200 rLoop call ledOut-pong ;output to LEDs A15-A8 from D ; Record the current right paddle state (A8) in the bit position ; in E corresponding to the present ball position. 0134 DBFF in 0ffh ;A=front panel switches 0136 E601 ani 01h ;get A8 alone 0138 CA2D00 jz chkRt-pong ;switch not up, bit already zero 013B 7A mov a,d ;set bit in E corresponding to... 013C B3 ora e ; the current ball position 013D E61F ani 1fh ;keep b7-b5 zero 013F 5F mov e,a ; See if at the right edge. If so, see if A8 "paddle" has a hit 0140 7A chkRt mov a,d ;is ball at right edge? 0141 E601 ani 1 0143 CA4500 jz moveRt-pong ;no, continue moving right 0146 7B mov a,e ;switch state for each ball position 0147 E602 ani HITEDGR ;test edge for switch too early 0149 C23F00 jnz missRt-pong ;hit too early 014C 7B mov a,e ;test for hit 014D E601 ani HITMSKR 014F C27300 jnz moveLfR-pong ;have a hit, switch direction ; missRt - right player missed the ball. Increment count 0152 218100 missRt lxi h,scoreR ;increment right misses 0155 34 inr m ; moveRt - Move the ball right again. 0156 1E00 moveRtR mvi e,0 ;reset switch state 0158 7A moveRt mov a,d ;move right again 0159 0F rrc 015A 57 mov d,a 015B C31E00 jmp rLoop-pong ;---------------------------------------------------------------- ; Moving left ;---------------------------------------------------------------- 015E CD1200 lLoop call ledOut-pong ;output to LEDs A15-A8 from D ; Record the current left paddle state (A15) in the bit position ; in E corresponding to the present ball position. 0161 DBFF in 0ffh ;A=front panel switches 0163 E680 ani 80h ;get A15 alone 0165 CA5D00 jz chkLft-pong ;switch not up, bit already zero 0168 7A mov a,d ;A=ball position 0169 0F rrc ;move b7..b3 to b4..b0 016A 0F rrc ; so LEDs A7-A5 stay off 016B 0F rrc 016C B3 ora e ;form switch state in E 016D E61F ani 1fh ;keep b7-b5 zero 016F 5F mov e,a ; See if at the left edge. If so, see if A15 "paddle" has a hit 0170 7A chkLft mov a,d ;is ball at left edge? 0171 E680 ani 80h 0173 CA7500 jz moveLf-pong ;no, continue moving left 0176 7B mov a,e ;switch state for each ball position 0177 E608 ani HITEDGL ;test edge for switch too early 0179 C26F00 jnz missLf-pong ;hit too early 017C 7B mov a,e ;test for hit 017D E610 ani HITMSKL 017F C24300 jnz moveRtR-pong ;have a hit, switch direction ; missLf - left player missed the ball. Increment count 0182 218000 missLf lxi h,scoreL ;increment left misses 0185 34 inr m ; moveLf - Move the ball left again. 0186 1E00 moveLfR mvi e,0 ;reset switch state 0188 7A moveLf mov a,d ;move right again 0189 07 rlc 018A 57 mov d,a 018B C34B00 jmp lLoop-pong 007B = LENGTH equ $-pong ;length of this code ;------------------------------------------------------------------ ; Data Storage ;------------------------------------------------------------------ 018E ds 2 ;stack space 0190 = stack equ $ 0080 org 80h ;put at 80h and 81h 0080 scoreL ds 1 ;score for left paddle 0081 scoreR ds 1 ;score for right paddle 0082 end