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