-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain-bootsect.asm
413 lines (349 loc) · 15.8 KB
/
main-bootsect.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
org 7c00h
cpu 386
use16
UP_ARROW equ 075h ; UP KEY SCAN CODE
DOWN_ARROW equ 072h ; DOWN KEY
LEFT_ARROW equ 06Bh ; LEFT KEY
RIGHT_ARROW equ 074h ; RIGHT KEY
SLIDE_LEFT equ 06Ch ; HOME KEY
SLIDE_RIGHT equ 069h ; END KEY
HORZ_CENTER equ 160 ; center of screen, horizontal
VERT_CENTER equ 100 ; vertical
STACK_SIZE equ 4096 ; 4K of stack (after BSS section) should be enough
main:
cld ; clear direction flag, as we can't assume anything
mov ax, 0A000h
mov es, ax ; set ES to video segment
xor ax, ax
; cli ; surrounding CLI/STI would be needed for some early 8088 processors
mov ss, ax ; since we targeting 80386 anyway, they're turned off to save space
mov sp, end_all+STACK_SIZE ; see https://stackoverflow.com/questions/32701854/boot-loader-doesnt-jump-to-kernel-code/
; sti
mov ds, ax ; ES,SS,DS set, CS could be 0x0000 or 0x07c0 or anything else, doesn't matter since we don't use jump tables
mov ax, 13h
int 10h ; VGA Mode 13h set
fld dword [plyangle] ;
fsincos ; [ cos(plyangle), sin(plyangle) ]
fld dword [plycoords] ;
fld dword [plycoords+4] ; [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
jmp projector ; at the very first time, having set up preconditions for projector, jump there straight
; to have our first screen layout before any key need to be pressed
keyPress:
xor ah, ah
int 16h ; AH=0: pause and get keypress
lea bp, [plyangle] ; BP=[plyangle], BP+4=[plycoords], BP+8=[plycoords+4] from now
cmp ah, UP_ARROW
je keyPress_forward
; cmp ah, DOWN_ARROW
; je keyPress_backward
cmp ah, LEFT_ARROW
je keyPress_turnLeftRight
cmp ah, RIGHT_ARROW
je keyPress_turnLeftRight
; cmp ah, SLIDE_LEFT ; SLIDING: switched off feature -- doesn't fit in 512 bytes
; je keyPress_slideLeft
; cmp ah, SLIDE_RIGHT
; je keyPress_slideRight
jmp keyPress
keyPress_forward:
fadd st3 ; [ ply.y+sin(plyangle), ply.x, cos(plyangle), sin(plyangle) ]
fstp dword [bp+8] ; update ply.y [ ply.x, cos(plyangle), sin(plyangle) ]
fadd st1 ; [ ply.x+cos(plyangle), cos(plyangle), sin(plyangle) ]
fst dword [bp+4] ; update ply.x [ ply.x+cos(plyangle), cos(plyangle), sin(plyangle) ]
fld dword [bp+8] ; reload ply.y [ ply.y+sin(plyangle), ply.x+cos(plyangle), cos(plyangle), sin(plyangle) ]
; using updated variables: [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
jmp projector
;keyPress_backward: ; GOING BACKWARDS: switched off feature -- doesn't fit in 512 bytes
; fsub st3 ; [ ply.y-sin(plyangle), ply.x, cos(plyangle), sin(plyangle) ]
; fstp dword [bp+8] ; update ply.y [ ply.x, cos(plyangle), sin(plyangle) ]
; fsub st1 ; [ ply.x-cos(plyangle), cos(plyangle), sin(plyangle) ]
; fst dword [bp+4] ; update ply.x [ ply.x-cos(plyangle), cos(plyangle), sin(plyangle) ]
; fld dword [bp+8] ; reload ply.y [ ply.y-sin(plyangle), ply.x-cos(plyangle), cos(plyangle), sin(plyangle) ]
; using updated variables: [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; jmp projector
;keyPress_slideLeft: ; SLIDING: switched off feature -- doesn't fit in 512 bytes
; fsub st2 ; [ ply.y-cos(plyangle), ply.x, cos(plyangle), sin(plyangle) ]
; fstp dword [bp+8] ; update ply.y [ ply.x, cos(plyangle), sin(plyangle) ]
; fadd st2 ; [ ply.x+sin(plyangle), cos(plyangle), sin(plyangle) ]
; fst dword [bp+4] ; update ply.x [ ply.x+sin(plyangle), cos(plyangle), sin(plyangle) ]
; fld dword [bp+8] ; reload ply.y [ ply.y-cos(plyangle), ply.x+sin(plyangle), cos(plyangle), sin(plyangle) ]
; ; using updated variables: [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; jmp projector
;
;keyPress_slideRight:
; fadd st2 ; [ ply.y+cos(plyangle), ply.x, cos(plyangle), sin(plyangle) ]
; fstp dword [bp+8] ; update ply.y [ ply.x, cos(plyangle), sin(plyangle) ]
; fsub st2 ; [ ply.x-sin(plyangle), cos(plyangle), sin(plyangle) ]
; fst dword [bp+4] ; update ply.x [ ply.x-sin(plyangle), cos(plyangle), sin(plyangle) ]
; fld dword [bp+8] ; reload ply.y [ ply.y+cos(plyangle), ply.x-sin(plyangle), cos(plyangle), sin(plyangle) ]
; ; using updated variables: [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; jmp projector
keyPress_turnLeftRight:
finit ; EMPTY []
fld dword [bp] ; [ plyangle ]
fld dword [plyangleDelta] ; [ plyagnleDelta, plyangle ]
cmp ah, RIGHT_ARROW ; check if this is positive direction
je keyPress_turnSkipNeg ; if so, skip negation
fchs
keyPress_turnSkipNeg: ; [ +-plyagnleDelta, plyangle ]
fadd ; [ plyangle+-plyagnleDelta ]
fst dword [bp] ; update plyangle [ plyangle+-plyagnleDelta ]
fsincos ; [ cos(plyangle+-plyagnleDelta), sin(plyangle+-plyagnleDelta) ]
; using updated variables: [ cos(plyangle), sin(plyangle) ]
fld dword [bp+4] ;
fld dword [bp+8] ; [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
projector:
mov cx, 320*200/2 ; clearScreen, fill whole video memory area w/ zeros (A000:0000-A000:FA00h, stack moved somewhere else)
xor ax, ax
xor di, di
rep stosw
; FPU STACK: ; [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
lea si, [polygon] ;
mov cx, POLYGONSIZE
calcOneSide:
lea di, [tx1] ; set to ....1 variableset
mov [plotxy_color], cl ; set color of current side
push cx ; save cx for outer loop
mov cl, 2 ; two vertices at a time -- setting CL is enough assuming that POLYGONSIZE will be < 256 at all times
calcOneVertex:
fild word [si] ; [ pgn[i].x, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fsub st2 ; [ pgn[i].x-ply.x, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fild word [si+2] ; [ pgn[i].y, pgn[i].x-ply.x, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fsub st2 ; [ pgn[i].y-ply.y, pgn[i].x-ply.x, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; ------ty------ ------tx------
fld st1 ; [ tx, ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul st5 ; [ tx*cos(angle), ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fld st1 ; [ ty, tx*cos(angle), ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul st7 ; FULL [ ty*sin(angle), tx*cos(angle), ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fadd ; [ tx*cos(angle)+ty*sin(angle), ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; di+4 = tz1 or 2
fstp dword [di+4] ; [ ty, tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul st4 ; [ ty*cos(plyangle), tx, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fxch st1 ; [ tx, ty*cos(plyangle), ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul st5 ; [ tx*sin(plyangle), ty*cos(plyangle), ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fsub ; [ tx*sin(plyangle)-ty*cos(plyangle), ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; di = tx1/2
fstp dword [di] ; [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fld dword [di+4] ; di+4 = tz1/2, di = tx1/2
fild word [zoomTimesAspect]
fld dword [di] ; [ tx1, zoomTimesAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fchs ; [ -tx1, zoomTimesAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul ; [ -tx1*zoomTimesAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fdiv st1 ; [ -tx1*zoomTimesAspect/tz1, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; di+8 = x1/2
fistp word [di+8] ; [ tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fild word [zoomWOAspect] ;
fild word [wallHeight] ; [ wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fld st0 ; FULL [ wallHeight, wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fchs ; FULL [ -wallHeight, wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul st2 ; FULL [ -wallHeight*zoomWOAspect, wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fdiv st3 ; FULL [ -wallHeight*zoomWOAspect/tz1, wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; di+10 = y1top/y2top, di+12 = y1bot/y2bot
fistp word [di+10] ; [ wallHeight, zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fmul ; [ wallHeight*zoomWOAspect, tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fdiv ; [ wallHeight*zoomWOAspect/tz1, ply.y, ply.x, cos(plyangle), sin(plyangle) ]
fistp word [di+12] ; [ ply.y, ply.x, cos(plyangle), sin(plyangle) ]
; FPU stack ready for next iteration
add si, POLYGONENTRY ; move to next vertex
add di, TEMPVARSIZE ; move to ...2 variableset
loop calcOneVertex
call drawOneSide ; draw side defined by x1,y1top/y1bot,x2,y2top/y2bot
pop cx
sub si, POLYGONENTRY ; two steps forward minus one step back = one step fwd
loop calcOneSide
jmp keyPress ; infinite loop - no return from main
drawOneSide:
mov si, HORZ_CENTER ; preparing to draw side defined by x1,y1top/y1bot,x2,y2top/y2bot
mov cx, si
mov di, VERT_CENTER
mov dx, di
pusha ; pusha instead of individual push's, stack memory is cheaper than instruction space
; +1 saves si,di,cx,dx at HCENTER,VCENTER,HCENTER,VCENTER
add si, [x1]
add cx, [x2]
pusha ; +2 saves si,di,cx,dx at HCENTER+x1,VCENTER,HCENTER+x2,VCENTER
add di, [y1top]
add dx, [y2top]
call lineDraw ; TOP edge: (HCENTER+x1,VCENTER+y1top)->(HCENTER+x2,VCENTER+y2top)
popa ; +1 restores HCENTER+x1,VCENTER,HCENTER+x2,VCENTER
add di, [y1bot]
add dx, [y2bot]
call lineDraw ; BOTTOM edge: (HCENTER+x1,VCENTER+y1bot)->(HCENTER+x2,VCENTER+y2bot)
popa ; 0 restores HCENTER,VCENTER,HCENTER,VCENTER
pusha ; +1 saves HCENTER,VCENTER,HCENTER,VCENTER
add si, [x1]
add di, [y1top]
mov cx, si
add dx, [y1bot]
call lineDraw ; LEFT edge: (HCENTER+x1,VCENTER+y1top)->(HCENTER+x1,VCENTER+y1bot)
popa ; 0 restores HCENTER,VCENTER,HCENTER,VCENTER
add si, [x2]
add di, [y2top]
mov cx, si
add dx, [y2bot]
call lineDraw ; RIGHT edge: (HCENTER+x2,VCENTER+y2top)->(HCENTER+x2,VCENTER+y2bot)
ret ; return from drawOneSide
plotxy: ; puts pixel into (si,di) of color plotxy_color
; assumes: es=video seg
push di
push ax
shl di, 6 ; mul di, 320
mov ax, di ; ax=di=y * 64
shl ax, 2 ; ax=y * 256
add di, ax ; di=y*(64+256)=320
add di, si ; di=y*320+x
mov al, [plotxy_color]
stosb
pop ax
pop di
ret ; return from plotxy, all registers preserved
; lineDraw octants, e.g. octant1 is when (fromx < tox, fromy < toy, and the line is more horizontal then vertical, i.e. |tox-fromx| > |toy-fromy|
; octant2
; \ | /
; \ | /
; \|/ octant1
; ---|---
; /|\ octant8
; / | \
; / | \
lineDraw: ; draws line from (si,di) to (cx,dx) with color plotxy_color
; lineDraw_part1: this part here checks whether |tox-fromx|<=>|toy-fromy| and sets dh so (0 iff "horizontal dominant",
; 1 iff "vertical dominant"), then swaps source and destination points if dominant axis coords are not
; in order, (e.g. if |tox < fromx| >= |toy-fromy| (horiz. dom.) and tox < fromx, (cx, dx) <-> (si, di)),
; futhermore sets whether the other (submissive) axis will be increasing (1) or decreasing (-1) after all that
; AH: 0 iff horiz dominant, 1 iff vert; AL: +1 or -1 submissive direction inc/dec
mov bp, dx ; BP will be |toy-fromy| later, first step isolated to save space
mov bx, cx
sub bx, si ; BX = tox-fromx
jge XinOrder
neg bx ; BX = |tox-fromx|
sub bp, di ; was BP=toy already, BP = toy-fromy now
jge XnotInOrder_YinOrder
neg bp ; BP = |toy-fromy|
; case 1: X not in order, Y not in order, swapping will be inevitable
cmp bx, bp
setc ah ; CPU80386 AH=0 iff dominant direction is horizontal
mov al, 1 ; AL=1: having swapped source<->dest, submissive direction will be increasing
xchg cx, si ; if X dom, swap source <-> destination
xchg dx, di
jmp lineDraw_part2
XnotInOrder_YinOrder:
; case 2: X not in order, but Y is, swapping will be necessary iif X is dominant
mov ax, 0x01FF ; Y dominant case will be default: AH=1, AL=-1, no src<->dst swapping
cmp bx, bp
jc lineDraw_part2 ; if Y dominant, leave the defaults
xchg cx, si ; if X dom, swap source <-> destination
xchg dx, di
dec ah ; AH=0 as X is dominant (submissive Y will be in wrong order after swap, so AL should stay -1)
jmp lineDraw_part2
XinOrder:
sub bp, di ; was BP=toy already, BP = toy-fromy now
jge XinOrder_YinOrder
neg bp ; BP = |toy-fromy|
; case 3: X is in order, Y isn't, swapping wil be necessary iif Y is dominant
mov ax, 0x00FF ; X dom. will be default: AH=0, AL=-1, no src<->dst swapping
cmp bx, bp
jnc lineDraw_part2 ; X dominant: leave the defaults
xchg cx, si ; Y dominant: swap source <-> destination
xchg dx, di
inc ah ; AH=1 as Y is dominant (submissive X will be in wrong order after swap, so AL should stay -1)
jmp lineDraw_part2
XinOrder_YinOrder:
; case 4: both X and Y are in order, no swapping will take place
cmp bx, bp
setc ah
mov al, 1
lineDraw_part2:
; lineDraw_part2: this is the actual drawing part; preconditions:
; - all input arguments intact yet (CX, DX, SI, DI)
; - BP = |toy-fromy| =: deltay, BX = |tox-fromx| =: deltax
; - AH = 0 iif horiz dominant, 1 iff vert dominant
; - AL = 1 iff submissive direction should increase, -1 iff it should decrease
test ah, ah
jnz lineDraw_part2vert
; lineDraw_part2/horizontal_dominant
movsx dx, al ; CPU80386//DX will be used to hold the step in submissive (Y) direction
shl bp, 1 ; BP = 2*deltay
mov ax, bp
sub ax, bx ; AX = 2*deltay - deltax
shl bx, 1 ; BX = 2*deltax
lineDrawMainLoop_horzdom:
call plotxy ; draw (SI,DI), color plotxy_color
cmp ax,0 ; check if error reached threshold
jle skipYincNow ; if no, line won't step into submissive direction
add di, dx ; increment/decrement current y coord if needed (delta = DX)
sub ax, bx ; error -= 2*deltax
skipYincNow:
add ax, bp ; error += 2*deltay
inc si ; increment current x coord
cmp si, cx ; have we reached tox?
jle lineDrawMainLoop_horzdom
lineDraw_part2vert:
; lineDraw_part2/vertical_dominant
movsx cx, al ; CPU80386//CX will be used to hold the step in submissive (X) direction
shl bx, 1 ; BX = 2*deltax
mov ax, bx
sub ax, bp ; AX = 2*deltax - deltay
shl bp, 1 ; BP = 2*deltay
lineDrawMainLoop_vertdom:
call plotxy ; draw (SI,DI), color plotxy_color
cmp ax,0 ; check if error reached threshold
jle skipXincNow ; if no, line won't step into submissive direction
add si, cx ; increment/decrement current x coord if needed (delta = CX)
sub ax, bp ; error -= 2*deltay
skipXincNow:
add ax, bx ; error += 2*deltax
inc di ; increment current y coord
cmp di, dx ; have we reached toy?
jle lineDrawMainLoop_horzdom
ret ; return from lineDraw, no registers preserved
; start of static/const variables section
plyangleDelta:
dd 0.01
polygon:
dw 0, 1
dw 2, 3
dw 4, 5
dw 6, 7
dw 8, 9
dw 0, 1
POLYGONENTRY equ (2 * 2)
POLYGONSIZE equ (($-polygon)/POLYGONENTRY) - 1
zoomTimesAspect:
dw 160 ; aspect ratio * zoom value = 320/200 * 100, factor of X coords
zoomWOAspect:
dw 100 ; zoom value (alone), factor of Y coords
wallHeight:
dw 50
plyangle: ; plycoords must follow plyangle immediately for bp-based addressing in ... to work
dd 0
plycoords:
dd 0,0
bootable_sector_signal:
db 0x55, 0xaa ; warning! not in the right place yet (should be at 511th and 512th position)
end_of_data:
; start of uninitialized variables section (BSS)
plotxy_color: resb 1 ; color of the pixel drawn in plotxy
tx1: resd 1
tz1: resd 1
x1: resw 1
y1top: resw 1
y1bot: resw 1
TEMPVARSIZE equ ($-tx1)
tx2: resd 1
tz2: resd 1
x2: resw 1
y2top: resw 1
y2bot: resw 1
end_all: nop ; end of all valuable code/data, stack area will be STACK_SIZE bytes starting from here
; stats (updated)
; plotxy 139h-14eh (21)
; lineDraw 14eh-1d7h (137)
; consts 1d7h-205h (46)
; main 000h-024h (36)
; main/keyPress 024h-06ah (70)
; projector 06dh-0e8h (123)
; drawOneSide 0e8h-139h (81)
; BSS 205h-222h (29)
; bootable signal (2)
; total 516 bytes + 29 bytes BSS