home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk10 / apps / life / life2.asm < prev    next >
Encoding:
Assembly Source File  |  1988-08-11  |  10.5 KB  |  386 lines

  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
  386.