;---------------------------------------------------------------------------- ;ca1disis.asm ;1-dimensional Cellular Automaton ;For the Intellec MDS888 (8080) running ISIS/OSIRIS ;By Roger Arrick ;3/4/2018 ;Edit 18 ;---------------------------------------------------------------------------- ;To build and run: submit :f1:ca1disis.mak ; ;ca1disis.mak ; asm80 :f1:ca1disis.asm ; link :f1:ca1disis.obj, system.lib to :f1:ca1disis.lnk ; locate :f1:ca1disis.lnk ; :f1:ca1disis ;---------------------------------------------------------------------------- ;Operation: ;There are two 1-dim arrays - ROW 1 for display, ROW 2 for work. ;Starts with a single * in the middle of ROW 1. ;A rule is applied to ROW 1 and stored in the work array ROW 2. ;ROW 2 is transferred to ROW 1 then sent to the console. ;ROW 2 is cleared for the next loop. ;Pressing SPACE pauses the program, any other key quits. ;---------------------------------------------------------------------------- NAME ca1disis EXTRN ISIS ;Must link with system.lib for EXIT. STKTOP EQU 08FFFH COLS EQU 132 ;# of columns. CR EQU 0DH LF EQU 0AH STOP EQU 0 ;String terminator for type routine. ESC EQU 18H BS EQU 08H SPACE EQU 20H CTRLC EQU 03H ;Monitor calls for console IO. CI EQU 0F803H ;Console input. CO EQU 0F809H ;Console output ;ISIS System Call Identifiers. OPEN EQU 0 CLOSE EQU 1 DELETE EQU 2 READ EQU 3 WRITE EQU 4 SEEK EQU 5 LOAD EQU 6 RENAME EQU 7 CONSOL EQU 8 EXIT EQU 9 ATTRIB EQU 10 RESCAN EQU 11 ERROR EQU 12 WHOCON EQU 13 SPATH EQU 14 CSEG main: ; lxi sp, STKTOP ;Stack pointer. ;Sign-on message. call type DB CR,LF,'One-Dimensional Cellular Automaton by Roger Arrick 2018',STOP ;Get blob char from user. mvi a,'*' sta BLOB ; call blobg ;Get rule from user. call ruleg ;Start message. call type DB CR,LF,'Running. Q=Quit, Space=Pause',CR,LF,STOP ;Load initial conditions into Row 1. call r1clr lda BLOB sta ROW1+(COLS/2) ;Middle ;Main Loop. main1: ;Display Row 1. call rout ;Clear Row 2. call r2clr ;Calculate rule into Row 2. call rulee ;Move Row 2 into Row 1. call rmov ;If user enters a character, stop or pause, otherwise loop. in 0F7H ;Get console 8251 status. MDS888 CRT port. ani 02H ;Received a char? Zero=no. in 0F6H ;Get char. Do this either way to clear buffer. jz main1 cpi SPACE ;Space bar pauses. jnz mainx ;Any other char stops. call CI ;Wait for char to resume. jmp main1 ;Loop. mainx: ;All done, restart. call type DB CR,LF,'Done.',STOP jmp main ;---------------------------------------------------------------------------- ;Calculate rule into Row 2. ;Pseudo code. ;Setup vars. b=column counter, hl=row1, de=row2, c=pattern ;if b counter zero then done ;get row 1 left into bit 2 ;get row 1 center into bit 1 ;get row 1 right into bit 0 ;These 3 bits are the pattern stored in c ;if pattern = 000 then ; if rule bit 0 = 1 then set blob in row 2 ;if pattern = 001 then ; if rule bit 1 = 1 then set blob in row 2 ;if pattern = 010 then ; if rule bit 2 = 1 then set blob in row 2 ;if pattern = 011 then ; if rule bit 3 = 1 then set blob in row 2 ;if pattern = 100 then ; if rule bit 4 = 1 then set blob in row 2 ;if pattern = 101 then ; if rule bit 5 = 1 then set blob in row 2 ;if pattern = 110 then ; if rule bit 6 = 1 then set blob in row 2 ;if pattern = 111 then ; if rule bit 7 = 1 then set blob in row 2 ;adjust counters/pointers. ;loop rulee: ;Setup variables. lxi h,ROW1 ;HL = Row 1 cell counter. lxi d,ROW2 ;DE = Row 2 cell counter. mvi b,COLS ;B = Columns counter. ruleel: ;Check for done. mov a,b cpi 0 ;If B=0 then return. rz ;Create bit pattern in C according to row 1 cells. mvi c,0 ;C = bit2=left, bit1=center, bit0=right ;Get row 1 left into bit 2 of c. ;If left is less than zero then skip. mov a,b ;if counter = cols then at 0. cpi COLS jz ruleex dcx h ;Get left of current cell. mov a,m inx h jmp ruleez ;At far left edge, get far right edge (wrap around). ruleex: lda ROW1+COLS-1 ;Get far right edge (wraparound). jmp ruleez ;At far left edge, fudge space. mvi a,SPACE ;Now set the bit. ruleez: cpi SPACE jz rulee2 ;If space then empty, don't set bit. mvi a,00000100b ;Set the bit. ora c mov c,a ;Save in c. rulee2: ;Get row 1 center into bit 1 of c. mov a,m cpi SPACE jz rulee3 ;If space then empty, don't set bit. mvi a,00000010b ;Set the bit. ora c mov c,a ;Save in c. rulee3: ;Get row 1 right into bit 0 of c. ;If right is beyond cols then skip. mov a,b ;if counter = 1 then at end. cpi 1 jz ruleey inx h ;Get right of current cell. mov a,m dcx h jmp ruleew ;At far right edge, get far left edge (wrap around). ruleey: lda ROW1 ;Get far left edge (wraparound). jmp ruleew ;At far right edge, fudge space. mvi a,SPACE ;Now set the bit ruleew: cpi SPACE jz rulee4 ;If space then empty, don't set bit. mvi a,00000001b ;Set the bit. ora c mov c,a ;Pattern bits in c. ;Now, set row 2 cells according to row 1 pattern and rule bits. rulee4: ;If cell pattern 000 then mov a,c ;C=pattern bits. cpi 00000000b jnz rulee5 ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00000001b jz rulee5 ;Set row 2 cell lda BLOB stax d rulee5: ;If cell pattern 001 then mov a,c ;C=pattern bits. cpi 00000001b jnz rulee6 ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00000010b jz rulee6 ;Set row 2 cell lda BLOB stax d rulee6: ;If cell pattern 010 then mov a,c ;C=pattern bits. cpi 00000010b jnz rulee7 ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00000100b jz rulee7 ;Set row 2 cell lda BLOB stax d rulee7: ;If cell pattern 011 then mov a,c ;C=pattern bits. cpi 00000011b jnz rulee8 ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00001000b jz rulee8 ;Set row 2 cell lda BLOB stax d rulee8: ;If cell pattern 100 then mov a,c ;C=pattern bits. cpi 00000100b jnz rulee9 ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00010000b jz rulee9 ;Set row 2 cell lda BLOB stax d rulee9: ;If cell pattern 101 then mov a,c ;C=pattern bits. cpi 00000101b jnz ruleea ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 00100000b jz ruleea ;Set row 2 cell lda BLOB stax d ruleea: ;If cell pattern 110 then mov a,c ;C=pattern bits. cpi 00000110b jnz ruleeb ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 01000000b jz ruleeb ;Set row 2 cell lda BLOB stax d ruleeb: ;If cell pattern 111 then mov a,c ;C=pattern bits. cpi 00000111b jnz ruleec ;then if rule bit = 1 then lda RULEL ;Get the rule. ani 10000000b jz ruleec ;Set row 2 cell lda BLOB stax d ruleec: ;Update pointers and counters for next loop. inx h ;Next row 1 cell location. inx d ;Next row 2 cell location. dcr b ;Down count. jmp ruleel ;Loop until done with all cells in row ;---------------------------------------------------------------------------- ;Rule # Test. Return carry = 1 if HL matches RULEH and RULEL. ;Destroys A. ; rulet: lda RULEH ;Compare high byte. cmp h jnz ruletn ;No match lda RULEL ;Compare low byte. cmp l jnz ruletn ;No match stc ;Match - Set carry. ret ruletn: stc ;No match - clear carry. cmc ret ;---------------------------------------------------------------------------- ;Get rule code from console as a 4-char hex word 0-65535 into RULEL, RULEH. ;Backspace restarts program. ;Destroys A. ; ruleg: call type ;Ask db CR,LF,'Enter Rule (0000-ffff, Q=quit, BS=restart): ',STOP call hexinw ;Get 4-char hex word from console into HL. mov a,h ;High byte into RuleH. sta RULEH mov a,l ;High byte into RuleL. sta RULEL call crlf ;New line. ret ;---------------------------------------------------------------------------- ;Get blob char from user. ;Destroys A. ; blobg: call type ;Ask db CR,LF,'Enter blob char in hex (2A=*): ',STOP call hexin ;Get 2-char hex word from console into A. sta BLOB ret ;---------------------------------------------------------------------------- ;Display row 1. ;Destroys A. ; rout: push h ;Save regs. push b lxi h,ROW1 ;HL = Row. mvi b,COLS ;B = Columns counter. call crlf ;New line. routl: mov a,b ;Check for done. cpi 0 jz routx mov c,m ;Get char. call CO ;Display it. inx h ;Point to next column. dcr b ;Decrement column counter. jmp routl ;Loop until done. routx: pop b ;Restore regs. pop h ret ;---------------------------------------------------------------------------- ;Clear row 1. ;Destroys A. ; r1clr: push h ;Save regs. push b lxi h,ROW1 mvi b,COLS ;B = Columns counter. r1clrl: mov a,b ;Check for done. cpi 0 jz r1clrx mvi m,SPACE ;Clear char. inx h ;Point to next column. dcr b ;Decrement column counter. jmp r1clrl ;Loop until done. r1clrx: pop b ;Restore regs. pop h ret ;---------------------------------------------------------------------------- ;Clear row 2. ;Destroys A. ; r2clr: push h ;Save regs. push b lxi h,ROW2 mvi b,COLS ;B = Columns counter. r2clrl: mov a,b ;Check for done. cpi 0 jz r2clrx mvi m,SPACE ;Clear char. inx h ;Point to next column. dcr b ;Decrement column counter. jmp r2clrl ;Loop until done. r2clrx: pop b ;Restore regs. pop h ret ;---------------------------------------------------------------------------- ;Move ROW 2 to ROW 1. ;Destroys A. ; rmov: push h ;Save regs. push d push b lxi h,ROW1 ;HL = Row 1. lxi d,ROW2 ;DE = Row 1. mvi b,COLS ;B = Columns counter. rmov1: mov a,b ;Check for done. cpi 0 jz rmovx ldax d ;get row 2. mov m,a ;put in row 1. inx h ;Point to next column. inx d dcr b ;Decrement column counter. jmp rmov1 ;Loop until done. rmovx: pop b ;Restore regs. pop d pop h ret ;---------------------------------------------------------------------------- ;Type string following call to CO. ; type: xthl ;Get pointer to string. push b ;Don't destroy BC. mov a,m ;Get the char. inx h ;Point to next char. cpi STOP ;Stop? jz type1 mov c,a ;Send char. call CO jmp type+2 ;Next char. type1: pop b xthl ;Get return address back to caller. ret ;---------------------------------------------------------------------------- ;Read 4-char hex byte from console. ;No validation. ;Return in HL. ; hexinw: call hexin ;Get hex byte mov h,a ;High byte. call hexin ;Get hex byte mov l,a ;Low byte. ret ;---------------------------------------------------------------------------- ;Read 2-char hex byte from console. ;No validation. ;Return in A. ; hexin: push b ;Don't destroy regs. call hexine ;Get 1st char and echo. call hexinc ;Convert char into value. mov b,a ;Save temp. call hexine ;Get 2nd char and echo. call hexinc ;Convert char into value. mov c,a ;Save temp. mov a,b ;Put 1st value in high nibble. rlc rlc rlc rlc ani 0f0h ora c ;Put 2nd value in low nibble. pop b ;Don't destroy regs. ret ;All done. ;Get char and echo, into A. hexine: call CI cpi BS ;BS restarts program. jz main cpi 'q' ;q=quit. jz done cpi 'Q' ;Q=quit. jz done mov c,a call CO cpi BS ;BS restarts program. jz main mov a,c ret ;Convert ASCII char in A to a 4 bit value. 0-F = 0-15. hexinc: sui '0' cpi 10 rm sui 7 ani 0fh ret ;---------------------------------------------------------------------------- ;CRLF. ; crlf: push b mvi c,CR call CO mvi c,LF call CO pop b ret ;---------------------------------------------------------------------------- ;Return to OS. ; done: call crlf MVI C,EXIT LXI D,EBLK CALL ISIS ;---------------------------------------------------------------------------- ;Storage ; EBLK: dw ESTAT ;For ISIS calls. ESTAT: ds 2 BLOB: ds 1 ;Blob character. RULEH: ds 1 ;Rule high byte. RULEL: ds 1 ;Rule low byte. ROW1: ds COLS ;Row of elements displayed. ROW2: ds COLS ;Row of elements being worked on. END main