initial commit, bumming the sierpinski
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 26 Feb 2020 15:14:31 +0000 (17:14 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 26 Feb 2020 15:14:31 +0000 (17:14 +0200)
dos1/Makefile [new file with mode: 0644]
dos1/a.asm [new file with mode: 0644]
dos1/b.asm [new file with mode: 0644]
dos1/c.asm [new file with mode: 0644]

diff --git a/dos1/Makefile b/dos1/Makefile
new file mode 100644 (file)
index 0000000..7c805f5
--- /dev/null
@@ -0,0 +1,20 @@
+.PHONY: all
+all: a.com b.com c.com
+
+a.com: a.asm
+b.com: b.asm
+c.com: c.asm
+
+%.com: %.asm
+       nasm -f bin -o $@ $<
+
+%.img: %.asm
+       nasm -f bin -DBOOTSECT -o $@ $<
+
+.PHONY: clean
+clean:
+       rm -f a.com
+
+.PHONY: boot
+boot: b.img
+       qemu-system-i386 -fda $<
diff --git a/dos1/a.asm b/dos1/a.asm
new file mode 100644 (file)
index 0000000..5b8f6ea
--- /dev/null
@@ -0,0 +1,29 @@
+       bits 16
+       org 100h
+
+       ; call video bios (10h) to set video mode (call 00h), to mode
+       ; 13h (320x200 8bpp).
+       mov ax, 13h     ; call number in ah (0), call argument in al (13h)
+       int 10h         ; call video bios
+
+       ; setup es to access the framebuffer segment (a000h)
+       push word 0a000h
+       pop es
+
+       ; prepare to fill the framebuffer with red (default palette color 4)
+       mov eax, 04040404h      ; value to store each time
+       mov ecx, 16000  ; framebuffer size in 32bit units (320x200/4 = 16000)
+       xor di, di      ; start from offset 0
+       rep stosd       ; repeat (while ecx != 0) the "store string dword" instr.
+
+.mainloop:
+       in al, 60h      ; read pending scancode from the keyboard port (if any)
+       dec al          ; ESC is 1, so decrement ...
+       jnz .mainloop   ; ... and loop as long as the result was not 0
+
+       ; switch back to text mode (mode 3)
+       mov ax, 3
+       int 10h
+
+       ; return to dos
+       ret
diff --git a/dos1/b.asm b/dos1/b.asm
new file mode 100644 (file)
index 0000000..8acb772
--- /dev/null
@@ -0,0 +1,252 @@
+; DOS or bootable sierpinski triangle hack
+;
+; Author: John Tsiombikas <nuclear@member.fsf.org>
+; License: public domain or CC0
+;
+; Build for DOS: nasm -o sierp.com -f bin sierp.asm
+; Build to boot: nasm -o sierp.img -f bin -DBOOTSECT sierp.asm
+;       (then dd if=sierp.img of=/dev/<usbstick> bs=512)
+
+       bits 16
+%ifdef BOOTSECT
+       org 7c00h
+%else
+       org 100h
+%endif
+
+NUM_POINTS equ 8192
+SHADOW_OFFS equ 5
+
+%macro SETPAL 4
+       push word %4
+       push word %3
+       push word %2
+       push word %1
+       call setpal
+       add sp, 8
+%endmacro
+
+start:
+%ifdef BOOTSECT
+       xor ax, ax
+       mov ds, ax
+       mov es, ax
+       mov ss, ax
+       jmp 00:.setcs
+.setcs:
+       mov sp, 0
+%endif
+       ; call video bios (10h) to set video mode (call 00h), to mode
+       ; 13h (320x200 8bpp).
+       mov ax, 13h     ; call number in ah (0), call argument in al (13h)
+       int 10h         ; call video bios
+
+       ; "allocate" the next segment for the framebuffer
+       mov ax, es
+       add ax, 1000h
+       mov es, ax
+
+       ; setup palette for the effect
+       ; - bg color (80h)
+       ; - shadow color (81h)
+       ; - fractal color (82h)
+       SETPAL 80h, 40, 40, 80
+       SETPAL 81h, 16, 16, 32
+       SETPAL 82h, 96, 192, 96
+
+.mainloop:
+       call animate
+
+       ; clear the framebuffer
+       mov eax, 80808080h      ; bg color
+       mov ecx, 16000          ; framebuffer size in 32bit units (320x200/4 = 16000)
+       xor di, di              ; start from offset 0
+       rep stosd               ; repeat (while ecx != 0) the "store string dword"
+
+       ; draw shadow
+       push word SHADOW_OFFS   ; offset for the shadow
+       push word 81h           ; shadow color
+       call drawsierp
+       ; draw fractal
+       mov bp, sp
+       mov word [bp + 2], 0    ; reset offset
+       mov word [bp], 82h      ; fractal color
+       call drawsierp
+       add sp, 4               ; clean up arguments from the stack
+
+       ; copy framebuffer to video ram
+       push ds
+       push es
+       ; point ds:si (source) to es:0
+       mov ax, es
+       mov ds, ax
+       xor si, si
+       ; point es:di (dest) to a000:0
+       mov ax, 0a000h
+       mov es, ax
+       xor di, di
+       mov ecx, 16000
+       call wait_vblank
+       rep movsd
+       pop es
+       pop ds
+
+%ifdef BOOTSECT
+       jmp .mainloop
+%else
+       in al, 60h      ; read pending scancode from the keyboard port (if any)
+       dec al          ; ESC is 1, so decrement ...
+       jnz .mainloop   ; ... and loop as long as the result was not 0
+
+       ; switch back to text mode (mode 3)
+       mov ax, 3
+       int 10h
+       ; return to dos
+       ret
+%endif
+
+       ; VBLANK is bit 3 of the input status #1 register (port 3dah).
+       ; It's 0 while we're in the visible area, and 1 if we're in the
+       ; vertical blank period.
+wait_vblank:
+       mov dx, 3dah
+       ; in case we're already in vblank, wait until we get out of it
+.inblank:
+       in al, dx
+       and al, 8
+       jnz .inblank    ; loop while vblank bit is 1 (in vblank)
+       ; wait until vblank starts
+.notblank:
+       in al, dx
+       and al, 8
+       jz .notblank    ; loop while vblank bit is 0 (visible area)
+       ret
+
+       ; draw sierpinski triangle
+drawsierp:
+       mov bp, sp
+       ; start from one of the vertices
+       mov ax, [sierp_verts]
+       mov bx, [sierp_verts + 2]
+       mov [sierp_pt], ax
+       mov [sierp_pt + 2], bx
+       ; number of iterations in cx
+       mov cx, NUM_POINTS
+.loop: ; pick a vertex at random and move half-way there
+       call rand
+       mov bx, 3
+       xor dx, dx
+       div bx  ; dx is now rand % 3
+       ; put the vertex address in ebx
+       mov edi, sierp_verts
+       movzx ebx, dx
+       lea ebx, [ebx * 4 + edi]
+       ; add to sierp_pt and divide by 2 to move half-way there
+       mov ax, [bx]
+       add ax, [sierp_pt]
+       shr ax, 1
+       mov [sierp_pt], ax      ; store the resulting X back to [sierp_pt]
+       mov di, ax              ; save X coordinate in di
+       mov ax, [bx + 2]
+       add ax, [sierp_pt + 2]
+       shr ax, 1
+       mov [sierp_pt + 2], ax  ; store the reuslting Y back to [sierp_pt + 2]
+       add ax, [bp + 4]        ; add offset
+       mov bx, ax
+       shl ax, 8
+       shl bx, 6
+       add bx, ax              ; bx = Y * 320
+       add bx, [bp + 4]        ; add offset
+       mov al, [bp + 2]        ; color to set
+       mov byte [es:bx + di], al
+
+       dec cx
+       jnz .loop
+       ret
+
+       align 2
+sierp_verts:
+       dw 160, 40
+       dw 240, 160
+       dw 80, 160
+sierp_pt dw 0, 0
+sierp_vel:
+       dw 1, 1
+       dw -1, 1
+       dw -1, -1
+
+animate:
+       mov cx, 3
+       mov di, sierp_verts
+       mov si, sierp_vel
+.loop:
+       mov ax, [di]            ; grab vertex X
+       add ax, [si]            ; add velocity X
+       jl .xout
+       cmp ax, 320-SHADOW_OFFS
+       jge .xout
+       jmp .skip_xflip
+.xout:
+       sub ax, [si]            ; revert to previous X
+       neg word [si]           ; negate velocity X
+.skip_xflip:
+       mov [di], ax            ; update vertex X
+
+       ; to do the same for Y increment edi and esi by 2
+       add di, 2
+       add si, 2
+       mov ax, [di]            ; grab vertex Y
+       add ax, [si]            ; add velocity Y
+       jl .yout
+       cmp ax, 200-SHADOW_OFFS
+       jge .yout
+       jmp .skip_yflip
+.yout:
+       sub ax, [si]            ; revert to previous Y
+       neg word [si]           ; negate velocity Y
+.skip_yflip:
+       mov [di], ax            ; update vertex Y
+
+       add di, 2
+       add si, 2
+       dec cx
+       jnz .loop
+       ret
+
+       ; set palette entry (idx, r, g, b)
+setpal:
+       mov bp, sp
+       mov dx, 3c8h            ; DAC index port
+       mov al, [bp + 2]
+       out dx, al
+       inc dx                  ; DAC data port
+       mov al, [bp + 4]
+       shr al, 2
+       out dx, al
+       mov al, [bp + 6]
+       shr al, 2
+       out dx, al
+       mov al, [bp + 8]
+       shr al, 2
+       out dx, al
+       ret
+
+       ; random number generator
+rand:
+       mov eax, [randval]
+       mul dword [randmul]
+       add eax, 12345
+       and eax, 0x7fffffff
+       mov [randval], eax
+       shr eax, 16
+       ret
+
+       align 4
+randval dd 0
+randmul dd 1103515245
+
+%ifdef BOOTSECT
+       times 510-($-$$) db 0
+       db 0x55,0xaa
+%endif
+; vi:ft=nasm:
diff --git a/dos1/c.asm b/dos1/c.asm
new file mode 100644 (file)
index 0000000..fdba3c0
--- /dev/null
@@ -0,0 +1,236 @@
+; Lowest yet: 312
+
+       bits 16
+%ifdef BOOTSECT
+       org 7c00h
+%else
+       org 100h
+%endif
+
+NUM_POINTS equ 8192
+SHADOW_OFFS equ 5
+
+SIERP_PT equ code_end
+RANDVAL equ code_end + 4
+
+
+%macro WAIT_VBLANK 0
+       mov dx, 3dah
+.inblank:
+       in al, dx
+       and al, 8
+       jnz .inblank    ; loop while vblank bit is 1 (in vblank)
+.notblank:
+       in al, dx
+       and al, 8
+       jz .notblank    ; loop while vblank bit is 0 (visible area)
+%endmacro
+
+
+start:
+%ifdef BOOTSECT
+       xor ax, ax
+       mov ds, ax
+       mov es, ax
+       mov ss, ax
+       jmp 00:.setcs
+.setcs:
+       mov sp, 0
+%endif
+       mov al, 13h
+       int 10h
+
+       ; "allocate" the next segment for the framebuffer
+       mov ax, es
+       add ax, 1000h
+       mov es, ax
+
+       ; setup palette for the effect
+       ; - bg color (0)
+       ; - shadow color (1)
+       ; - fractal color (2)
+       mov dx, 0x3c8
+       xor al, al
+       out dx, al
+       inc dx
+       mov al, 10      ; 0: 40, 40, 80
+       out dx, al
+       out dx, al
+       shl al, 1
+       out dx, al
+       mov al, 4       ; 1: 16, 16, 32
+       out dx, al
+       out dx, al
+       shl al, 1
+       out dx, al
+       mov al, 18h     ; 2: 96, 192, 96
+       out dx, al
+       mov al, 48
+       out dx, al
+       mov al, 18h
+       out dx, al
+
+mainloop:
+       call animate
+
+       ; clear the framebuffer
+       xor al, al
+       mov cx, 64000
+       xor di, di
+       rep stosb
+
+       ; draw shadow
+       mov si, 5
+       mov byte [setcol + 1], 1        ; shadow color
+       call drawsierp
+       ; draw fractal
+       xor si, si
+       mov byte [setcol + 1], 2        ; fractal color
+       call drawsierp
+
+       ; copy framebuffer to video ram
+       push ds
+       push es
+       ; point ds:si (source) to es:0
+       mov ax, es
+       mov ds, ax
+       xor si, si
+       ; point es:di (dest) to a000:0
+       mov ax, 0a000h
+       mov es, ax
+       xor di, di
+       mov cx, 32000
+       WAIT_VBLANK
+       rep movsw
+       pop es
+       pop ds
+
+%ifdef BOOTSECT
+       jmp mainloop
+%else
+       in al, 60h      ; read pending scancode from the keyboard port (if any)
+       dec al          ; ESC is 1, so decrement ...
+       jnz mainloop    ; ... and loop as long as the result was not 0
+
+       ; switch back to text mode (mode 3)
+       mov ax, 3
+       int 10h
+       ; return to dos
+       ret
+%endif
+
+       ; draw sierpinski triangle
+drawsierp:
+       ; start from one of the vertices
+       mov ax, [sierp_verts]
+       mov bx, [sierp_verts + 2]
+       mov [SIERP_PT], ax
+       mov [SIERP_PT + 2], bx
+       ; number of iterations in cx
+       mov cx, NUM_POINTS
+dsloop:        ; pick a vertex at random and move half-way there
+       call rand
+       mov bx, 3
+       xor dx, dx
+       div bx  ; dx is now rand % 3
+       ; put the vertex address in bx
+       mov bx, sierp_verts
+       shl dx, 2
+       add bx, dx
+       ; add to SIERP_PT and divide by 2 to move half-way there
+       mov ax, [bx]
+       add ax, [SIERP_PT]
+       shr ax, 1
+       mov [SIERP_PT], ax      ; store the resulting X back to [SIERP_PT]
+       mov di, ax              ; save X coordinate in di
+       mov ax, [bx + 2]
+       add ax, [SIERP_PT + 2]
+       shr ax, 1
+       mov [SIERP_PT + 2], ax  ; store the reuslting Y back to [SIERP_PT + 2]
+       add ax, si      ; add offset
+       mov bx, ax
+       shl ax, 8
+       shl bx, 6
+       add bx, ax              ; bx = Y * 320
+setcol:        mov al, 1
+       mov byte [es:bx + di], al
+
+       dec cx
+       jnz dsloop
+       ret
+
+sierp_verts:
+       dw 160, 40
+       dw 240, 160
+       dw 80, 160
+sierp_vel:
+       dw 1, 1
+       dw -1, 1
+       dw -1, -1
+
+animate:
+       mov cx, 3
+       mov di, sierp_verts
+       mov si, sierp_vel
+.loop:
+       mov ax, [di]            ; grab vertex X
+       add ax, [si]            ; add velocity X
+       jl .xout
+       cmp ax, 320-SHADOW_OFFS
+       jge .xout
+       jmp .skip_xflip
+.xout:
+       sub ax, [si]            ; revert to previous X
+       neg word [si]           ; negate velocity X
+.skip_xflip:
+       mov [di], ax            ; update vertex X
+
+       ; to do the same for Y increment edi and esi by 2
+       add di, 2
+       add si, 2
+       mov ax, [di]            ; grab vertex Y
+       add ax, [si]            ; add velocity Y
+       jl .yout
+       cmp ax, 200-SHADOW_OFFS
+       jge .yout
+       jmp .skip_yflip
+.yout:
+       sub ax, [si]            ; revert to previous Y
+       neg word [si]           ; negate velocity Y
+.skip_yflip:
+       mov [di], ax            ; update vertex Y
+
+       add di, 2
+       add si, 2
+       dec cx
+       jnz .loop
+       ret
+
+       ; random number generator
+rand:
+       mov ax, [randval]
+       mov bx, ax
+       shr bx, 7
+       xor ax, bx
+       mov bx, ax
+       shl bx, 9
+       xor ax, bx
+       mov [randval], ax
+       ret
+;      mov eax, [RANDVAL]
+;      mul dword [randmul]
+;      add eax, 12345
+;      and eax, 0x7fffffff
+;      mov [RANDVAL], eax
+;      shr eax, 16
+;      ret
+
+;randmul dd 1103515245
+randval dw 0ace1h
+code_end:
+
+%ifdef BOOTSECT
+       times 510-($-$$) db 0
+       db 0x55,0xaa
+%endif
+; vi:ft=nasm: