; ***** LIFE ***** ; ; A GAME OF LIFE FOR A VDM DISPLAY. ; ;Adapted from the 'Oznaki' life program (Dr Dobbs, No. 24) ;by R. Daniells of the S.A.M.G. Inc. ; ;This version of life uses the screen memory of the Processor ;Technology VDM-1 display to store the current status of the ;cells. It should work OK with similar memory mapped VDU's ;such as the DG-640 with perhaps a few modifications. ; ;Caution: Program contains some machine dependant I/O due to ;the lack of a non-echoing input routine in CP/M. ; VDM EQU 0CC00H ;START OF VDM MEMORY. VDMU EQU VDM SHR 8 ;HIGH BYTE OF VDM MEMORY. VDMPT EQU 0C8H ;VDM CONTROL PORT (TO INHIBIT SCROLL). ALIVEC EQU 0AAH ;ALIVE CHARACTER. DEADC EQU 7FH ;DEAD CHARACTER. CR EQU 0DH ;CARRIAGE RETURN CHARACTER. LF EQU 0AH ;LINEFEED CHARACTER. KSTAT EQU 0 ;KEYBOARD STATUS PORT. KDATA EQU 2 ;KEYBOARD DATA PORT. RDR EQU 10H ;KEYBOARD DATA READY MASK. ENTRY EQU 5 ;ENTRY TO CP/M. ; ORG 100H START: LXI H,0 ;SAVE CPM'S STACK. DAD SP SHLD OLDSTK MLOOP: LXI SP,NEWSTK ;SET UP NEW LOCAL STACK. MVI A,0 OUT 0C8H ;INIT VDM (NO SCROLLING). CLEAR: LXI H,VDM+400H ;GENERATE DEAD SCREEN. MVI A,VDMU-1 BLANK: MVI M,DEADC DCX H CMP H JNZ BLANK READY: PUSH H MVI A,0 ;CLEAR ONE-GENERATION FLAG. STA ONEFLAG LXI B,0FFC0H ;NORTH ADDRESS INCREMENT. ;B IS ALSO CURSOR CHAR. LXI D,40H ;SOUTH ADDRESS INCREMENT. READIN: MOV C,M ;REAL CHAR IN C. MOV M,B INPUT: CALL GETCH ;WAIT FOR INPUT CHARACTER. JZ INPUT MOV M,C MVI C,0C0H ;RESTORE C. CPI 'C'-40H ;CONTROL - C? JZ EXIT CPI 30H ;NUMBER? JC NOTNUM CPI 3AH ;NUMBER LESS THAN 9? JC SETSPD NOTNUM CPI 'H' ;REQUEST FOR HELP? JZ HELP CPI 'N' ;MOVEMENT COMMAND? CZ NORTH CPI 'S' CZ SOUTH CPI 'E' CZ EAST CPI 'W' CZ WEST CPI 'M' CZ MIDDLE CPI 'K' ;KILL CELL? CZ KILL CPI 'L' ;GRANT LIFE? CZ LIVE CPI 'C' ;CLEAR SCREEN? CZ CLEAR CPI 'O' ;ONE GENERATION ONLY? CZ ONEGEN CPI 'G' ;GO? JNZ READIN POP H ;SET VDM-1 IN CURRENT GENERATION POINTER. LIFE XRA A ;INIT CELL COUNTER. ADD M DAD B ;TO GO NORTH. ADD M INX H ;TO GO EAST. ADD M INX H ;TO GO EAST. ADD M DAD D ;TO GO SOUTH. ADD M DAD D ;TO GO SOUTH. ADD M DCX H ;TO GO WEST. ADD M DCX H ;TO GO WEST. ADD M INX H ;TO GO EAST. DAD B ;TO GO NORTH. ANI 7 ;WHAT'S IN BOTTOM 3 BITS. CPI 6 ;WERE THERE 2 LIVE? CNZ MARK ;DO NOTHING IF 2 NEIGHBORS. MOV A,H ;HAVE WE CHECKED ALL OF SCREEN? CPI 0D0H JNZ LIFE ;CONTINUE IF NOT DONE. CALL DELAY ;DELAY BETWEEN GENERATIONS. ;BIRTH/DEATH AGONY SEQUENCE. C1 DCX H MOV A,M ORA A CPE LIVE CPO KILL MOV A,H CPI VDMU-1 JNZ C1 ; DELAY FOR VIEWING MARKED LOCATIONS. CALL DELAY ; SEE IF ONLY ONE GENERATION REQUESTED. LDA ONEFLAG ORA A JNZ READY ;STOP IF SO. ; DISPLAY CAN BE STOPPED AND ALTERED. CALL GETCH ;SEE IF KEY PRESSED. JZ LIFE ;CONTINUE IF NOT. JMP READY ;ELSE, GET NEW COMMAND. ; ; ROUTINES THAT MARK CELLS FOR POSSIBLE ALTERATION. MARK CPI 1 ;ARE THERE EXACTLY 3 LIVE NEIGHBOURS? JZ LMARK DMARK MVI A,DEADC ANA M MOV M,A ;CELL NOW MARKED FOR DEATH. RET LIVEMARK EQU 80H LMARK MVI A,LIVEMARK ORA M MOV M,A ;CELL NOW MARKED FOR LIFE. RET ; ROUTINES FOR SEEDING THE SCREEN. NORTH DAD B RET SOUTH DAD D RET EAST INX H RET WEST DCX H RET MIDDLE LXI H,VDM+220H RET KILL MVI M,DEADC RET LIVE MVI M,ALIVEC RET ;NON-ECHOING CHARACTER INPUT ROUTINE. GETCH: IN KSTAT ;GET STATUS ANI RDR ;SEE IF KEY PRESSED. RZ ;RETURN IF NOT. IN KDATA ;ELSE, GET CHARACTER. ANI 7FH ;STRIP PARITY. RET ; ; DELAY ROUTINE. DELAY PUSH D ;SAVE REGISTERS. PUSH B LDA DMULT ;GET DELAY MULTIPLIER. MOV B,A ;PUT IN REG. B. ORA A ;WANT MAXIMUM SPEED? JZ NODEL ;SKIP DELAY IF SO. DELA1 LXI D,16665 ;LOAD LOOP COUNT. DELA2 DCX D ;DECREMENT COUNT. MOV A,D ORA E ;ZERO YET? JNZ DELA2 ;CONTINUE IF NOT. DCR B ;DECREMENT DELAY MULTIPLIER. JNZ DELA1 NODEL POP B ;RESTORE REGISTERS. POP D RET ; SETSPD SUI 30H ;REMOVE ASCII BIAS. STA DMULT ;UPDATE DELAY MULTIPLIER. JMP READY ; ONEGEN MVI A,1 ;SET ONEFLAG. STA ONEFLAG MVI A,'G' ;PUT G IN ACC. RET ; HELP CALL CLS ;CLEAR SCREEN, INIT CURSOR. LXI D,HMESS ;POINT TO MESSAGE. MVI C,9 ;PRINT BUFFER FUNCTION FOR CP/M. CALL ENTRY ;PRINT THE MESSAGE. WAIT CALL GETCH ;WAIT FOR KEY DEPRESSION. JZ WAIT JMP MLOOP ;THEN RESTART. ; HMESS DB 'AVAILABLE ' DB 'COMMANDS ' DB 'ARE:' DB CR DB LF DB 'H = HELP.' DB CR DB LF DB 'C = CLEAR ' DB 'SCREEN.' DB CR DB LF DB 'M = GO TO ' DB 'MIDDLE OF ' DB 'SCREEN.' DB CR DB LF DB 'N = GO ' DB 'NORTH.' DB CR DB LF DB 'S = GO SOUTH.' DB CR DB LF DB 'E = GO EAST.' DB CR DB LF DB 'W = GO WEST.' DB CR DB LF DB 'G = GRANT ' DB 'LIFE.' DB CR DB LF DB 'O = DO ONE ' DB 'GENERATION ' DB 'THEN HALT.' DB CR DB LF DB 'L = MAKE ' DB 'LIVE CELL.' DB CR DB LF DB 'K = KILL CELL.' DB CR DB LF DB 'NUMBER ' DB '0 - 9 = ' DB 'SET DELAY ' DB '(0 = FASTEST ' DB 'SPEED).' DB CR DB LF DB 'ANY KEY = ' DB 'HALT, AND ' DB 'WAIT FOR ' DB 'NEW COMMAND.' DB CR DB LF DB CR DB LF DB 'PRESS ' DB 'ANY KEY ' DB 'TO RESTART.' DB '$' ;DELIMITER. ; EXIT LHLD OLDSTK ;RESTORE CP/M'S STACK. SPHL RET ;BACK TO CPM. ; ;ROUTINE TO CLEAR SCREEN AND INITIALIZE CURSOR. CLS LXI H,VDM ;POINT TO SCREEN MEMORY. MVI M,80H+' ' ;THIS IS THE CURSOR. INX H ;BUMP POINTER. CLS1 MVI M,' ' ;STORE BLANK. INX H ;NEXT.... MOV A,H ;SEE IF END OF SCREEN YET. CPI VDMU+10H JC CLS1 ;CONTINUE IF NOT. RET ; ONEFLAG DB 0 ;FLAG FOR ONE GENERATION MODE. DMULT DB 0 ;DELAY MULTIPLER. ; DS 12 ;SPACE FOR LOCAL STACK. NEWSTK EQU $ ;LOCAL STACK TOP. OLDSTK DS 2 ;SAVE CPM'S STACK HERE. ; END õÕÿ÷þ÷õÿós÷ÿ÷¿Œÿ ÿÿ ÿÿÿÿÿ„ÿÿÿlÿˆÿ ÿÿÿôöòövÿöòöôööòôö ÿÿ ÿÿÿÿ ÿÿÿÿHÿ ÿÿÿÿ ÿ÷w÷Óõÿ÷õÿöÿ÷÷÷õ_Lÿÿ ÿÿˆÿÿÿ€ÿÿÿÿÿÿÿÿÿÿýÿ¾ÿÿûÿþþûÿþÿÿÿÿÿÿ@ÿÿÿ€ÿÿÿÿÿÿÿÿÿÿ