📄 system.inc
字号:
; flat assembler interface for DOS
; Copyright (c) 1999-2006, Tomasz Grysztar.
; All rights reserved.
go32:
use16
call modes:real32
use32
retw
init_memory:
mov [stack_limit],0
cmp [mode],dpmi
je init_dpmi_memory
mov ax,4300h ; check for XMS
int 2Fh
cmp al,80h ; XMS present?
je xms_init
mov ax,0E801h ; check for large free extended memory
int 15h
jnc large_raw_memory
mov ah,88h ; how much extended memory free?
int 15h
or ax,ax
jz no_extended_memory
movzx eax,ax ; convert AX kilobytes to pointer
shl eax,10
jmp use_raw_memory
large_raw_memory:
movzx ecx,cx
shl ecx,10
movzx edx,dx
shl edx,16
mov eax,ecx
add eax,edx
use_raw_memory:
add eax,100000h
sub eax,[program_base]
mov [memory_end],eax
push ds
push 0 ; DS := 0
pop ds
call enable_a20 ; enable A20
call test_a20 ; is A20 enabled?
jz a20_ok
pop ds
jmp no_extended_memory
a20_ok:
lds bx,dword [4*19h]
mov eax,100000h ; initial free extended memory base
cmp dword [bx+12h],'VDIS' ; VDISK memory allocation?
jne short no_vdisk ; if present, get base of free memory
mov eax,dword [bx+2Ch] ; get first free extended memory byte
add eax,0Fh ; align on paragraph
and eax,0FFFFF0h ; address is only 24bit
no_vdisk:
push 0FFFFh ; DS := FFFFh for ext mem addressing
pop ds
cmp dword [13h],'VDIS' ; VDISK memory allocation?
jne short vdisk_ok ; if present, get base of free memory
movzx ebx,word [2Eh] ; get first free kilobyte
shl ebx,10
cmp eax,ebx ; pick larger of 2 addresses
ja short vdisk_ok
mov eax,ebx
vdisk_ok:
pop ds
sub eax,[program_base]
mov [memory_start],eax
mov edx,[memory_setting]
shl edx,10
jz extended_memory_ok
mov eax,[memory_end]
sub eax,[memory_start]
sub eax,edx
jbe extended_memory_ok
sub [memory_end],eax
jmp extended_memory_ok
enable_a20:
call test_a20 ; is A20 already enabled?
jz a20_enabled ; if yes, done
in al,92h ; PS/2 A20 enable
or al,2
out 92h,al
call test_a20 ; is A20 enabled?
jz a20_enabled ; if yes, done
call kb_wait ; AT A20 enable
jnz a20_enabled
mov al,0D1h
out 64h,al
call kb_wait
jnz a20_enabled
mov al,0DFh
out 60h,al
call kb_wait
a20_enabled:
ret
kb_wait: ; wait for safe to write to 8042
xor cx,cx
.loop:
in al,64h ; read 8042 status
test al,2 ; buffer full?
loopnz .loop ; if yes, loop
ret
test_a20: ; test for enabled A20
mov al,[0] ; get byte from 0:0
mov ah,al ; preserve old byte
not al ; modify byte
xchg al,[100000h] ; put modified byte to 0FFFFh:10h
cmp ah,[0] ; set zero if byte at 0:0 not modified
mov [100000h],al ; restore byte at 0FFFFh:10h
ret ; return, zero if A20 enabled
xms_init:
push es
mov ax,4310h ; get XMS driver address
int 2Fh
mov word [xms_proc],bx ; store XMS driver address
mov word [xms_proc+2],es
pop es
mov ah,3 ; enable A20
call call_xms
cmp ax,1 ; error enabling A20?
jne no_extended_memory
mov ah,88h ; get free extended memory size (XMS 3.0)
xor bl,bl
call call_xms
or bl,bl
jz xms_large_init
mov ah,8 ; get free extended memory size
xor bl,bl
call call_xms
or bl,bl
jnz no_extended_memory
mov dx,ax
movzx eax,ax
shl eax,10
mov [memory_end],eax
mov ah,9 ; allocate largest memory block
xms_allocate:
mov ecx,[memory_setting]
shl ecx,10
jz xms_size_ok
cmp ecx,[memory_end]
jae xms_size_ok
mov [memory_end],ecx
mov edx,[memory_setting]
xms_size_ok:
call call_xms
mov [xms_handle],dx
cmp ax,1
jne no_extended_memory
mov ah,0Ch ; lock extended memory block
call call_xms
cmp ax,1
jne no_extended_memory
shl edx,16
mov dx,bx
sub edx,[program_base]
mov [memory_start],edx ; store memory block address
add [memory_end],edx
jmp extended_memory_ok
xms_large_init:
mov edx,eax
shl eax,10
mov [memory_end],eax
mov ah,89h ; allocate largest memory block (XMS 3.0)
jmp xms_allocate
call_xms:
call modes:switch_real16
use16
call far dword [xms_proc]
call modes:switch_real32
use32
ret
no_extended_memory:
xor eax,eax
mov [memory_start],eax
extended_memory_ok:
mov ah,48h ; get free conventional memory size
mov bx,-1
int 21h
movzx ecx,bx
shl ecx,4
mov ah,48h ; allocate all conventional memory
int 21h
movzx edi,ax
shl edi,4
sub edi,[program_base]
mov [additional_memory],edi
mov [additional_memory_end],edi
add [additional_memory_end],ecx
cmp [memory_start],0
je only_conventional_memory
mov eax,[memory_end]
sub eax,[memory_start]
shr eax,2
cmp eax,ecx
ja no_conventional_memory
ret
only_conventional_memory:
shr ecx,2 ; use part of conventional memory
add edi,ecx ; as a substitute for extended memory
mov [memory_start],edi
xchg [additional_memory_end],edi
mov [memory_end],edi
ret
init_dpmi_memory:
mov ax,500h ; get free memory information
mov edi,[buffer_address]
int 31h
mov ebx,[edi]
allocate_dpmi_memory:
mov edx,[memory_setting]
shl edx,10
jz dpmi_memory_size_ok
cmp ebx,edx
jbe dpmi_memory_size_ok
mov ebx,edx
dpmi_memory_size_ok:
mov [memory_end],ebx
mov ecx,ebx
shr ebx,16
mov ax,501h
int 31h
jnc dpmi_memory_ok
mov ebx,[memory_end]
shr ebx,1
cmp ebx,4000h
jb out_of_memory
jmp allocate_dpmi_memory
dpmi_memory_ok:
shl ebx,16
mov bx,cx
sub ebx,[program_base]
jc out_of_memory
mov [memory_start],ebx
add [memory_end],ebx
mov ax,100h ; get free conventional memory size
mov bx,-1
int 31h
movzx ecx,bx
shl ecx,4
jecxz no_conventional_memory
mov ax,100h ; allocate all conventional memory
int 31h
movzx edi,ax
shl edi,4
sub edi,[program_base]
jc no_conventional_memory
mov [additional_memory],edi
mov [additional_memory_end],edi
add [additional_memory_end],ecx
mov eax,[memory_end]
sub eax,[memory_start]
shr eax,2
cmp eax,ecx
ja no_conventional_memory
ret
no_conventional_memory:
mov eax,[memory_end]
mov ebx,[memory_start]
sub eax,ebx
shr eax,2
mov [additional_memory],ebx
add ebx,eax
mov [additional_memory_end],ebx
mov [memory_start],ebx
ret
dos_int:
cmp [mode],dpmi
je dpmi_dos_int
stc
int 21h
ret
dpmi_dos_int:
mov [real_mode_segment],main
simulate_real_mode:
push 0 ; SS:SP (DPMI will allocate stack)
push 0 ; CS:IP (ignored)
push 0
push [real_mode_segment] ; DS
push [real_mode_segment] ; ES
stc
pushfw
push eax
push ecx
push edx
push ebx
push 0
push ebp
push esi
push edi
mov ax,300h
mov bx,21h
xor cx,cx
mov edi,esp
push es ss
pop es
int 31h
pop es
mov edi,[esp]
mov esi,[esp+4]
mov ebp,[esp+8]
mov ebx,[esp+10h]
mov edx,[esp+14h]
mov ecx,[esp+18h]
mov ah,[esp+20h]
add esp,32h
sahf
mov eax,[esp-32h+1Ch]
ret
dos_int_with_buffer:
cmp [mode],dpmi
je dpmi_dos_int_with_buffer
push ds buffer
pop ds
stc
int 21h
pop ds
ret
dpmi_dos_int_with_buffer:
mov [real_mode_segment],buffer
jmp simulate_real_mode
exit_program:
cmp [mode],dpmi
je .exit
cmp [xms_handle],0
je .exit
push ax
mov ah,0Dh ; unlock extended memory block
mov dx,[xms_handle]
call call_xms
mov ah,0Ah ; free extended memory block
call call_xms
pop ax
.exit:
mov ah,4Ch
int 21h
xms_proc dd ? ; XMS driver pointer
xms_handle dw ? ; handle of XMS memory block
get_environment_variable:
mov ebx,esi
push ds
mov ds,[environment_segment]
xor esi,esi
compare_variable_names:
mov edx,ebx
compare_character:
lodsb
mov ah,[es:edx]
inc edx
cmp al,'='
je end_of_variable_name
or ah,ah
jz next_variable
sub ah,al
jz compare_character
cmp ah,20h
jne next_variable
cmp al,41h
jb next_variable
cmp al,5Ah
jna compare_character
next_variable:
lodsb
or al,al
jnz next_variable
cmp byte [esi],0
jne compare_variable_names
pop ds
ret
end_of_variable_name:
or ah,ah
jnz next_variable
copy_variable_value:
lodsb
cmp edi,[es:memory_end]
jae out_of_memory
stosb
or al,al
jnz copy_variable_value
dec edi
pop ds
ret
open:
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100000b
mov dx,1
xor cx,cx
xor si,si
call dos_int_with_buffer
jnc open_done
cmp ax,7100h
je old_open
stc
jmp open_done
old_open:
mov ax,3D00h
xor dx,dx
call dos_int_with_buffer
open_done:
mov bx,ax
pop edi esi
ret
adapt_path:
mov esi,edx
mov edi,[buffer_address]
copy_path:
lodsb
cmp al,'/'
jne path_char_ok
mov al,'\'
path_char_ok:
stosb
or al,al
jnz copy_path
ret
create:
push esi edi
call adapt_path
mov ax,716Ch
mov bx,100001b
mov dx,10010b
xor cx,cx
xor si,si
xor di,di
call dos_int_with_buffer
jnc create_done
cmp ax,7100h
je old_create
stc
jmp create_done
old_create:
mov ah,3Ch
xor cx,cx
xor dx,dx
call dos_int_with_buffer
create_done:
mov bx,ax
pop edi esi
ret
write:
push edx esi edi ebp
mov ebp,ecx
mov esi,edx
.loop:
mov ecx,1000h
sub ebp,1000h
jnc .write
add ebp,1000h
mov ecx,ebp
xor ebp,ebp
.write:
push ecx
mov edi,[buffer_address]
shr ecx,2
rep movsd
mov ecx,[esp]
and ecx,11b
rep movsb
pop ecx
mov ah,40h
xor dx,dx
call dos_int_with_buffer
or ebp,ebp
jnz .loop
pop ebp edi esi edx
ret
read:
push edx esi edi ebp
mov ebp,ecx
mov edi,edx
.loop:
mov ecx,1000h
sub ebp,1000h
jnc .read
add ebp,1000h
mov ecx,ebp
xor ebp,ebp
.read:
push ecx
mov ah,3Fh
xor dx,dx
call dos_int_with_buffer
cmp ax,cx
jne .eof
mov esi,[buffer_address]
mov ecx,[esp]
shr ecx,2
rep movsd
pop ecx
and ecx,11b
rep movsb
or ebp,ebp
jnz .loop
.exit:
pop ebp edi esi edx
ret
.eof:
pop ecx
stc
jmp .exit
close:
mov ah,3Eh
int 21h
ret
lseek:
mov ah,42h
mov ecx,edx
shr ecx,16
int 21h
pushf
shl edx,16
popf
mov dx,ax
mov eax,edx
ret
display_string:
lods byte [esi]
or al,al
jz string_end
mov dl,al
mov ah,2
int 21h
jmp display_string
string_end:
ret
display_number:
push ebx
mov ecx,1000000000
xor edx,edx
xor bl,bl
display_loop:
div ecx
push edx
cmp ecx,1
je display_digit
or bl,bl
jnz display_digit
or al,al
jz digit_ok
not bl
display_digit:
mov dl,al
add dl,30h
mov ah,2
int 21h
digit_ok:
mov eax,ecx
xor edx,edx
mov ecx,10
div ecx
mov ecx,eax
pop eax
or ecx,ecx
jnz display_loop
pop ebx
ret
display_user_messages:
mov [displayed_count],0
call flush_display_buffer
cmp [displayed_count],1
jb line_break_ok
je make_line_break
mov ax,word [last_displayed]
cmp ax,0A0Dh
je line_break_ok
cmp ax,0D0Ah
je line_break_ok
make_line_break:
mov ah,2
mov dl,0Dh
int 21h
mov dl,0Ah
int 21h
line_break_ok:
ret
display_block:
add [displayed_count],ecx
cmp ecx,1
ja take_last_two_characters
jb display_character
mov al,[last_displayed+1]
mov ah,[esi]
mov word [last_displayed],ax
jmp display_character
take_last_two_characters:
mov ax,[esi+ecx-2]
mov word [last_displayed],ax
display_character:
lods byte [esi]
mov dl,al
mov ah,2
int 21h
loopd display_character
ret
fatal_error:
mov dx,error_prefix
mov ah,9
call dos_int
pop esi
call display_string
mov dx,error_suffix
mov ah,9
call dos_int
mov al,0FFh
jmp exit_program
assembler_error:
call display_user_messages
push dword 0
mov ebx,[current_line]
get_error_lines:
push ebx
test byte [ebx+7],80h
jz display_error_line
mov edx,ebx
find_definition_origin:
mov edx,[edx+12]
test byte [edx+7],80h
jnz find_definition_origin
push edx
mov ebx,[ebx+8]
jmp get_error_lines
display_error_line:
mov esi,[ebx]
call display_string
mov dx,line_number_start
mov ah,9
call dos_int
mov eax,[ebx+4]
and eax,7FFFFFFFh
call display_number
mov dl,']'
mov ah,2
int 21h
pop esi
cmp ebx,esi
je line_number_ok
mov dl,20h
mov ah,2
int 21h
push esi
mov esi,[esi]
movzx ecx,byte [esi]
inc esi
call display_block
mov dx,line_number_start
mov ah,9
call dos_int
pop esi
mov eax,[esi+4]
and eax,7FFFFFFFh
call display_number
mov dl,']'
mov ah,2
int 21h
line_number_ok:
mov dx,line_data_start
mov ah,9
call dos_int
mov esi,ebx
mov edx,[esi]
call open
mov al,2
xor edx,edx
call lseek
mov edx,[esi+8]
sub eax,edx
mov [counter],eax
xor al,al
call lseek
mov esi,[additional_memory]
read_line_data:
mov ecx,100h
cmp ecx,[counter]
jbe bytes_count_ok
mov ecx,[counter]
bytes_count_ok:
sub [counter],ecx
lea eax,[esi+ecx]
cmp eax,[additional_memory_end]
ja out_of_memory
push ecx
mov edx,esi
call read
pop ecx
get_line_data:
mov al,[esi]
cmp al,0Ah
je display_line_data
cmp al,0Dh
je display_line_data
cmp al,1Ah
je display_line_data
or al,al
jz display_line_data
inc esi
loop get_line_data
cmp [counter],0
ja read_line_data
display_line_data:
call close
mov ecx,esi
mov esi,[additional_memory]
sub ecx,esi
call display_block
mov dx,cr_lf
mov ah,9
call dos_int
pop ebx
or ebx,ebx
jnz display_error_line
mov dx,error_prefix
call dos_int
pop esi
call display_string
mov dx,error_suffix
mov ah,9
call dos_int
mov al,2
jmp exit_program
make_timestamp:
mov ah,2Ah
int 21h
push dx cx
movzx ecx,cx
mov eax,ecx
sub eax,1970
mov ebx,365
mul ebx
mov ebp,eax
mov eax,ecx
sub eax,1969
shr eax,2
add ebp,eax
mov eax,ecx
sub eax,1901
mov ebx,100
div ebx
sub ebp,eax
mov eax,ecx
xor edx,edx
sub eax,1601
mov ebx,400
div ebx
add ebp,eax
movzx ecx,byte [esp+3]
mov eax,ecx
dec eax
mov ebx,30
mul ebx
add ebp,eax
cmp ecx,8
jbe months_correction
mov eax,ecx
sub eax,7
shr eax,1
add ebp,eax
mov ecx,8
months_correction:
mov eax,ecx
shr eax,1
add ebp,eax
cmp ecx,2
pop cx
jbe day_correction_ok
sub ebp,2
test ecx,11b
jnz day_correction_ok
xor edx,edx
mov eax,ecx
mov ebx,100
div ebx
or edx,edx
jnz day_correction
mov eax,ecx
mov ebx,400
div ebx
or edx,edx
jnz day_correction_ok
day_correction:
inc ebp
day_correction_ok:
pop dx
movzx eax,dl
dec eax
add eax,ebp
mov ebx,24
mul ebx
push eax
mov ah,2Ch
int 21h
pop eax
push dx
movzx ebx,ch
add eax,ebx
mov ebx,60
mul ebx
movzx ebx,cl
add eax,ebx
mov ebx,60
mul ebx
pop dx
movzx ebx,dh
add eax,ebx
ret
program_base dd ?
buffer_address dd ?
psp_segment dw ?
environment_segment dw ?
mode dw ?
real_mode_segment dw ?
displayed_count dd ?
last_displayed rb 2
error_prefix db 'error: ',24h
error_suffix db '.'
cr_lf db 0Dh,0Ah,24h
line_number_start db ' [',24h
line_data_start db ':',0Dh,0Ah,24h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -