public      SetMode_, ResetMode_, GenTable_, CalcLife_

.486
.model flat
.code

VID_MODE    equ 0Dh
X_SIZE      equ 320
Y_SIZE      equ 200

X_BYTES     equ X_SIZE / 8

;----------------------------------------------------------
; void SetMode(void);

SetMode_    Proc

            push eax                ;Set the video mode
            mov ax,VID_MODE
            int 10h
            pop eax
            ret

SetMode_    EndP

;----------------------------------------------------------
; void ResetMode(void);

ResetMode_  Proc

            push eax                ;Set text mode
            mov ax,3
            int 10h
            pop eax
            ret

ResetMode_  EndP

;----------------------------------------------------------
; void GenTable(void *buf);

GenTable_   Proc

            pushad                  ;Save all registers

            mov edi,eax             ;EDI = table pointer
            xor esi,esi             ;Zero ESI (counter)

gt_loop:    xor al,al               ;AL = 0
            mov ebx,esi             ;EBX = bits         [ 1 ]
            and ebx,038A38h
            call gt_count           ;Count bits
            cmp cl,3
            sete ah
            cmp cl,2
            jne gt_test2
            test esi,000400h
            setnz ah

gt_test2:   shl ah,3                ;Add in bit
            or al,ah

            mov ebx,esi             ;EBX = bits         [ 2 ]
            and ebx,01C51Ch
            call gt_count           ;Count bits
            cmp cl,3
            sete ah
            cmp cl,2
            jne gt_test3
            test esi,000200h
            setnz ah

gt_test3:   shl ah,2                ;Add in bit
            or al,ah

            mov ebx,esi             ;EBX = bits         [ 3 ]
            and ebx,00E28Eh
            call gt_count           ;Count bits
            cmp cl,3
            sete ah
            cmp cl,2
            jne gt_test4
            test esi,000100h
            setnz ah

gt_test4:   shl ah,1                ;Add in bit
            or al,ah

            mov ebx,esi             ;EBX = bits         [ 4 ]
            and ebx,007147h
            call gt_count           ;Count bits
            cmp cl,3
            sete ah
            cmp cl,2
            jne gt_lback
            test esi,000080h
            setnz ah

gt_lback:   or al,ah                ;Add in bit
            stosb                   ;Store value
            inc esi
            cmp esi,040000h         ;Loop back
            jb gt_loop

            popad                   ;Restore registers
            ret                     ;Return

gt_count:   mov ecx,ebx             ;Collect bit pairs
            shr ebx,1
            and ecx,55555555h
            and ebx,55555555h
            add ebx,ecx

            mov ecx,ebx             ;Collect nibbles
            shr ebx,2
            and ecx,33333333h
            and ebx,33333333h
            add ebx,ecx

            mov ecx,ebx             ;Collect bytes
            shr ebx,4
            and ecx,0F0F0F0Fh
            and ebx,0F0F0F0Fh
            add ecx,ebx

            add ch,cl               ;CL = result
            shr ecx,8
            add cl,ch
            ret                     ;Return

GenTable_   EndP

;----------------------------------------------------------
; void CalcLife(void *src, void *dest, void *table);

CalcLife_   Proc

            pushad                  ;Save all registers

            mov esi,eax             ;ESI = source
            mov edi,edx             ;EDI = dest. - source
            sub edi,esi             ;EBP = table
            mov ebp,ebx

            mov ecx,X_BYTES         ;ECX = X counter
            add esi,ecx             ;Start at row 2

cl_oloop:   pushad                  ;Save all registers

            mov eax,[esi-X_BYTES-1] ;Load initial values
            call cl_shift
            mov eax,[esi-1]
            call cl_shift           ;Clear top byte
            mov byte ptr [esi+edi-X_BYTES],0

            mov ecx,Y_SIZE - 2      ;ECX = Y size - 2

cl_loop:    mov eax,[esi+X_BYTES-1] ;Get next row of bits

            bswap eax               ;Serialize bits in EAX
            shl eax,7

            shld ebx,eax,6          ;Shift into EBX and EDX
            shl eax,4
            shld edx,eax,6
            and ebx,03FFFFh         ;Mask to fit
            and edx,03FFFFh

            mov ah,[ebp+ebx]        ;Look up values for 2 bytes
            mov al,[ebp+edx]
            shl ah,4
            or al,ah

            mov [esi+edi],al        ;Write new value

            add esi,X_BYTES         ;Next row
            dec ecx                 ;Loop back
            jnz cl_loop

            mov byte ptr [esi+edi],0 ;Clear bottom byte
            popad                   ;Restore registers
            inc esi                 ;Next column
            dec ecx                 ;Loop back
            jnz cl_oloop

            popad                   ;Restore registers
            ret                     ;Return

cl_shift:   bswap eax               ;Serialize bits in EAX
            shl eax,7

            shld ebx,eax,6          ;Shift into EBX and EDX
            shl eax,4
            shld edx,eax,6
            ret

CalcLife_   EndP

End
