Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- %define BOCHS_HD_IMAGE ;define this when booting in Bochs as a hard drive image
- %define CONSOLE_WIDTH 0x4E
- %define RTC_DIVIDER 0xF
- %define PADDLE_WIDTH 0x08
- %define PADDLE_SPEED 0x2
- BITS 16 ;we are running in real mode, so 16 bit only
- [org 0x7C00] ;set origin address to 0x7C00. This is where BIOS drops us off in RAM
- boot:
- cli ;halt interrupts
- xor ax, ax
- mov ds, ax ;set data segment register
- mov gs, ax ;set general-use segment register
- mov ax, 0B800h
- mov es, ax ;VGA color text data segment
- mov ax, 07E0h
- mov ss, ax ;set stack segment register
- mov bp, ax ;set stack base pointer. bottom of stack
- mov sp, 9C00h ;set stack pointer. top of stack
- mov ax, word int70h_handler ;setup 70h interrupt for RTC timer
- mov [gs:70h*4], ax ;set interrupt offset
- mov [gs:70h*4+2], ds ;set interrupt segment
- mov ax, word int09h_handler ;setup 09h for keyboard
- mov [gs:09h*4], ax ;set interrupt offset
- mov [gs:09h*4+2], ds ;set interrupt segment
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Init Routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- init:
- ;fill with border chars
- mov ax, 0x0FFE ;set ax to bg color
- xor di, di ;clear di ;consider for space
- mov cx, 80 * 25 ;set cx to size of console screen
- rep stosw ;write ax to video memory cx times. mov [es:di++], ax
- mov bx, 0x1901
- xor ax, ax
- call fill_area
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Draw Bricks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- mov bx, 0x0501 ;start at row 1, col 1
- mov ax, 0x03B2 ;char and attr to write
- call fill_area
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; RTC Init ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- mov al, 8Bh ;select reg B, disable NMI
- out 70h, al
- in al, 71h ;read B
- or al, 40h ;OR 0x40 to set flag for start
- push ax
- mov ax, 8Bh ;select B
- out 70h, al
- pop ax
- out 71h, al ;set B register to start
- mov al, 8Ah ;select reg A and disable NMI
- out 70h, al
- in al, 71h ;read reg A value
- and al, 11110000b ;keep top nibble received
- or al, RTC_DIVIDER ;OR in divider in low nibble
- push ax
- mov al, 8Ah
- out 70h, al ;select A
- pop ax
- out 71h, al ;write value to A
- in al, 0A1h ;clear PIC 2 mask to ensure that IRQ 8 fires
- xor al, al
- out 0A1h, al
- sti
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- jmp main_loop
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- fill_area:
- .iter:
- mov cx, CONSOLE_WIDTH ;brick row counter
- call vga_get_char_offset ;get video offset
- rep stosw ;write cx num bricks
- dec bh
- cmp bh, 0 ;loop
- jnz .iter
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Update Frame ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- update_frame:
- mov al, byte [paddle_x] ;load paddle offsets
- add al, byte [paddle_vec] ;add vector
- cmp al, 1 ;test against left side
- jge .testpaddlehigh ;bigger then test right side
- mov al, 1 ;clip to 1
- jmp .storepaddlex ;store it
- .testpaddlehigh:
- cmp al, CONSOLE_WIDTH - PADDLE_WIDTH - 1;compare adjusted values for right edge
- jle .storepaddlex ;nope just store it
- mov al, CONSOLE_WIDTH - PADDLE_WIDTH - 1;clip to right side
- .storepaddlex:
- mov byte [paddle_x], al ;store the new x value
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- .checkballycollision:
- mov bx, word [ball_x] ;load x,y at once
- push bx ;save old position for later
- add bh, byte [ball_vecy] ;add y pos + y vec
- call vga_get_char_offset ;get video mem offset
- mov ax, word [es:di] ;get char from memory offset
- cmp al, 0 ;check if the cell is empty
- je .storebally ;if it is, move there
- neg byte [ball_vecy] ;if not, reverse direction
- ;this would be simpler with a paddle made of 1 char
- cmp al, 205 ;check for paddle left side char
- jz .paddlecollide ;if we hit, handle the collision
- cmp al, 213 ;paddle middle char
- jz .paddlecollide ;...
- cmp al, 184 ;paddle right side char
- jnz .ybrickcollision ;inverse test, if we hit just fall through
- .paddlecollide:
- mov dl, byte [ball_vecx] ;load ball x vec
- cmp byte [paddle_vec], 0 ;check direction of paddle
- jl .pvecn ;moving left ?
- jg .pvec ;moving right ?
- jmp .checkballxcollision ;no movement (only possible at start)
- .pvecn: ;there's got to be a better way handling this
- dec dl ;we are negative so decrement ball vec
- cmp dl, -1 ;clip it to -1
- jg .donepaddle ;if greater, finish and store
- mov dl, -1 ;if not, set to -1
- jmp .donepaddle ;store it
- .pvec: ;paddle is positive
- inc dl ;increment ball vec
- cmp dl, 1 ;clipping to 1 this time
- jl .donepaddle ;...
- mov dl, 1 ;...
- .donepaddle:
- mov byte [ball_vecx], dl ;store new vector
- jmp .checkballxcollision ;we hit something and reversed so just go on to check x direction
- .ybrickcollision:
- call brick_collider ;we possibly hit a brick so check and handle accordingly
- jmp .checkballxcollision ;move on
- .storebally:
- mov byte [ball_y], bh ;cell was empty so we store the new y position
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- .checkballxcollision:
- pop bx ;restore old ball x,y in case it changed above
- push bx ;push it back onto the stack for later
- cmp byte [ball_vecx], 0 ;if we have no x vector we can't hit anything
- jz .skiptodraw ;no vec, just go draw
- add bl, byte [ball_vecx] ;add vector to x pos
- call vga_get_char_offset ;get new video offset
- mov ax, [es:di] ;retrieve char there
- cmp al, 0 ;is it empty?
- je .storeballx ;if it is, move there
- neg byte [ball_vecx] ;nope, reverse direction
- .xbrickcollision:
- call brick_collider ;we can only hit bricks on this axis, so handle if we did
- jmp .skiptodraw ;no store, just draw
- .storeballx:
- mov byte [ball_x], bl ;we hit nothing and had a vector, so store
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Clear Scr ;;;
- .skiptodraw:
- xor ax, ax ;clear paddle row for redraw
- mov bx, 0x1701 ;row 23, col 1
- mov cl, CONSOLE_WIDTH ;clear row
- call vga_get_char_offset
- rep stosw ;write blank chars to row
- pop bx ;retrieve our original ball x,y
- call vga_get_char_offset
- mov [es:di], ax ;clear
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Draw Ball ;;;
- mov bx, word [ball_x] ;get new ball x,y
- mov ax, 0x0D07 ;ball char
- call vga_get_char_offset
- mov [es:di], ax ;write it
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Draw Paddle
- mov bx, word [paddle_x] ;read as word to get row offset as well
- mov ax, 0x07D5 ;left side char
- call vga_get_char_offset
- mov [es:di], ax ;write to video mem
- add di, 2 ;increment video pointer
- mov cl, PADDLE_WIDTH
- mov al, 0xCD
- rep stosw ;write middle bars to video mem
- mov al, 0xB8
- mov [es:di], ax ;write right side char
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- .update_end:
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Brick Collider ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- brick_collider: ;bx - bl - x, bh - y, al - char
- cmp al, 178 ;chars 176-178 are brick chars. 178 - solid, 177 - 50%, 176 - 25%
- jle .charlow ;if its less or equal, check low bound
- jmp .skip ;greater, not a brick
- .charlow:
- cmp al, 176 ;check low bound
- jl .skip ;lower, not a brick
- push ax ;ax has our char and attr, save on stack
- xor ax, ax ;clear ax
- mov al, bl ;move ball x into al
- mov dl, 3 ;set dl to 3. bricks are 3 wide. we need to divide ball x by 3 to get a brick offset
- div dl ;do the divide
- test ah, 0x3 ;check remainder. if its zero, we need to adjust or we will hit the brick to the right
- jnz .noadjust ;not zero, dont adjust
- dec al ;decrement so we collide with correct brick
- .noadjust:
- mul dl ;multiply our brick offset by brick size (3)
- mov dl, al ;move offset into dl
- ;this gives us a brick offset that starts with the leftmost char of the brick
- pop ax ;pop our char and attr off stack
- push bx ;push our x/y onto stack so we don't clobber it
- mov bl, dl ;vga_get_char_offset uses bx for x/y so transfer brick x offset to it
- inc bl ;increment position since our bricks start at column 1
- mov cl, 3 ;we need to draw 3 chars
- dec al ;decrement to more damage brick char
- cmp al, 176 ;if we fall below lowest brick char, zero it out, its destroyed
- jge .draw ;nope, not destroyed, just draw
- xor al, al ;zero out char
- .draw:
- call vga_get_char_offset ;get brick mem offset
- rep stosw ;draw
- pop bx ;restore original ball x,y into bx
- .skip:
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- main_loop:
- jmp main_loop
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; VGA Offset ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- vga_get_char_offset: ;bx parm. bl - x, bh - y. ret - offset in di
- push ax ;push ax and dx onto stack
- push dx ;we don't want to clobber them
- xor dx, dx
- mov al, bh ;put y value into al
- mul byte [console_w] ;y * row_width. mul requires register or memory operand
- mov dl, bl ;put x value into dl
- add ax, dx ;add x + y_row offset
- mov di, ax ;move to di for our return value
- shl di, 1 ;offset * 2, chars occupy 2 bytes
- pop dx ;restore ax and dx
- pop ax
- ret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; RTC Timer Handler ;;;;;;;;;;;;;;;;;;;;;;;;;;;
- int70h_handler:
- call update_frame
- mov al, 0Ch ;select reg C
- out 70h, al ;read RTC reg C. We have to do this to keep receiving interrupts
- in al, 71h ;required dummy read. resets to reg D
- mov al, 0x20 ;send EOI to allow interrupts continue
- out 0xa0, al ;this int occurs on the slave PIC 2, so we need to notify it
- out 0x20, al ;notify the master PIC 1, too
- ;this is fudged a bit since it doesn't reset. It'll trigger multiple times per 1 missed
- ;ball count reflects this
- cmp byte [ball_y], 24 ;check if we missed the ball
- jl .done ;nope, we're done
- dec byte [balls_left] ;yep, decrement ball count
- cmp byte [balls_left], 0 ;if we are at 0 we lose
- jnz .done ;nope, we're done
- .check:
- in al, 64h ;out of balls, force reset. Read keyboard controller port
- test al, 02h ;test system flag bit
- jnz .check ;if its not clear, loop
- mov al, 0FEh ;system reset command
- out 64h, al ;send to controller
- .done:
- iret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;; Keyboard handler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- int09h_handler:
- in al, 60h ;read the key pressed
- cmp al, 0x4B ;left arrow key
- jnz .testright ;if not pressed check right key
- mov byte [paddle_vec], -PADDLE_SPEED ;set negative direction vector
- jmp .done
- .testright:
- cmp al, 0x4D ;right arrow key
- jnz .done ;not pressed, exit
- mov byte [paddle_vec], PADDLE_SPEED ;set positive direction vector
- ;;;;;;;;;;;;;;;;;;;;;;;;;;; Stuff we gotta do to make the keyboard interrupt happy
- .done:
- in al, 61h ;get keyboard control line value
- mov ah, al ;save for later
- or al, 80h ;set enable keyboard bit
- out 61h, al ;write to port
- xchg ah, al ;swap control port value into al
- out 61h, al ;write to port
- mov al, 20h ;send EOI to allow interrupts to continue
- out 20h, al
- iret
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- console_w db 80 ;console width
- paddle_x db 36 ;current paddle x
- db 23 ;hack to save 1 byte @ draw_paddle
- paddle_vec db 0 ;paddle movement direction
- ball_x db 40 ;current ball x
- ball_y db 22 ;current ball y
- ball_vecx db 0 ;vector in console chars
- ball_vecy db -1 ;vector in console chars
- block_cnt db 130 ;number of blocks left
- balls_left db 0x20
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
- dw 0xAA55 ; The standard PC boot signature
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- %ifdef BOCHS_HD_IMAGE
- times 1024 * 1024 db 0 ;Bochs HD image padding. Set Cylinders/Sectors/Heads to 3
- %endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement