343c381323
FossilOrigin-Name: f656e5d148998902ce7693bcbdd89d1bc9ab1b2960f1f2ecfaef4d2b73968c20
912 lines
19 KiB
ArmAsm
912 lines
19 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 .data
|
|
gdt:
|
|
dw (.end-.dummy)
|
|
dd .dummy
|
|
dw 0
|
|
.dummy: dw 0,0,0,0
|
|
dw 0xffff,0x0000
|
|
db 0x00,0x9a,0xcf,0x00
|
|
dw 0xffff,0x0000
|
|
db 0x00,0x92,0xcf,0x00
|
|
.end:
|
|
|
|
|
|
section .text
|
|
extern main
|
|
global _start
|
|
global putchar
|
|
global getchar
|
|
|
|
align 4
|
|
_start:
|
|
mov dword [0xb8000], 0x2f4b2f4f
|
|
jmp main
|
|
jmp $
|
|
|
|
align 4
|
|
putchar:
|
|
mov eax, [esp-4]
|
|
call vEmit
|
|
ret
|
|
|
|
align 4
|
|
getchar:
|
|
call key
|
|
push eax
|
|
call vEmit
|
|
pop eax
|
|
ret
|
|
|
|
section .text
|
|
|
|
key:
|
|
xor eax,eax ; clear eax
|
|
.a: in al,64h ; Is any data waiting?
|
|
test al,1 ; Is character = ASCII 0?
|
|
jz .a ; Yes? Try again
|
|
in al,60h ; Otherwise, read scancode
|
|
xor edx,edx ; edx: 0=make, 1=break
|
|
test al,80h ; Is character = HEX 80h?
|
|
jz .b ; Skip the next line
|
|
inc edx ; Update edx
|
|
.b: and al,7Fh ; Filters to handle
|
|
cmp al,39h ; the ignored keys
|
|
ja .a ; We just try another key
|
|
mov ecx,[board] ; Load the keymap
|
|
mov al,[ecx+eax] ; Get the key ASCII char
|
|
or al,al ; Is is = 0?
|
|
js .shift ; No, use CAPITALS
|
|
jz .a ; Ignore 0's
|
|
or dl,dl ; Filter for break code
|
|
jnz .a ; Ignore break code
|
|
jmp .done
|
|
.shift: mov ecx,[edx*4 + .shifts] ; Load the CAPITAL keymap
|
|
mov [board],ecx ; Store into BOARD pointer
|
|
jmp .a ; And try again
|
|
.done:
|
|
ret
|
|
|
|
section .data
|
|
.shifts dd shift,alpha
|
|
board dd alpha
|
|
alpha:
|
|
db 0,27,"1234567890-=",8 ;00-0E
|
|
db 9,"qwertyuiop[]",10 ;0F-1C
|
|
db 0,"asdfghjkl;'`" ;1D-29
|
|
db -1,"\zxcvbnm,./",-1,"*",0,32,-2 ;2A-3A
|
|
shift:
|
|
db 0,27,"!@#$%^&*()_+",8 ;00-0E
|
|
db 9,"QWERTYUIOP{}",10 ;0F-1C
|
|
db 0,'ASDFGHJKL:"~' ;1D-29
|
|
db -1,"|ZXCVBNM<>?",-1,"*",0,32,-2 ;2A-3A
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|