Merge pull request #272 from tkchia/tkchia/20220826

plat/msdos386: refactor, firm up, and optimize
This commit is contained in:
David Given 2022-08-26 23:14:26 +02:00 committed by GitHub
commit 8619ce3ada
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 309 additions and 350 deletions

View file

@ -91,7 +91,7 @@ begtext:
! Copy the whole thing into 32-bit memory. ! Copy the whole thing into 32-bit memory.
mov ecx, 0x100/4 mov ecx, 0x100/4
mov edi, _psp mov edi, .psp
cld cld
1: 1:
eseg lods eseg lods
@ -101,7 +101,7 @@ begtext:
! Find the environment. ! Find the environment.
mov es, (_psp + 0x002C) ! converted to pmode segment mov es, (.psp + 0x002C) ! converted to pmode segment
! Count the size of the environment variable block. ! Count the size of the environment variable block.
@ -155,7 +155,7 @@ empty_environment:
push 3 ! MS-DOS version push 3 ! MS-DOS version
push ecx ! env. string data push ecx ! env. string data
push edx ! count of env. vars. push edx ! count of env. vars.
push _psp+0x80 ! raw command line push .psp+0x80 ! raw command line
call __sys_initmain call __sys_initmain
add esp, 5*4 add esp, 5*4
@ -225,7 +225,7 @@ no_room_msg: .ascii 'No room$'
.comm _errno, 4 .comm _errno, 4
.comm .doshandle, 2 .comm .doshandle, 2
.comm _psp, 256 .comm .psp, 256
.sect .bss .sect .bss
.space 32*1024 .space 32*1024

View file

@ -9,6 +9,7 @@ ackfile {
ackfile { ackfile {
name = "stub", name = "stub",
srcs = { "./stub.s" }, srcs = { "./stub.s" },
deps = { "plat/msdos386/libsys+headers" },
vars = { plat = "msdos386" } vars = { plat = "msdos386" }
} }

View file

@ -3,12 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .bss .sect .bss

View file

@ -1,11 +1,9 @@
! Declare segments (the order is important). #
! $Source$
! $State$
! $Revision$
.sect .text #include "libsysasm.h"
.sect .rom
.sect .data
.sect .bss
.sect .text
.define _brk .define _brk
_brk: _brk:

View file

@ -1,3 +1,10 @@
bundle {
name = "headers",
srcs = {
"./libsysasm.h"
}
}
acklibrary { acklibrary {
name = "lib", name = "lib",
srcs = { srcs = {
@ -9,6 +16,9 @@ acklibrary {
"./isatty.s", "./isatty.s",
"./rename.s", "./rename.s",
"./sbrk.c", "./sbrk.c",
"./sys_cpyin.s",
"./sys_cpyout.s",
"./sys_dpmidos.s",
"./sys_exists.s", "./sys_exists.s",
"./sys_getdate.s", "./sys_getdate.s",
"./sys_gettime.s", "./sys_gettime.s",
@ -19,17 +29,16 @@ acklibrary {
"./sys_rawopen.s", "./sys_rawopen.s",
"./sys_rawread.s", "./sys_rawread.s",
"./sys_rawwrite.s", "./sys_rawwrite.s",
"./sys_scpyout.s",
"./sys_xret.s", "./sys_xret.s",
"./unlink.s", "./unlink.s",
"plat/msdos/libsys+srcs", "plat/msdos/libsys+srcs",
}, },
deps = { deps = {
"lang/cem/libcc.ansi/headers+headers",
"plat/msdos386/include+headers",
"plat/msdos/libsys+headers", "plat/msdos/libsys+headers",
"+headers"
}, },
vars = { vars = {
plat = "msdos386" plat = "msdos386"
} }
} }

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Close a file. ! Close a file.

View file

@ -3,12 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
#define D(e) .define e; e #define D(e) .define e; e

View file

@ -15,14 +15,7 @@
! the new terms are clearly indicated on the first page of each file where ! the new terms are clearly indicated on the first page of each file where
! they apply. ! they apply.
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Get the current process identifier. For MS-DOS, use the Program Segment ! Get the current process identifier. For MS-DOS, use the Program Segment
! Prefix (PSP) segment as the PID, unless the system supports an actual ! Prefix (PSP) segment as the PID, unless the system supports an actual

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Say whether a given file descriptor number refers to a terminal. ! Say whether a given file descriptor number refers to a terminal.

View file

@ -0,0 +1,24 @@
/*
* © 2013 David Given
* © 2022 TK Chia
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef LIBSYSASM_H
#define LIBSYSASM_H
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Size of transfer buffer, for 32-bit DPMI mode.
TRANSFER_BUFFER_SIZE = 32 * 1024
#endif

View file

@ -3,54 +3,40 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Rename a file. ! Rename a file.
.define _rename .define _rename
_rename: _rename:
mov ebx, esp
push esi
push edi push edi
! Source filename.
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
! Destination filename. ! Destination filename.
mov eax, edi mov eax, 4+8(esp)
mov esi, 8(ebx) #define DEST_NAME_OFFSET (TRANSFER_BUFFER_SIZE / 2)
1: mov edx, DEST_NAME_OFFSET
lodsb mov ecx, edx
stosb call .sys_sncpyout
testb al, al jc 9f
jnz 1b xchg edi, eax
! Source filename.
mov eax, 4+4(esp)
xor edx, edx
call .sys_sncpyout
jc 9f
xchg edx, eax
! Make the DOS call. ! Make the DOS call.
o16 mov dx, (transfer_buffer_ptr)
o16 mov di, ax
movb ah, 0x56 movb ah, 0x56
mov ebx, 0x210000 call .sys_dpmidos
callf (interrupt_ptr)
pop edi pop edi
pop esi
push ss
pop es
jmp .sys_zret jmp .sys_zret
9:
pop edi
jmp .sys_toolongret

View file

@ -0,0 +1,32 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_cpyin: copy ecx bytes from the transfer buffer to es:eax (= ds:eax).
! Preserve all registers, except the flags.
.extern .sys_cpyin
.sys_cpyin:
push eax
push ecx
push esi
push edi
movzx esi, (transfer_buffer_ptr)
xchg edi, eax
mov ds, (pmode_ds)
mov eax, ecx
shr ecx, 2
rep movs
andb al, 3
movb cl, al
rep movsb
mov eax, ss
mov ds, eax
pop edi
pop esi
pop ecx
pop eax
ret

View file

@ -0,0 +1,34 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_cpyout: copy ecx bytes starting from ds:eax to the transfer
! buffer. Return eax := offset of transfer buffer in the real mode data
! segment. Preserve all other registers, except the flags.
.extern .sys_cpyout
.sys_cpyout:
push ecx
push edx
push esi
push edi
xchg esi, eax
movzx edi, (transfer_buffer_ptr)
mov eax, edi
mov es, (pmode_ds)
mov edx, ecx
shr ecx, 2
rep movs
movb cl, dl
andb cl, 3
rep movsb
mov ecx, ss
mov es, ecx
pop edi
pop esi
pop edx
pop ecx
ret

View file

@ -0,0 +1,16 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_dpmidos: simulate a call to real-mode int 0x21 with the current
! 16-bit register values.
.extern .sys_dpmidos
.sys_dpmidos:
movzx ebx, bx
or ebx, 0x210000
callf (interrupt_ptr)
ret

View file

@ -3,35 +3,19 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Say whether a file exists with the given name. ! Say whether a file exists with the given name.
.define __sys_exists .define __sys_exists
__sys_exists: __sys_exists:
push esi mov eax, 4(esp)
mov esi, 4+4(esp) call .sys_scpyout
movzx edi, (transfer_buffer_ptr) jc 9f
mov edx, edi xchg edx, eax
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
mov eax, 0x4300 mov eax, 0x4300
mov ebx, 0x210000 call .sys_dpmidos
callf (interrupt_ptr) 9:
push ss
pop es
sbb eax, eax sbb eax, eax
inc eax inc eax
ret ret

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Get the current system date from MS-DOS. ! Get the current system date from MS-DOS.

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Get the current system time from MS-DOS. ! Get the current system time from MS-DOS.

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Say whether a given file descriptor number refers to a valid open file ! Say whether a given file descriptor number refers to a valid open file
! descriptor. ! descriptor.

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Say whether a file descriptor is ready for input, i.e. reading from the ! Say whether a file descriptor is ready for input, i.e. reading from the
! fd will immediately return something. ! fd will immediately return something.

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Create or truncate a file. ! Create or truncate a file.
@ -18,30 +11,18 @@
__sys_rawcreat: __sys_rawcreat:
! Copy filename to transfer buffer. ! Copy filename to transfer buffer.
mov ebx, esp mov eax, 4(esp)
push esi call .sys_scpyout
push edi jc 9f
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
! Make the DOS call. ! Make the DOS call.
xchg edx, eax
movb ah, 0x3c movb ah, 0x3c
movzx edx, (transfer_buffer_ptr) movb al, 8(esp)
movb al, 8(ebx) call .sys_dpmidos
mov ebx, 0x210000
callf (interrupt_ptr)
pop edi
pop esi
push ss
pop es
jmp .sys_axret jmp .sys_axret
9:
jmp .sys_toolongret

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Move the current file position for a file descriptor. ! Move the current file position for a file descriptor.

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Open an existing file. ! Open an existing file.
@ -18,30 +11,14 @@
__sys_rawopen: __sys_rawopen:
! Copy filename to transfer buffer. ! Copy filename to transfer buffer.
mov ebx, esp mov eax, 4(esp)
push esi call .sys_scpyout
push edi
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
! Make the DOS call. ! Make the DOS call.
xchg edx, eax
movb ah, 0x3d movb ah, 0x3d
o16 mov dx, (transfer_buffer_ptr) movb al, 8(esp)
movb al, 8(ebx) call .sys_dpmidos
mov ebx, 0x210000
callf (interrupt_ptr)
pop edi
pop esi
push ss
pop es
jmp .sys_axret jmp .sys_axret

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Read bytes from a file descriptor. These routines do not do any ! Read bytes from a file descriptor. These routines do not do any
! translation between CRLF and LF line endings. ! translation between CRLF and LF line endings.
@ -20,15 +13,12 @@
.define __sys_rawread .define __sys_rawread
__sys_rawread: __sys_rawread:
enter 0, 0 file_handle = 1*4
push esi write_buffer = 2*4
push edi amount_to_read = 3*4
file_handle = 2*4
write_buffer = 3*4
amount_to_read = 4*4
mov eax, amount_to_read(ebp) mov eax, amount_to_read(esp)
mov ecx, 32*1024 mov ecx, TRANSFER_BUFFER_SIZE
cmp eax, ecx cmp eax, ecx
jge 2f jge 2f
mov ecx, eax mov ecx, eax
@ -38,41 +28,23 @@ amount_to_read = 4*4
movb ah, 0x3f movb ah, 0x3f
o16 mov dx, (transfer_buffer_ptr) o16 mov dx, (transfer_buffer_ptr)
movzx esi, dx o16 mov bx, file_handle(esp)
mov ebx, 0x210000 call .sys_dpmidos
o16 mov bx, file_handle(ebp) jc 3f
callf (interrupt_ptr)
jnc success
! Copy eax bytes out of the transfer buffer.
movzx ecx, ax
mov eax, write_buffer(esp)
call .sys_cpyin
xchg eax, ecx
ret
3:
! Process errors. ! Process errors.
push eax push eax
call __sys_seterrno call __sys_seterrno
pop ecx pop ecx
jmp exit
success:
! Copy eax bytes out of the transfer buffer.
movzx eax, ax
mov ecx, eax
jcxz exit
push eax
mov edi, write_buffer(ebp)
mov es, (pmode_ds)
cld
1:
eseg lodsb
movb (edi), al
inc edi
loop 1b
pop eax
exit:
pop edi
pop esi
push ss
pop es
leave
ret ret

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Write bytes to/to a file descriptor. These routines do not do any ! Write bytes to/to a file descriptor. These routines do not do any
! translation between CRLF and LF line endings. ! translation between CRLF and LF line endings.
@ -20,15 +13,12 @@
.define __sys_rawwrite .define __sys_rawwrite
__sys_rawwrite: __sys_rawwrite:
enter 0, 0 file_handle = 1*4
push esi read_buffer = 2*4
push edi amount_to_write = 3*4
file_handle = 2*4
read_buffer = 3*4
amount_to_write = 4*4
mov eax, amount_to_write(ebp) mov eax, amount_to_write(esp)
mov ecx, 32*1024 ! size of transfer buffer mov ecx, TRANSFER_BUFFER_SIZE
cmp eax, ecx cmp eax, ecx
jge 2f jge 2f
mov ecx, eax mov ecx, eax
@ -36,32 +26,22 @@ amount_to_write = 4*4
! Copy ecx bytes into the transfer buffer. ! Copy ecx bytes into the transfer buffer.
push ecx mov eax, read_buffer(esp)
mov esi, read_buffer(ebp) call .sys_cpyout
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
rep movsb
pop ecx
! Write from the transfer buffer to DOS. ! Write from the transfer buffer to DOS.
xchg edx, eax
movb ah, 0x40 movb ah, 0x40
o16 mov dx, (transfer_buffer_ptr) o16 mov bx, file_handle(esp)
mov ebx, 0x210000 call .sys_dpmidos
o16 mov bx, file_handle(ebp) movzx eax, ax
callf (interrupt_ptr)
jnc exit jnc exit
push eax push eax
call __sys_seterrno call __sys_seterrno
pop ecx pop ecx
exit: exit:
pop edi
pop esi
push ss
pop es
leave
ret ret
! vim: sw=4 ts=4 et ! vim: sw=4 ts=4 et

View file

@ -0,0 +1,58 @@
#
! $Source$
! $State$
! $Revision$
#include "libsysasm.h"
! .sys_scpyout: copy the ASCIIZ string starting from ds:eax to the
! transfer buffer. The resulting ASCIIZ string, including the final null,
! should fit into the entire transfer buffer. Return eax := offset of
! transfer buffer in real mode data segment. Return CF = 1 if and only if
! the ASCIIZ string is too long to fit. Preserve all other registers,
! except the flags.
!
! .sys_sncpyout: copy the ASCIIZ string starting from ds:eax to offset
! edx into the transfer buffer. The resulting ASCIIZ string should occupy
! at most ecx bytes, including the final null. Return eax : offset of
! string in real mode data segment. Return CF = 1 if and only if the ASCIIZ
! string is too long to fit. Preserve all other registers, except the
! flags.
.extern .sys_scpyout
.extern .sys_sncpyout
.sys_scpyout:
push ecx
push edx
mov ecx, TRANSFER_BUFFER_SIZE
xor edx, edx
jmp .cont
.sys_sncpyout:
push ecx
push edx
.cont:
push esi
push edi
mov esi, eax
movzx edi, (transfer_buffer_ptr)
add edi, edx
mov edx, edi
mov es, (pmode_ds)
jcxz .error
.loop:
lodsb
stosb
testb al, al
loopnz .loop
jz .ok
.error:
stc
.ok:
xchg edx, eax
mov edx, ss
mov es, edx
pop edi
pop esi
pop edx
pop ecx
ret

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! .sys_zret: if the carry flag is set, then set `errno' from the DOS error ! .sys_zret: if the carry flag is set, then set `errno' from the DOS error
! code in ax, and return an int -1. If the carry flag is clear, just ! code in ax, and return an int -1. If the carry flag is clear, just
@ -18,14 +11,18 @@
! !
! .sys_axret: if the carry flag is set, then set `errno' from the DOS error ! .sys_axret: if the carry flag is set, then set `errno' from the DOS error
! code in ax, and return a shortword -1. If the carry flag is clear, just ! code in ax, and return a shortword -1. If the carry flag is clear, just
! return ax as a return value. ! return eax := ax as a return value.
! !
! .sys_dxaxret: same as .sys_axret, but return -1 or eax := dx:ax as a ! .sys_dxaxret: same as .sys_axret, but return -1 or eax := dx:ax as a
! return value. ! return value.
!
! .sys_toolongret: a file name is too long: set `errno' to E2BIG, and return
! -1.
.extern .sys_zret .extern .sys_zret
.extern .sys_axret .extern .sys_axret
.extern .sys_dxaxret .extern .sys_dxaxret
.extern .sys_toolongret
.sys_zret: .sys_zret:
jc error jc error
xor eax, eax xor eax, eax
@ -34,6 +31,7 @@ no_error:
.sys_axret: .sys_axret:
jc error jc error
movzx eax, ax
ret ret
.sys_dxaxret: .sys_dxaxret:
@ -43,6 +41,11 @@ no_error:
mov eax, edx mov eax, edx
ret ret
.sys_toolongret:
mov (_errno), 7 ! E2BIG
or eax, -1
ret
error: error:
movzx eax, ax movzx eax, ax
push eax push eax

View file

@ -3,14 +3,7 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! Remove a file. ! Remove a file.
@ -18,29 +11,13 @@
_unlink: _unlink:
! Copy filename to transfer buffer. ! Copy filename to transfer buffer.
mov ebx, esp mov eax, 4(esp)
push esi call .sys_scpyout
push edi
mov esi, 4(ebx)
movzx edi, (transfer_buffer_ptr)
mov es, (pmode_ds)
cld
1:
lodsb
stosb
testb al, al
jnz 1b
! Make the DOS call. ! Make the DOS call.
mov dx, (transfer_buffer_ptr) xchg edx, eax
movb ah, 0x41 movb ah, 0x41
or ebx, 0x210000 call .sys_dpmidos
callf (interrupt_ptr)
pop edi
pop esi
push ss
pop es
jmp .sys_zret jmp .sys_zret

View file

@ -3,14 +3,8 @@
! $State$ ! $State$
! $Revision$ ! $Revision$
! Declare segments (the order is important). #include "libsysasm.h"
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
.use16 .use16
exe_header: exe_header:
.data2 0x5a4d ! magic number .data2 0x5a4d ! magic number
@ -319,12 +313,12 @@ int21:
o32 or ebx, 0x210000 o32 or ebx, 0x210000
! Simulate interrupt in the high half of ebx. ! Simulate interrupt in the high half of ebx.
interrupt: interrupt:
mov (dpmi_eax), ax o32 mov (dpmi_eax), eax
mov (dpmi_ebx), bx o32 mov (dpmi_ebx), ebx
mov (dpmi_ecx), cx o32 mov (dpmi_ecx), ecx
mov (dpmi_edx), dx o32 mov (dpmi_edx), edx
mov (dpmi_esi), si o32 mov (dpmi_esi), esi
mov (dpmi_edi), di o32 mov (dpmi_edi), edi
pushf pushf
pop (dpmi_flags) pop (dpmi_flags)
mov ax, (rseg) mov ax, (rseg)
@ -340,12 +334,12 @@ interrupt:
xor cx, cx xor cx, cx
int 0x31 ! simulate DOS interrupt int 0x31 ! simulate DOS interrupt
pop es pop es
o32 movzx eax, (dpmi_eax) o32 mov eax, (dpmi_eax)
o32 movzx ebx, (dpmi_ebx) o32 mov ebx, (dpmi_ebx)
o32 movzx ecx, (dpmi_ecx) o32 mov ecx, (dpmi_ecx)
o32 movzx edx, (dpmi_edx) o32 mov edx, (dpmi_edx)
o32 movzx esi, (dpmi_esi) o32 mov esi, (dpmi_esi)
o32 movzx edi, (dpmi_edi) o32 mov edi, (dpmi_edi)
push (dpmi_flags) push (dpmi_flags)
popf popf
ret ret
@ -410,7 +404,6 @@ stack:
.space 512 .space 512
dosstack: dosstack:
TRANSFER_BUFFER_SIZE = 32*1024
transfer_buffer: transfer_buffer:
.space TRANSFER_BUFFER_SIZE .space TRANSFER_BUFFER_SIZE