X-Git-Url: https://eleni.mutantstargoat.com/git/?p=bootboot;a=blobdiff_plain;f=bb.asm;h=c28880edbec2b0680843c3ce277c4840e010890b;hp=397bb3053154b28be9a62c0194cfb17ded1d8fac;hb=8d136d20a7fbf88f385d1a885977e081ed5dc89a;hpb=58f3c8759eb5a75795d83199d237f038f1d2cf4c diff --git a/bb.asm b/bb.asm index 397bb30..c28880e 100644 --- a/bb.asm +++ b/bb.asm @@ -8,6 +8,20 @@ ; we have to tell assembler that code is 16bit mode bits 16 +; macros +%macro SETPAL 4 ; 4 = num arguments of macro (index rgb) + mov dx, 3c8h ; index register + mov al, %1 + out dx, al + inc dx + mov al, %2 >> 2 + out dx, al + mov al, %3 >> 2 + out dx, al + mov al, %4 >> 2 ; shift to give the value from 0 - 255 + out dx, al +%endmacro + start: mov sp, 7c00h @@ -37,26 +51,15 @@ start: mov ax, 3 call clearscreen -; waiting for keypress -; x86 has 2 special instructions to read/write from I/O -; devices: in and out (because some processors have different -; address spaces for devices and for memory, arm not) -.key_wait: - in al, 64h ; 60h = keyb data port, 64h = keyb status port - and al, 1 ; 1 = OUTBUF_FULL = the keyb controller out buf is full - jz .key_wait - - in al, 60h ; reads the keyb that was pressed to reset the flag - ; load 2nd sector from boot device and jump to it ; bios helpers, 13h = disk io mov ax, 0 mov ds, ax - mov ah, 02h ; call 2: read sectors into memory - mov al, 1 ; number of sectors to read - mov ch, 0 ; low 8 bits of cylinder number - mov cl, 2 ; sector number that starts from 1 - mov dh, 0 ; head number + mov ah, 02h ; call 2: read sectors into memory + mov al, 3 ; number of sectors to read + mov ch, 0 ; low 8 bits of cylinder number + mov cl, 2 ; sector number that starts from 1 + mov dh, 0 ; head number mov dl, [saved_drive_num] ; 8bits mov bx, sector_2 int 13h @@ -126,7 +129,237 @@ sector_2: cmp cx, 200 jnz .y_loop -; fix palette (256 colors) - +; setup grayscale palette (64 first colors because ramdac uses 6 bits / color so 2^6) +; ram dac (digital to analog converter) tis vga +; in a ^ register which index we want to write +; 3 writes in another ramdac register (data) +; ramdac feature: when you need to set a palette + mov al, 0 ; first index + mov dx, 3c8h ; ramdac index registe + out dx, al ; because io port (address) > 255 + inc dx ; ramdac data register: 3c9h +.pal_loop: + out dx, al ; r + out dx, al ; g + out dx, al ; b + inc al + test al, 3fh ; test with 3fh to keep the lowest 6 bits of al + jnz .pal_loop + +; setup lovebug palette + SETPAL 64, 0, 255, 0 ; chr(64) = @ + SETPAL 65, 0, 0, 0 ; A + SETPAL 66, 50, 50, 50 ; B + SETPAL 67, 57, 4, 4 ; C + SETPAL 68, 108, 9, 9 ; D + SETPAL 69, 164, 4, 4 ; E + +; disable all interrupts (for bios to not read the keyboard) + cli + + ; ds on 0 because rand uses it for accesses to mem + xor ax, ax + mov ds, ax + mov ax, backbuffer + shr ax, 4 ; to use it as segment! (shift right) + mov es, ax +main_loop: +; draw to back buffer + xor bx, bx ; mov bx, 0 to clear the register +.static_loop: + call rand + and ax, 3fh ; last six bits of eax (see rand) + mov [es:bx], al ; [] -> bx offset and default segment ds we change it to es + inc bx + cmp bx, 64000 ; num pixels + jnz .static_loop + + ; draw lovebug + mov di, (200 - 32) * 320 + 160 - 16 + mov ax, [num_frames] + mov bx, ax + shl ax, 8 + shl bx, 6 + add ax, bx + sub di, ax + call rand + and ax, 3 ; random value in 0, 15 + sub ax, 1 ; random value in -3, 12 + add di, ax + mov si, lovebug + call blit32 + +; wait for vblank +.vsync: + mov dx, 3dah + in al, dx + and al, 8 ; the 4th bit is 1 when we are in the vertical blanking period + jnz .vsync + +; copy backbuffer to video memory + push es + push ds + mov ax, es + mov ds, ax ; ds points to backbuffer now (was in es) + xor si, si + mov ax, 0a000h + mov es, ax + xor di, di ; write in es:di + mov ecx, 16000 ; 16000 double words (dwords) = 64000 bytes + rep movsd + pop ds + pop es + + inc word [num_frames] + cmp word [num_frames], 200 - 32 + jz .end + + in al, 64h ; 60h = keyb data port, 64h = keyb status port + and al, 1 ; 1 = OUTBUF_FULL = the keyb controller out buf is full + jz main_loop ; no key pressed, loop back + in al, 60h ; reads the keyb that was pressed to reset the flag + +.end: +; re-enable all interrupts + sti + +; text mode + mov ax, 3 ; text mode + int 10h +; use bios to print +; Int 10/AH=0Eh + mov si, str_frames + call print_str + mov ax, [num_frames] + call print_num + mov si, str_newline + call print_str .inf_loop: jmp .inf_loop + +; reads from ds:si writes to es:di (bug top left corner) +; knows how many pixels on screen and how many in the lovebug +blit32: + mov cx, 1024 ; 32 x 32 lovebug +.loop: + mov al, [ds:si] + cmp al, 64 + jz .skip_pixel + mov [es:di], al +.skip_pixel: + inc si + inc di + + dec cx ; dec the num_pixels we want to write + jz .end ; all pixels have been written + test cx, 1fh ; keep 5 least significant bits, 3 most significant bits 0 + jnz .loop ; when this is 0 we are in a multiple of 32 + add di, 320 - 32 ; screen width - bug width + jmp .loop +.end: + ret + +print_str: + ;Int 10/AH=0Eh + mov al, [si] + test al, al + jz .end + mov ah, 0eh + xor bx, bx + int 10h + inc si + jmp print_str +.end: + ret + +print_num: + ; converts digits to ascii - print + push word 0 + test ax, ax + jnz .conv_loop + push word '0' + jmp .conv_end +.conv_loop: + test ax, ax + jz .conv_end + xor dx, dx + mov cx, 10 + div cx ; ax contains cx / 10 + add dl, '0' + push dx + jmp .conv_loop +.conv_end: + mov bp, sp + mov ax, [ss:bp] + test ax, ax + jz .print_end + mov ah, 0eh + xor bx, bx + int 10h + add sp, 2 + jmp .conv_end +.print_end: + add sp, 2 + ret + +; random number generator +; by nuclear +rand: + mov eax, [randval] + mul dword [randmul] + add eax, 12345 + and eax, 0x7fffffff + mov [randval], eax + shr eax, 16 + ret + +randmul dd 1103515245 +randval dd 0ace1h + +num_frames dw 0 +str_frames db 'frames: ', 0 +str_newline db 13, 10, 0 ; crlf carriage return line feed newline + +; db to write pixels transparent 255 +; @: transparent +; A: black +; B: gray +; C: dark red +; D: medium red +; E: red +lovebug: + db '@@@@BAAAB@@@@@BAAB@@@@@BAAAB@@@@' + db '@@@@@@@@AAAB@BAAAAB@BAAA@@@@@@@@' + db '@@@@@@@@@@@AAAAAAAAAA@@@@@@@@@@@' + db '@@@@@@@@@@@@AAAAAAAA@@@@@@@@@@@@' + db '@@@@@@@@@@@@AAAAAAAA@@@@@@@@@@@@' + db '@@@@@@@@@@@@BAAAAAAB@@@@@@@@@@@@' + db '@@@@@@@@@@@@@AAACAA@@@@@@@@@@@@@' + db '@@@@@@@@@@CDDEECDEEDDC@@@@@@@@@@' + db '@@@@@@@CDDEEEEEDCEEEEEDDC@@@@@@@' + db '@@@@@CDEEEEDCDECDEDCDEEEEDC@@@@@' + db '@@@@CDDCDEECACEDCECACEEDCDDC@@@@' + db '@@@CDECACEEDCDECDEDCDEECACEDC@@@' + db '@@@DEEDCDEEEEEEDCEEEEEEDCDEED@@@' + db '@@CEEEEEEEEEEEDCDDEEEEEEEEEEEC@@' + db '@@DEDCDEEEDCDECACCEDCDEEEDCDED@@' + db '@@EECACEEECACEDCDDECACEEECACEE@@' + db '@CEEDCDEEEDCDEEDCEEDCDEEEDCDEEC@' + db '@DEEEEEEEEEEEEDCCDEEEEEEEEEEEED@' + db 'CEEEEEEDCDEEEDCBACDEEEDCDEEEEEEC' + db 'CEDCDEECACEEDCAABACDEECACEEDCDEC' + db 'DECACEEDCDEDCAABAAACDEDCDEECACED' + db 'DEDCDEEEEEDCAAAABAAACDEEEEEDCDED' + db 'CEEEEEEEEECAAAABAAAAACEEEEEEEEEC' + db 'CEEEEEEEEDAAAAAABAAAAADEEEEEEEEC' + db '@DEDCDEEDCAAAAABAAAAAACDEEDCDED@' + db '@DECACEDCAAAAAAABAAAAAACDECACED@' + db '@DEDCDDCAAAAAAABAAAAAAAACDDCDED@' + db '@CEEEECAAAAAAAAABAAAAAAAACEEEEC@' + db '@@EEED@AAAAAAAABAAAAAAAAA@DEEE@@' + db '@@EEDC@@AAAAAAAABAAAAAAA@@CDEE@@' + db '@@DEC@@@@@AAAAABAAAAAA@@@@@CED@@' + db '@@@C@@@@@@@@AAAABAAA@@@@@@@@C@@@' + + align 16 ; if the address is not a multiple of 16 add some 0 to become one (because we'll use backbuffer as a segment) +backbuffer: