vga-logic-processor-examples/vga.asm

398 lines
6.7 KiB
NASM

PUBLIC _enableUnchainedVGAMode
PUBLIC _enableTextMode
PUBLIC _fillScreen
PUBLIC _latchCopyCube
PUBLIC _drawColorCube
PUBLIC _writeCube
PUBLIC _keyboardPressed
PUBLIC keyboardHandler_
DISPLAY_MODE_VGA equ 13h
DISPLAY_MODE_TEXT equ 03h
VGA_SEQUENCE_CONTROLLER_INDEX equ 0x3c4
VGA_SEQUENCE_CONTROLLER_DATA equ 0x3c5
VGA_SEQUENCE_CONTROLLER_MEMORY_MODE equ 0x04
VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE equ 0x02
VGA_GRAPHICS_MODE_INDEX equ 0x3CE
VGA_GRAPHICS_MODE equ 0x05
VGA_CRT_CONTROLLER_INDEX equ 0x03d4
VGA_CRT_CONTROLLER_DATA equ 0x03d5
VGA_CRT_CONTROLLER_UNDERLINE_LOC equ 0x14
VGA_CRT_CONTROLLER_MODE_CONTROL equ 0x17
.386
.model flat,c
.DATA
_keyboardPressed db 0
.CODE
keyboardHandler_:
cli
push eax
push ebx
; put scancode into bl
in al, 0x60
mov bl, al
; acknowledge keyboard
in al, 0x61
mov ah, al
or al, 0x80
out 0x61, al
xchg ah, al
out 0x61, al
; a key is pressed if the topmost bit of the scancode is 0
and bl,0x80
jne _keyboardHandler_notKeydown
mov [_keyboardPressed], 1
_keyboardHandler_notKeydown:
; acknowledge interrupt
mov al, 0x20
out 0x20, al
pop ebx
pop eax
sti
; return from the interrupt in a way that preserves the calling stack
iretd
_enableUnchainedVGAMode:
mov ax,0x0013;
int 0x10
mov dx, VGA_SEQUENCE_CONTROLLER_INDEX
mov al, VGA_SEQUENCE_CONTROLLER_MEMORY_MODE
mov ah, 0x06
out dx, ax
mov dx, VGA_CRT_CONTROLLER_INDEX
mov al, VGA_CRT_CONTROLLER_MODE_CONTROL
mov ah, 0xe3
out dx, ax
mov dx, VGA_CRT_CONTROLLER_INDEX
mov al, VGA_CRT_CONTROLLER_UNDERLINE_LOC
mov ah, 0x00
out dx, ax
ret
_enableTextMode:
mov ah,0h
mov al,DISPLAY_MODE_TEXT
int 10h
ret
_fillScreen:
push ebp
mov ebp, esp
; set all bitplanes
mov dx, VGA_SEQUENCE_CONTROLLER_INDEX
mov al, 0x02
mov ah, 0x0f
out dx, ax
push ebx
push ecx
push edx
sub eax,eax
mov al, [ebp+8] ; requested color
; we can write a long at a time and let the bus
; and BIU work out the details. on a 16-bit ISA
; bus with a 16-bit VGA card, this will be faster
; than byte writes
sub edx,edx
add dl,al
shl edx,8
add dl,al
shl edx,8
add dl,al
shl edx,8
add dl,al
; with all planes selected we only need to fill 16000 bytes of data
; and we're filling them four bytes at a time
mov cx, 4000
mov ebx, 0xA0000 ; VGA base address
_fillScreen_loop:
mov DWORD PTR [ebx], edx
add ebx,4
loop _fillScreen_loop
pop edx
pop ecx
pop ebx
mov esp,ebp
pop ebp
ret
_drawColorCube:
push ebp
mov ebp, esp
sub esp, 4 ; y
push ebx
push ecx
push edx
; write to all planes
mov dx, VGA_SEQUENCE_CONTROLLER_INDEX
mov al, VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE
mov ah, 0xf
out dx, ax
; write out host data only
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x03
mov ah, 0x00
out dx, ax
; disable set/reset registers
mov al, 0x00
mov ah, 0x00
out dx, ax
mov al, 0x01
mov ah, 0x00
out dx, ax
mov DWORD PTR [ebp-4], 16 ; y
mov cx,[ebp-4]
; offset is [ebp+8]
mov bh,[ebp+12]; color
_drawColorCube_yLoop:
mov [ebp-4],cx
; put the VGA write offset into eax
mov eax,[ebp-4]
dec eax
mov bl,80
mul bl
add eax,[ebp+8]
add eax,0xa0000
mov cx, 4
_drawColorCube_xLoop:
mov [eax],bh ; write color four bytes at a time
inc eax
loop _drawColorCube_xLoop
mov cx, [ebp-4]
loop _drawColorCube_yLoop
pop edx
pop ecx
pop ebx
mov esp, ebp
pop ebp
ret
_writeCube:
push ebp
mov ebp,esp
; we need a y variable
sub esp,4
push ebx
push ecx
push edx
; [ebp+8] is x offset
; [ebp+12] is data rotate
; [ebp+16] is set/reset
; [ebp+20] is enable set/reset
; enable Logical Operation and host data shifts
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x03
mov ah, [ebp+12]
out dx, ax
; enable set/reset registers
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x00
mov ah, [ebp+16]
out dx, ax
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x01
mov ah, [ebp+20]
out dx, ax
mov DWORD PTR [ebp-4],16
mov cx,[ebp-4]
_writeCube_yLoop:
mov [ebp-4],cx
; determine the offset within VGA memory to write this line to
; and put it in eax
mov eax,[ebp-4]
dec eax
mov bl,80
mul bl
add eax,0xA0000
; 16 pixels across
mov cx,16
_writeCube_xLoop:
push eax
; get the plane to write to in bl
push ecx
dec ecx
and ecx,0x03
mov bl,1
shl bl,cl
pop ecx
; write to one plane
mov dx, VGA_SEQUENCE_CONTROLLER_INDEX
mov al, VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE
mov ah, bl
out dx, ax
; select color to write into bl
mov ax,[ebp-4]
dec ax
mov bl,16
mul bl
add al,cl
mov bl,al
pop eax
push edx
push ecx
; select the correct pixel offset (x / 4) and write the color
dec ecx
shr ecx,2
add ecx,[ebp+8]
mov BYTE PTR [eax+ecx],bl
pop ecx
pop edx
loop _writeCube_xLoop
mov cx,[ebp-4]
loop _writeCube_yLoop
pop edx
pop ecx
pop ebx
mov esp,ebp
pop ebp
ret
_latchCopyCube:
push ebp
mov ebp, esp
; we need a y variable
sub esp,4 ; y
push edx
push ebx
; accept a mode
; accept a mix value
; accept an x offset
; [ebp+8] is x offset
; [ebp+12] is written value
; [ebp+16] is data rotate register
; [ebp+20] is set/reset register
; [ebp+24] is enable set/reset register
; write to all planes
mov dx, VGA_SEQUENCE_CONTROLLER_INDEX
mov al, VGA_SEQUENCE_CONTROLLER_MAP_MASK_MODE
mov ah, 0xf
out dx, ax
; enable Logical Operation and host data shifts
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x03
mov ah, [ebp+16]
out dx, ax
; enable set/reset registers
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x00
mov ah, [ebp+20]
out dx, ax
mov dx, VGA_GRAPHICS_MODE_INDEX
mov al, 0x01
mov ah, [ebp+24]
out dx, ax
mov dh, [ebp+12]
mov DWORD PTR [ebp-4],16 ; y
; read across the cube, should take 4 * 16 reads
mov cx,[ebp-4]
_latchCopyCube_yLoop:
mov [ebp-4],cx ; put y back in loop
mov eax,[ebp-4] ; put y in eax
dec eax ; offset by 1 for loop
; can only multiply in eax by register
mov bl,80
mul bl ; number of lines
add eax,0xa0000 ; vga base address
; keep our index handy
mov ebx, [ebp+8]
; start x loop
mov cx,4
_latchCopyCube_xLoop:
; fill latches via memory read
mov dl, BYTE PTR [eax]
; write blank
mov BYTE PTR [eax+ebx], dh
; increment vga pointer
inc eax
; loop until x is 0
loop _latchCopyCube_xLoop
; restore y for looping
mov cx,[ebp-4]
; loop until y is 0
loop _latchCopyCube_yLoop
_done:
; put things back
pop ebx
pop edx
mov esp,ebp
pop ebp
ret
end