retroforth/experimental/386.s
2018-01-30 21:30:49 +00:00

849 lines
17 KiB
ArmAsm

; ___ ___ _____ ___ ___ __ ____ ___ __
; | _ \ __|_ _| _ \/ _ \ / / |__ /( _ ) / /
; | / _| | | | / (_) | / / |_ \/ _ \/ _ \
; |_|_\___| |_| |_|_\\___/ /_/ |___/\___/\___/
;
; This is the minimal startup & I/O needed to run a basic RETRO
; instance on x86 hardware.
;
; NOTE: NOT COMPLETE OR TESTED YET!
; =============================================================
section .multiboot_header
header_start:
dd 0xe85250d6 ; magic number (multiboot 2)
dd 0 ; architecture 0 (protected mode i386)
dd header_end - header_start ; header length
; checksum
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
; insert optional multiboot tags here
; required end tag
dw 0 ; type
dw 0 ; flags
dd 8 ; size
header_end:
section .text
extern main
global _start
global putchar
global getchar
align 4
_start:
mov dword [0xb8000], 0x2f4b2f4f
jmp main
jmp $
align 4
putchar:
ret
align 4
getchar:
ret
section .text
;---------------------------------------------------------------
; This code is based on the video driver for FTS/Forth. Samuel
; Falvo II has kindly granted permission for me to redistribute
; and modify it without restrictions. Thank you Sam!
;---------------------------------------------------------------
; Current VGA text-mode screen location, along with
; some descriptive attributes
video_base: dd 0xB8000
video_width: dd 80
video_height: dd 25
; Current VGA text-mode color attribute.
; NOTE that it's shifted left by 8 bits, ready for
; logical ORing with a character code.
video_attributes: dd 0x0700
; Current VGA cursor position. Also dictates where
; the next character will be displayed via EMIT or
; TYPE. These probably don't need to be 32-bits wide,
; but it's more convenient for asm coding purposes if
; they are.
video_cursorX: dd 0
video_cursorY: dd 0
; I/O ports for the VGA device in question
video_io: dd 0x3D4
;****** vChangeAttributes *************************************
;
; NAME
; vChangeAttributes
;
; SYNOPSIS
; mov eax,andMask
; mov ebx,xorMask
; call vChangeAttributes
; mov [oldAttributes],eax
;
; FUNCTION
; This function can be used to clear, set, replace, or toggle
; all video attributes flags, depending on the settings of
; EAX and EBX. The attribute flags currently defined are as
; follows:
;
; Bit 0-7: Used to force character code bits to 1.
; Bit 8-11: Foreground color
; Bit 12-14: Background color
; Bit 15: Blink flag
; Bit 16-31: Unused -- leave clear.
;
; Note that for normal text output operation, bits 7-0 must be
; left 0.
;
; INPUTS
; EAX This register contains the AND-mask. This mask is
; applied first. Typically used to "zero out" a sub-field
; to be set via EBX.
;
; EBX This register contains the XOR-mask. This mask is
; applied second.
;
; RESULT
; EAX contains the *former* set of attributes.
;
; NOTE
; To query the current attributes without changing them,
; clear EAX and EBX, like this:
;
; xor eax,eax
; xor ebx,ebx
; call vChangeAttributes
; mov [currentAttributes],eax
;
; BUGS
;
; SEE ALSO
;
;**************************************************************
vChangeAttributes:
xchg eax,[video_attributes]
and [video_attributes],eax
xor [video_attributes],ebx
ret
;****** vRethinkCursor ****************************************
;
; NAME
; vRethinkCursor
;
; SYNOPSIS
; call vRethinkCursor
;
; FUNCTION
; Updates the video hardware to relocate the displayed
; text cursor to match expectations of the running environment.
;
; INPUTS
;
; RESULT
;
; BUGS
; This function is undefined if video_cursorX and/or
; video_cursorY is outside the normal addressible bounds
; of the current display.
;
; SEE ALSO
; vCR, vLF, vMoveTo
;
;**************************************************************
vRethinkCursor:
push eax
push ebx
push edx
; Compute offset
; ASSUMES: 0 <= video_cursorX < video_width
; ASSUMES: 0 <= video_cursorY < video_height
mov eax,[video_cursorY]
imul eax,[video_width]
add eax,[video_cursorX]
mov ebx,eax
; Write low offset byte
mov al, 0x0f
mov dx, [video_io]
out dx, al
mov al, bl ;AL = offset low
inc edx ;0x3d5
out dx, al
; Write high offset byte
mov al, 0x0e ;Index reg.: cursor pos (high byte)
dec edx ;0x3d4
out dx, al
mov al, bh ;AL = offset high
inc edx ;0x3d5
out dx, al
pop edx
pop ebx
pop eax
ret
;****** vClear ************************************************
;
; NAME
; vClear
;
; SYNOPSIS
; call vClear
;
; FUNCTION
; Fills the entire screen with space characters, using the
; currently set attribute. The cursor position is NOT
; affected by this call.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vHome
;
;**************************************************************
vClear:
push eax
push ebx
push ecx
mov eax,[video_base]
mov ebx,[video_height]
imul ebx,[video_width]
mov ecx,[video_attributes]
or ecx,0x20
.more: mov [eax],cx
add eax,2
dec ebx
or ebx,ebx
jnz .more
pop ecx
pop ebx
pop eax
ret
;****** vHome *************************************************
;
; NAME
; vHome
;
; SYNOPSIS
; call vHome
;
; FUNCTION
; Locates the cursor in the upper left-hand corner of the
; display.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vCR, vLF, vClear
;
;**************************************************************
vHome:
mov [video_cursorY],dword 0
; fall-through to vCR intentional
;****** vCR ***************************************************
;
; NAME
; vCR
;
; SYNOPSIS
; call vCR
;
; FUNCTION
; Performs the glass-tty equivalent of a carriage return.
;
; INPUTS
;
; RESULT
;
; SEE ALSO
; vLF, vHome
;
;**************************************************************
vCR:
mov [video_cursorX],dword 0
jmp vRethinkCursor
;****** vLF ***************************************************
;
; NAME
; vLF
;
; SYNOPSIS
; call vLF
;
; FUNCTION
; Performs the glass-tty equivalent of a line feed. Note
; that the horizontal cursor position is NOT affected by
; this function.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vHome, vCR
;
;**************************************************************
vLF:
push eax
mov eax,[video_cursorY]
inc eax
cmp eax,[video_height]
jb .scrolling_unnecessary
dec eax
call vScrollUp
.scrolling_unnecessary:
mov [video_cursorY],eax
call vRethinkCursor
pop eax
call vCR
ret
;****** vScrollUp *********************************************
;
; NAME
; vScrollUp
;
; SYNOPSIS
; call vScrollUp
;
; FUNCTION
; Scrolls the whole screen up one line, filling in the bottom
; with spaces in the currently set attribute. This function
; does NOT change the current cursor location.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vChangeAttributes, vCR, vLF
;
;**************************************************************
vScrollUp:
push eax
push ebx
push ecx
; Scroll the display up one line
xor eax,eax ; Get offset for (0,1)
lea ebx,[eax+1]
call vOffsetAt ; EAX := source
mov ebx,[video_base] ; EBX := destination address
mov ecx,[video_width] ; ECX := number of bytes to move
imul ecx,[video_height]
sub ecx,[video_width]
shl ecx,1
call uMoveDown
; Overwrite the garbage at the bottom.
xor eax,eax
mov ebx,[video_height]
dec ebx
call vOffsetAt
mov ebx,[video_width]
mov ecx,[video_attributes]
or cl,0x20
.more: mov [eax],cx
add eax,2
dec ebx
or ebx,ebx
jnz .more
pop ecx
pop ebx
pop eax
ret
;****** vOffsetAt *********************************************
;
; NAME
; vOffsetAt
;
; SYNOPSIS
; mov eax,Xcoord
; mov ebx,Ycoord
; call vOffsetAt
; mov [memLocation],eax
;
; FUNCTION
; Given an X and Y coordinate on the display (with the upper-
; left-hand corner set to (0,0)), return a memory address
; with which a character and attribute pair can be stored.
;
; INPUTS
; EAX The horizontal coordinate
; EBX The vertical coordinate
;
; RESULT
; Byte address of the corresponding character in the video
; frame buffer.
;
; BUGS
; Strange things happen if the X or Y coordinate are out of
; bounds for the current VGA frame buffer size.
;
; SEE ALSO
;
;**************************************************************
vOffsetAt:
push ebx
imul ebx,[video_width]
add eax,ebx
shl eax,1
add eax,[video_base]
pop ebx
ret
;****** vEmit *************************************************
;
; NAME
; vEmit
;
; SYNOPSIS
; mov al,charToEmit
; call vEmit
;
; FUNCTION
; Displays the character in al to the screen at the current
; cursor position. This function DOES interpret the following
; control codes:
;
; $08 Backspace -- moves cursor to the left one position
; $09 Tab -- moves cursor to next tab stop (every 8 chars)
; $0A Line feed -- advances cursor down one line
; $0C Form feed -- clears the screen and homes the cursor
; $0D Carriage Return -- Restores cursor to column 0
;
; INPUTS
; AL Character to emit to the display
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vRawEmit
;
;**************************************************************
vEmit:
cmp al,0x08
jz vBS
cmp al,0x09
jz vTAB
cmp al,0x0A
jz vLF
cmp al,0x0C
jz vFF
cmp al,0x0D
jz vCR
; flow-through to vRawEmit is intentional.
;****** vRawEmit **********************************************
;
; NAME
; vRawEmit
;
; SYNOPSIS
; mov al,charToEmit
; call vRawEmit
;
; FUNCTION
; Displays the character in al to the screen at the current
; cursor position. This function DOES NOT interpret any
; control codes.
;
; INPUTS
; AL Character to emit to the display
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vEmit
;
;**************************************************************
vRawEmit:
push eax
push ebx
push ecx
and eax,0x000000FF
or eax,[video_attributes]
mov ecx,eax
mov eax,[video_cursorX]
mov ebx,[video_cursorY]
call vOffsetAt
mov [eax],cx
pop ecx
pop ebx
pop eax
; fall-through to vBumpCursor is intentional.
;****** vBumpCursor *******************************************
;
; NAME
; vBumpCursor
;
; SYNOPSIS
; call vBumpCursor
;
; FUNCTION
; Advances the cursor one character to the right.
; If wrap-around occurs, it will further drop the cursor
; down one line, if possible. If not, the screen is
; scrolled.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vEmit, vRawEmit, vLF, vCR
;
;**************************************************************
vBumpCursor:
push eax
mov eax,[video_cursorX]
inc eax
cmp eax,[video_width]
jnb .wrapAround
mov [video_cursorX],eax
pop eax
jmp vRethinkCursor
.wrapAround:
pop eax
call vCR
jmp vLF
;****** vType *************************************************
;
; NAME
; vType
;
; SYNOPSIS
; mov eax,msgBuffer
; mov ebx,msgLength
; call vType
;
; FUNCTION
; Displays the text stored in msgBuffer, consisting of msgLength
; bytes. It is safe to type a buffer of zero bytes.
;
; INPUTS
; EAX Pointer to the buffer to display
; EBX Length of the buffer. If 0, no text is displayed.
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vEmit, vRawEmit
;
;**************************************************************
vType:
push eax
push ebx
push ecx
mov ecx,eax
.again: or ebx,ebx
jz .done
mov al,[ecx]
inc ecx
call vEmit
dec ebx
jmp .again
.done: pop ecx
pop ebx
pop eax
ret
;****** vBS ***************************************************
;
; NAME
; vBS
;
; SYNOPSIS
; call vBS
;
; FUNCTION
; Emulates the glass-tty equivalent of a backspace on a
; teletype by moving the cursor to the left, if possible.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vTAB
;
;**************************************************************
vBS: push eax
call vRawBS
mov al,' '
call vEmit
pop eax
; fall-through to vBumpCursor is intentional.
vRawBS: push eax
mov eax,[video_cursorX]
or eax,eax
jz .asFarAsItllGo
dec eax
mov [video_cursorX],eax
call vRethinkCursor
.asFarAsItllGo:
pop eax
ret
;****** vTAB **************************************************
;
; NAME
; vTAB
;
; SYNOPSIS
; call vTAB
;
; FUNCTION
; Advances the cursor to the next tabstop, which is currently
; every 8 characters.
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vBS, vCR, vLF
;
;**************************************************************
vTAB: push eax
mov eax,[video_cursorX]
and eax,7
jz .moveAnother8
.oneMoreSpace:
mov al,0x20
call vEmit
mov eax,[video_cursorX]
and eax,7
jnz .oneMoreSpace
pop eax
ret
.moveAnother8:
mov al,0x20
call vEmit
call vEmit
call vEmit
call vEmit
call vEmit
call vEmit
call vEmit
call vEmit
pop eax
ret
;****** vPage / vFF *******************************************
;
; NAME
; vPage
;
; AKA
; vFF
;
; SYNOPSIS
; call vPage ; or...
; call vFF
;
; FUNCTION
; Clears the screen and homes the cursor, thus emulating
; a form-feed operation on a teletype (hence the name; it
; delivers a "new page").
;
; INPUTS
;
; RESULT
;
; BUGS
;
; SEE ALSO
; vTAB, vCR, vLF, vEmit
;
;**************************************************************
vPage:
vFF:
call vClear
jmp vHome
;****** uMoveDown *********************************************
;
; NAME
; uMoveDown
;
; SYNOPSIS
; mov eax,srcAddress
; mov ebx,dstAddress
; mov ecx,nbrOfBytes
; call uMoveDown
;
; FUNCTION
; Moves ECX bytes from EBX to EAX. This move is assumed
; correct if and only if EBX <= EAX. Otherwise, memory
; is filled with a repeating pattern.
;
; INPUTS
; EAX source address
; EBX destination address
; ECX number of bytes to move
;
; RESULT
;
; BUGS
;
; SEE ALSO
; uMoveUp, uMove
;
;**************************************************************
uMoveDown:
push eax
push ebx
push ecx
push edx
cmp ecx,4
jb .no32bits
.more32bits:
mov edx,[eax]
add eax,4
mov [ebx],edx
add ebx,4
sub ecx,4
cmp ecx,4
jae .more32bits
.no32bits:
cmp ecx,2
jb .no16bits
.more16bits:
mov dx,[eax]
add eax,2
mov [ebx],dx
add ebx,2
sub ecx,2
cmp ecx,2
jae .more16bits
.no16bits:
or ecx,ecx
jz .done
.morebytes:
mov dl,[eax]
inc eax
mov [ebx],dl
inc ebx
dec ecx
or eax,eax
jnz .morebytes
.done:
pop edx
pop ecx
pop ebx
pop eax
ret