From 8e0a308b85272b28b59e7db0079472a81f0fc2dc Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Wed, 26 Feb 2020 17:14:31 +0200 Subject: [PATCH] initial commit, bumming the sierpinski --- dos1/Makefile | 20 +++++ dos1/a.asm | 29 +++++++ dos1/b.asm | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dos1/c.asm | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 537 insertions(+) create mode 100644 dos1/Makefile create mode 100644 dos1/a.asm create mode 100644 dos1/b.asm create mode 100644 dos1/c.asm diff --git a/dos1/Makefile b/dos1/Makefile new file mode 100644 index 0000000..7c805f5 --- /dev/null +++ b/dos1/Makefile @@ -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 index 0000000..5b8f6ea --- /dev/null +++ b/dos1/a.asm @@ -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 index 0000000..8acb772 --- /dev/null +++ b/dos1/b.asm @@ -0,0 +1,252 @@ +; DOS or bootable sierpinski triangle hack +; +; Author: John Tsiombikas +; 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/ 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 index 0000000..fdba3c0 --- /dev/null +++ b/dos1/c.asm @@ -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: -- 1.7.10.4