|
|
1.1 ! root 1: ;*** life2.asm - assembler routines for life.c ! 2: ;* ! 3: ;* Contains: _draw_grid - draws 79x45 grid on screen ! 4: ;* _dostep - advances the internal and screen grids ! 5: ;* one generation ! 6: ;* scrfill - private screen routine for _dostep ! 7: ;* scrremove - private screen routine for _dostep ! 8: ;* ! 9: ! 10: ! 11: ;*** segment definitions for the link with C ! 12: ; ! 13: _TEXT SEGMENT BYTE PUBLIC 'CODE' ! 14: _TEXT ENDS ! 15: _DATA SEGMENT WORD PUBLIC 'DATA' ! 16: _DATA ENDS ! 17: CONST SEGMENT WORD PUBLIC 'CONST' ! 18: CONST ENDS ! 19: _BSS SEGMENT WORD PUBLIC 'BSS' ! 20: _BSS ENDS ! 21: DGROUP GROUP CONST, _BSS, _DATA ! 22: ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP ! 23: ! 24: ;*** the public routines ! 25: ; ! 26: PUBLIC _draw_grid, _dostep ! 27: ! 28: ! 29: ;*** Global variables from LIFE.C ! 30: ; ! 31: EXTRN _ScrSeg:WORD ! 32: EXTRN _ScrCol:WORD ! 33: EXTRN _ScrRow:WORD ! 34: ! 35: ;*** OS/2 functions ! 36: ; ! 37: EXTRN VIOSCRUNLOCK:FAR ! 38: EXTRN VIOSCRLOCK:FAR ! 39: ! 40: ! 41: _TEXT SEGMENT ! 42: ;*** _draw_grid - clears screen and draws 79x45 grid ! 43: ;* ! 44: ;* Entry: ds:_ScrSeg - screen buffer segment, from life.c ! 45: ;* ! 46: ;* Exit: None ! 47: ;* ! 48: _draw_grid PROC NEAR ! 49: push bp ; startup ! 50: mov bp,sp ! 51: sub sp,2 ; one word variable for VIOSCRLOCK ! 52: push di ; save register used by C compiler ! 53: ! 54: ; get screen access ! 55: mov ax,1 ! 56: push ax ; wait until screen available ! 57: lea ax,byte ptr [bp-2] ! 58: push ss ! 59: push ax ; far address of return code ! 60: sub ax,ax ! 61: push ax ; reserved word ! 62: call VIOSCRLOCK ; call DOS for access ! 63: ! 64: ; get parameter and set up ! 65: mov es,ds:_ScrSeg ; (es) = screen buffer segment ! 66: xor di,di ; (di) = offset in screen (start at 0) ! 67: ! 68: ; loop to draw 45 rows of the tops and middles of grid squares ! 69: mov dx,45 ; (dx) = rows of grid squares, counter ! 70: dg1: mov ax,5555h ; (ax) = alternating bit pattern ! 71: mov cx,39 ; (cx) = number of full words on a line ! 72: rep stosw ; fill line with 5555h ! 73: mov es:[di],al ; finish off last odd byte ! 74: inc di ; (di) = start of next row ! 75: inc di ! 76: mov ax,08080h ; (ax) = left bit on ! 77: mov cx,40 ; (cx) = number of words on a line ! 78: rep stosw ; fill next line with f0f0h ! 79: dec dx ; at screen bottom? ! 80: jnz dg1 ; if no, loop ! 81: ! 82: ; draw the last line ! 83: mov ax,5555h ; (ax) = alternating bits ! 84: mov cx,39 ; (cx) = full words on last line ! 85: rep stosw ; do fill ! 86: mov es:[di],al ; finish off line with odd byte ! 87: ! 88: ; clear bottom on screen on even bit plane ! 89: inc di ; (di) = start of last few lines ! 90: sub ax,ax ; (ax) = blank ! 91: mov cx,400 ; (cx) = words left at bottom ! 92: rep stosw ! 93: ! 94: ; draw the grid lines on the odd bit plane ! 95: mov di,2000h ; (di) = top of odd bit plane ! 96: mov ax,08080h ; (ax) = left bit on ! 97: mov cx,40*2*45 ; (cx) = words to fill ! 98: rep stosw ; fill remainder with f0f0h ! 99: ! 100: ; clear bottom on screen on odd bit plane ! 101: sub ax,ax ; (ax) = blank ! 102: mov cx,400 ; (cx) = words left at bottom ! 103: rep stosw ! 104: ! 105: ; return the screen ! 106: sub ax,ax ! 107: push ax ; reserved word ! 108: call VIOSCRUNLOCK ; call DOS to return screen ! 109: ! 110: ; return ! 111: pop di ! 112: mov sp,bp ! 113: pop bp ! 114: ret ! 115: _draw_grid ENDP ! 116: ! 117: ! 118: ;*** _dostep - advances InGrid one generation. ! 119: ;* ! 120: ;* Entry: char far *INGRID - InGrid, main internal bit map of cells ! 121: ;* char far *INGRID2 - InGrid2, working area of same size ! 122: ;* unsigned INROW - InRow, bits per row of above to areas ! 123: ;* unsigned INCOL - InCol, rows of above to areas ! 124: ;* ds:_ScrSeg - from life.c ! 125: ;* ds:_ScrRow - from life.c ! 126: ;* ds:_ScrCol - from life.c ! 127: ;* ! 128: ;* Exit: InGrid is updated on generation in accordance with ! 129: ;* the rules of life. ! 130: ;* Returns in AX the return code from its VIOSCRLOCK call ! 131: ;* ! 132: INGRID EQU [bp+4] ! 133: INGRID2 EQU [bp+8] ! 134: INROW EQU [bp+12] ! 135: INCOL EQU [bp+14] ! 136: ! 137: _dostep PROC NEAR ! 138: push bp ! 139: mov bp,sp ! 140: sub sp,2 ; make room for local var ! 141: push di ! 142: push si ! 143: push es ! 144: push ds ! 145: ! 146: ; try to lock screen and put return code in [BP-2] ! 147: xor ax,ax ! 148: push ax ; don't wait until screen available ! 149: lea ax,byte ptr [bp-2] ! 150: push ss ! 151: push ax ; far address of return code ! 152: sub ax,ax ! 153: push ax ; reserved word ! 154: call VIOSCRLOCK ; call DOS for access ! 155: ! 156: ; get pointers to the two internal grids ! 157: les di,INGRID2 ; (es:di) = @InGrid2 ! 158: lds si,INGRID ; (ds:si) = @InGrid ! 159: ! 160: ; copy InGrid into InGrid2 ! 161: mov ax,INCOL ; (ax) = cells per row ! 162: mul word ptr INROW ; (ax) = total cells ! 163: mov cl,4 ! 164: shr ax,cl ; (ax) = cell/16 = total words ! 165: mov cx,ax ; (cx) = total words ! 166: rep movsw ; move InGrid into InGrid2 ! 167: ! 168: ! 169: ; main step loop ! 170: ; I use a rather odd algorithm. "neighbors" is defined ! 171: ; here as all cells in a 3x3 grid summed. If neighbors < 3, the ! 172: ; the cell in the center is turned off. If neighbors = 3, the cell ! 173: ; is turned on. If neighbors = 4, the cell is left in its current ! 174: ; state. If neighbors > 4, the cell is turned off. ! 175: push ds ! 176: pop es ; (es) = InGrid's segment ! 177: lds bx,INGRID2 ; (ds) = InGrid2's segment ! 178: ; (bx) = pointer to offset in both ! 179: mov di,INROW ; (di) = row count ! 180: mov si,INCOL ; (si) = column count ! 181: shr si,1 ! 182: shr si,1 ! 183: shr si,1 ; (si) = bytes per row in grids ! 184: ! 185: ; loop within the grid through all its rows ! 186: ; here we come when at the start of a row ! 187: ds1: mov cx,INCOL ; (cx) = column count ! 188: mov al,80h ; (al) = bit mask for current bit ! 189: xor dx,dx ; (dh) = #of neighbors 1 col back ! 190: ; (dl) = #of neighbors at cur col ! 191: ! 192: ; get number of neighbors on current row ! 193: ds2: xor ah,ah ; (ah) = count of neighbors on cur row ! 194: test ds:[bx],al ; is current bit on? ! 195: jz ds3 ; if not go on ! 196: inc ah ; if yes, inc neighbor count ! 197: ds3: cmp bx,si ; are we on top row ! 198: jb ds4 ; if yes, don't check above top ! 199: push bx ; save bx ! 200: sub bx,si ; backup bx to previous row ! 201: test ds:[bx],al ; is up a row bit on? ! 202: pop bx ; restore bx ! 203: jz ds4 ; if not go on ! 204: inc ah ; if yes, inc neighbor count ! 205: ds4: cmp di,1 ; are we on last row? ! 206: jz ds5 ; if yes, don't read off edge ! 207: test ds:[bx+si],al ; is bit down a row on? ! 208: jz ds5 ; if not, go on to final neighbor addin ! 209: inc ah ; if yes, inc neighbor count ! 210: ! 211: ; add up the total number of neighbors and decide what to do ! 212: ds5: cmp cx,INCOL ; are we at far left? ! 213: jz ds12 ; if yes, don't affect bits off edge ! 214: add dh,dl ; (dh) = previous two rows of neighbors ! 215: add dh,ah ; (dh) = total neighbor count ! 216: cmp dh,3 ! 217: jb ds6 ; if neighbors <3, turn off the cell ! 218: je ds9 ; if neighbors = 3, turn on the cell ! 219: cmp dh,4 ; ! 220: je ds12 ; if neighbors = 4, do nothing ! 221: ! 222: ; turn off the center bit ! 223: ds6: rol al,1 ; backup to center bit ! 224: jnc ds7 ; if no overflow, go on ! 225: dec bx ; else, backup to last byte ! 226: ds7: test es:[bx],al ; is it already off ! 227: jz ds8 ; if yes, don't do it again ! 228: not al ; turn on all bits but one to blank ! 229: and es:[bx],al ; force off bit in InGrid ! 230: not al ; restore al ! 231: ! 232: pop ds ; (ds) = C's data ptr ! 233: call scrremove ; turn off on screen ! 234: push ds ; resave C's data ptr ! 235: mov ds,[bp+8+2] ; (ds) = seg of InGrid2 ! 236: ! 237: ds8: ror al,1 ; put back al to foreward bit ! 238: jnc ds12 ; if no overflow, go to next bit ! 239: inc bx ; if overflow, restore bx ! 240: jmp ds12 ; go on to next bitl ! 241: ! 242: ; turn on the center bit ! 243: ds9: rol al,1 ; backup to center bit ! 244: jnc ds10 ; if no overflow, go on ! 245: dec bx ; else, backup to last byte ! 246: ds10: test es:[bx],al ; is it already on? ! 247: jnz ds11 ; if yes, don't do it again ! 248: or es:[bx],al ; force on bit in InGrid ! 249: pop ds ; (ds) = C's data ptr ! 250: call scrfill ; turn on on screen ! 251: push ds ; resave C's data ptr ! 252: mov ds,[bp+8+2] ; (ds) = seg of InGrid2 ! 253: ds11: ror al,1 ; put back al to foreward bit ! 254: jnc ds12 ; if no overflow, go to next bit ! 255: inc bx ; if overflow, restore bx ! 256: ! 257: ; advance to the next bit ! 258: ds12: ror al,1 ; (al) mask advances to next bit ! 259: mov dh,dl ; move done neighbor count ! 260: mov dl,ah ; move the new neighbor row into bl ! 261: jnc ds13 ; if still in same byte, jmp ! 262: inc bx ; if at byte end, advance to next byte ! 263: ds13: loop ds2 ; loop through rest of bits on line ! 264: ! 265: ! 266: ; at the end of the row ! 267: dec di ; decrement row count ! 268: jz dsx ; if at end of grid, goto exit routine ! 269: jmp ds1 ; if not at bottom, go to next row ! 270: ! 271: ; at the end of the grid ! 272: ; return the screen ! 273: dsx: cmp byte ptr [bp-2],0 ; is the screen locked? ! 274: jnz dsx1 ; if not, don't unlock ! 275: ! 276: sub ax,ax ! 277: push ax ; reserved word ! 278: call VIOSCRUNLOCK ; call DOS to return screen ! 279: ! 280: dsx1: xor ah,ah ! 281: mov al,[bp-2] ; return code from SCRLOCK ! 282: ! 283: pop ds ! 284: pop es ! 285: pop si ! 286: pop di ! 287: mov sp,bp ! 288: pop bp ! 289: ret ! 290: _dostep ENDP ! 291: ! 292: ! 293: ;*** scrfill - fills in a cell on the screen in 79x45 grid ! 294: ;* ! 295: ;* Entry: (di) = row number counted from bottom up (InRow-di=row to fill) ! 296: ;* (cx) = col number from right-1 (InCol-1-cx = col to fill) ! 297: ;* (ds) = data segment of life.c ! 298: ;* ! 299: ;* Exit: None, saves all registers ! 300: ;* ! 301: scrfill proc near ! 302: cmp [bp-2],byte ptr 0 ; is the screen available? ! 303: jnz sfxx ; if not, exit ! 304: ! 305: push es ! 306: push ax ! 307: push bx ! 308: push dx ! 309: ! 310: ; get screen pointer ! 311: mov es,ds:_ScrSeg ; (es) = screen buf segment ! 312: mov ax,INROW ! 313: sub ax,di ; (ax) = row ! 314: cmp ax,ds:_ScrRow ; is it on the screen? ! 315: jae sfx ; if off, exit ! 316: mul WORD PTR INCOL ; * InCol ! 317: shl ax,1 ; * 2 ! 318: mov dx,INCOL ! 319: sub dx,cx ! 320: dec dx ; (dx) = col to fill ! 321: cmp dx,ds:_ScrCol ; is it on the screen? ! 322: jae sfx ; if off, exit ! 323: add ax,dx ; + col = scrn offset of cell ! 324: ! 325: ; fill in screen cell ! 326: mov bx,ax ; (es:bx) = far ptr to screen cell ! 327: mov BYTE PTR es:[bx+2000h],7fh ; first line of cell ! 328: mov BYTE PTR es:[bx+80],7fh ; second ! 329: mov BYTE PTR es:[bx+2000h+80],7fh ; third line of cell ! 330: ! 331: sfx: pop dx ! 332: pop bx ! 333: pop ax ! 334: pop es ! 335: sfxx: ret ! 336: scrfill endp ! 337: ! 338: ! 339: ;*** scrremove - removes a cell on the screen in 79x45 grid ! 340: ;* ! 341: ;* Entry: (di) = row number counted from bottom up (InRow-di=row to fill) ! 342: ;* (cx) = col number from right-1 (InCol-1-cx = col to fill) ! 343: ;* (ds) = data segment of life.c ! 344: ;* ! 345: ;* Exit: None, saves all registers ! 346: ;* ! 347: scrremove proc near ! 348: cmp [bp-2],byte ptr 0 ; is the screen available? ! 349: jnz srxx ; if not, exit ! 350: ! 351: push es ! 352: push ax ! 353: push bx ! 354: push dx ! 355: ! 356: ; get screen pointer ! 357: mov es,ds:_ScrSeg ; (es) = screen buf segment ! 358: mov ax,INROW ! 359: sub ax,di ; (ax) = row ! 360: cmp ax,ds:_ScrRow ; is it on the screen? ! 361: jae srx ; if off, exit ! 362: mul WORD PTR INCOL ; * InCol ! 363: shl ax,1 ; * 2 ! 364: mov dx,INCOL ! 365: sub dx,cx ! 366: dec dx ; (dx) = col ! 367: cmp dx,ds:_ScrCol ; is it on the screen? ! 368: jae srx ; if off, exit ! 369: add ax,dx ; + col = scrn offset of cell ! 370: ! 371: ; remove screen cell ! 372: mov bx,ax ; (es:bx) = far ptr to screen cell ! 373: mov BYTE PTR es:[bx+2000h],80h ; first line of cell ! 374: mov BYTE PTR es:[bx+80],80h ; second ! 375: mov BYTE PTR es:[bx+2000h+80],80h ; third line of cell ! 376: ! 377: srx: pop dx ! 378: pop bx ! 379: pop ax ! 380: pop es ! 381: srxx: ret ! 382: scrremove endp ! 383: ! 384: _TEXT ENDS ! 385: END
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.