d9d1fe61dec99dfbc3cabc76949ab51c8ab86ae8
[bootboot] / bb.asm
1 ; org: all instructions from now on start in 7c00h
2 ; 7c00h is where the bios loads the 1st sector
3 ; assembler formatting:
4 ; column 0: labels
5 ; tab: commands
6         org 7c00h
7 ; at boot: real mode (like it's 8086)
8 ; we have to tell assembler that code is 16bit mode
9         bits 16
10
11 start:
12         mov sp, 7c00h
13
14 ; initialize segment registers
15         mov ax, 0
16         mov ds, ax
17         mov es, ax
18         mov ss, ax
19
20 ; save dl value
21 ; bios sets in dl the num of the drive that
22 ; loaded you so if you overwrite dl you can reuse it
23         mov [saved_drive_num], dl
24
25 ; service 0: set videomode ah
26 ; param: which video mode (13h: 320x200, 256 colors) al
27 ; ax: ah (high 8 bits), al (low)
28 ; call 0 = set_videomode it expects the video mode in al
29 ; ah : 0, al: 13, ax:ahal
30         mov ax, 13h
31
32 ; calling video bios
33 ; software interrupt 10h
34 ; what's the value of ah? al=video mode when ah=0
35 ; which set which video mode
36         int 10h
37         mov ax, 3
38         call clearscreen
39
40 ; load 2nd sector from boot device and jump to it
41 ; bios helpers, 13h = disk io
42         mov ax, 0
43         mov ds, ax
44         mov ah, 02h                     ; call 2: read sectors into memory
45         mov al, 1                               ; number of sectors to read
46         mov ch, 0                               ; low 8 bits of cylinder number
47         mov cl, 2                               ; sector number that starts from 1
48         mov dh, 0                               ; head number
49         mov dl, [saved_drive_num]       ; 8bits
50         mov bx, sector_2
51         int 13h
52 ; error check: if carry flag isn't set jump to loaded code
53         jnc     sector_2
54 .inf_loop:
55         jmp .inf_loop
56
57
58 clearscreen:
59 ; video ram is mapped in a0000
60 ; first 64000 bytes appear immediately on screen
61 ; mem addresses in real mode have 2 parts: segment and offset
62 ; bits overlap: segment is shifted by 4 and is added to the
63 ; overlapping offset (20 bits number = x86's addressable space = 1MB)
64 ; segment register for the segment: es, ds, cs, ss (and: fs, gs)
65 ; default register = ds (data segment), es = extra segment
66 ; cs = code segment cs:ip (it points where to read instructions and is
67 ; automatically set to 7c0 (7c00h)
68 ; offset can be paired with any register
69 ; pair the registers
70         push ax
71         mov ax, 0a000h
72         mov ds, ax
73         mov di, 0
74         pop ax
75 ; counter cx
76         mov cx, 64000
77
78 .loop_begin:
79 ; dereferrence[] address
80         mov [di], al
81         inc     di
82         dec cx
83 ; when cx is 0, 0 flag is set
84         jnz .loop_begin
85         ret
86
87 saved_drive_num:
88         db 0 ; define byte 0
89
90 ; assembler trick: write as many 0 needed to fill 510 bytes
91 ; $ <- means here
92         times 510-($-$$) db 0
93         dw 0aa55h
94
95 sector_2:
96 ; disp palette
97         mov ax, 0a000h  ; video segment points to video memory
98         mov ds, ax
99         mov bx, 0               ; video offset
100         mov cx, 0               ; y
101 .y_loop:
102         mov dx, 0               ; x
103 .x_loop:
104         mov ax, dx
105         test ax, 0ff00h ; lower 8 bits 0, highest 1, Z flag is set while < 256, test = and but doesnt change ax 
106         jz      .skip_clear_ax
107         mov al, 0
108 .skip_clear_ax:
109         mov [bx], al    ; pixel written on screen
110         inc bx                  ; increment
111         inc dx
112         cmp dx, 320
113         jnz .x_loop
114         inc cx
115         cmp cx, 200
116         jnz .y_loop
117
118 ; setup grayscale palette (64 first colors because ramdac uses 6 bits / color so 2^6)
119 ; ram dac (digital to analog converter) tis vga
120 ; in a ^ register which index we want to write
121 ; 3 writes in another ramdac register (data)
122 ; ramdac feature: when you need to set a palette
123         mov al, 0               ; first index
124         mov dx, 3c8h    ; ramdac index registe
125         out dx, al              ; because io port (address) > 255
126         inc dx                  ; ramdac data register: 3c9h
127 .pal_loop:
128         out dx, al              ; r
129         out dx, al              ; g
130         out dx, al              ; b
131         inc al
132         test al, 3fh    ; test with 3fh to keep the lowest 6 bits of al
133         jnz .pal_loop
134
135 ; disable all interrupts (for bios to not read the keyboard)
136         cli
137
138 main_loop:
139         mov ax, 0a000h
140         mov ds, ax
141         xor bx, bx              ; mov bx, 0 to clear the register
142 .static_loop:
143         call rand
144         and ax, 3fh             ; last six bits of eax (see rand)
145         mov [bx], al
146         inc bx
147         cmp bx, 64000   ; num pixels
148         jnz .static_loop
149
150         in al, 64h              ; 60h = keyb data port, 64h = keyb status port
151         and al, 1               ; 1 = OUTBUF_FULL = the keyb controller out buf is full
152         jz main_loop    ; no key pressed, loop back
153         in al, 60h              ; reads the keyb that was pressed to reset the flag
154
155 ; re-enable all interrupts
156         sti
157
158 .inf_loop:
159         jmp .inf_loop
160
161 ; random number generator
162 ; by nuclear
163 rand:
164         mov eax, [randval]
165         mul dword [randmul]
166         add eax, 12345
167         and eax, 0x7fffffff
168         mov [randval], eax
169         shr eax, 16
170         ret
171
172 randmul dd 1103515245
173 randval dd 0ace1h