name DCExe title "DCExe (C)2000 Double Dutch Designs Limited" comment "Written by Anthony Ball" ; This source code & any modifications remain the property of ; Double Dutch Designs Limited ; You are free to modify this code as you wish, but note that ; you will probabily lose compatibility with future versions. ; If you have any "constructive" critism, or great ideas please ; get in touch with: dcexe@doubledutchdesigns.co.uk ; This is my 1st pc assembly program in 3 years - don't laugh! ;) ; to assemble, it requires a masm compatible assembler include bios.inc ; included with masm include dos.inc ; included with masm true equ 1 ; logic equates false equ 0 yes equ true no equ false TimeOut equ 30000 ; max value 60000 DefaultN equ 1 name_max equ 128 ; max length of filename BufferSize equ 50*1024 lf equ 0ah cr equ 0dh stack segment para stack "STACK" db 64 dup("STACK ") stack ends data segment para public "DATA" FastBuffer db BufferSize dup (0) FileSize dd 0 ; file size BinaryA dd 8c010000h ; binary destination address GoA dd 8c010000h CurrentWritten dd 0 CurrentRead dd 0 StartClock dd 0 BufferPos dw 0 BufferLeft dw 0 BufferDone dw 0 LineNo dd 0 ; current accelerated line no Handle dw 0 ; file handle Port dw 268h ; port address LastK dw 0 ; number of k transfered WriteK dw 0 EndK dw 0 ; number of k to transfer SafeAx dw 0 SafeDi dw 07 LengthH dw 0 ; transfer length high LengthL dw 0 ; transfer length low BaudN db 0 ; default to fastest on new lead! BinaryF db 0 ; binary mode GoF db 0 ; go flag FileServerF db 0 ; fileserver mode... UpdateF db 0 ; update marcus dc first! ConsoleF db 0 ; console mode on SlowF db 0 ; slow mode MyRTS db 0 TransLen db 0 ; length of line AboveDos2 db cr,lf,"DCExe.exe for DOS 2.0 or above only!!!",cr,lf,"$" DCExeTitle db cr,lf,"DCExe.exe Version 1.011 (c)2000 Double Dutch Designs Limited$" Missing db cr,lf,"Required parameter missing",cr,lf,"$" Usage db cr,lf,"Sends a file across to the DreamCast" db cr,lf,lf,"DCEXE [/?] [/2] [/3] [/n#] [/c] [/b[@]] [/f] [/g[@]] [/s] [filename]" db cr,lf," /? The correct way of displaying usage!" db cr,lf," /2 Sends to 2nd port on pro card" db cr,lf," /3 Sends to 'doomed's custom card!" db cr,lf," /4 Sends to 'fire' licenced card!" db cr,lf," /n# Sends at speed '#' using a turbo card (N value on SH4)." db cr,lf," /b[@] Binary transfer to address @ (default is 8c010000)." db cr,lf," /f Enter fileserver mode (experimental)." db cr,lf," /g[@] Go run at @ (if no addr then -b addr)!" db cr,lf," /c Enables console mode." db cr,lf," /s Slow mode (turn off accelerated SRECords)." db cr,lf," filename Specifies the file to be sent (by default an SRECord)." db cr,lf,lf,"Note: # numbers are decimal, @ numbers are hex." db cr,lf,lf,"You can use '-' instead of '/' when choosing options. Options ARE" db cr,lf,"case dependant! The default 'N' value is 0!" db cr,lf,lf,"Visit 'http://www.doubledutchdesigns.co.uk' for updates...$" DCSpeed db cr,lf,lf,"Speed $" DCIs db " is $" DCKbps db "kbps (approx)$" BadFSCmd db cr,lf,"Bad FileServer command or garbage!!!$" NoCable db cr,lf,"No DCExe cable detected!!!$" UMarcus db cr,lf,"Updating Original Serial Slave to DCExe...$" NoCard db cr,lf,"DCXfer card not found!!!$" NoDCExe db cr,lf,"Cannot find DC side of DCExe!!! Reboot DC!!!" db cr,lf,"This may be due to the 110 ohm resistor being incorrect." db cr,lf,"If you think this is the problem, there is more information on" db cr,lf,"the web page to help you solve it...$" TransferInt db cr,lf,"Transfer interrupted!!!$" FileNotFound db cr,lf,"File not found!!!$" ZeroLen db cr,lf,"File has zero length!!!$" TransAcc db cr,lf,"Accelerated SRECord transfer...$" UnknownSRec db cr,lf,"Uncorrect SRECord at line $" Transfering db cr,lf,"Transfering across to DC..." Filename db cr,lf,"File:" DCFile db name_max dup(0) ; file spec string DCFile2 db name_max dup(0) ; file spec 2 string DCOf db " of $" DCBytes db "kbytes transfered...",cr,"$" DCOf2 db " of $" DCBytes2 db "kbytes read ($" DCBytes3 db "kbytes written!)...",cr,"$" DCTime db cr,lf,"Transfer took $" DCTime2 db ".$" DCTime3 db " seconds!!!$" ConsoleMode db cr,lf,lf,"Console mode enabled:",cr,lf,"$" FileServerMode db cr,lf,lf,"FileServer mode enabled:",cr,lf,"$" BinaryMode db cr,lf,lf,"Binary transfer started...",cr,lf,"$" DCNumber db "xxxxxxxxxxxxxxxx$" HexTable db "0123456789abcdef" data ends cseg segment para public "CODE" Start proc far assume cs:cseg,ds:data,ss:stack .386 push ds ; don't ask why!!! sub ax,ax push ax mov ax,seg data ; load ds with data address mov ds,ax @ShowStr DCExeTitle ; display title ; Check DOS @GetVer ; get DOS version .if al < 2 ; requires DOS 2.0 @ShowStr AboveDos2 ; else error and quit int 20h .endif ; get clock... mov ah,0 int 1ah shl ecx,16 and edx,0ffffh or ecx,edx mov StartClock,ecx ; Get command line and copy to filename buffer mov di, 80h ; PSP offset of command line mov bl, es:[di] ; Get length from first byte sub bh, bh or bx, bx je MissingErr mov word ptr es:[bx+81h], 0 ; Convert to ASCIIZ NextCmd: mov al," " ; Character to check for inc di ; Advance beyond count mov cx, 0ffffh ; Don't let count interfere repe scasb ; Find first nonspace dec di ; Adjust mov al,es:[di] cmp al,"/" je Command cmp al,"-" je Command push ax mov cx,26 ; set baud rate... 56k!!! call InitPort ; init port now, then it's ready! pop ax cmp bx,0 ; is card present? je NoCardErr cmp bx,2 ; is cable in socket? je NocableErr ; send "built-in" latest version to Marcus DC!!! mov SafeAx,ax mov SafeDi,di call Flush mov al,lf call TxByte call TxByte mov cx,TimeOut MWait: push cx call RxByte pop cx dec cx jz NotMarcus cmp ah,0 je MWait mov cx,TimeOut cmp al,'>' jne MWait UpdateMarcus: @ShowStr UMarcus lea di,SerialInc FindMarcus: mov ah,byte ptr cs:[di] mov al,byte ptr cs:[di+1] cmp ax,5330h je Marcus inc di jmp FindMarcus Marcus: push di mov al,byte ptr cs:[di] cmp al,0 je MarcusDone push ax call TxByte ; send to serial port call RxByte ; recieve any replies... pop ax MarcusDone: pop di inc di cmp al,0 jne Marcus NotMarcus: call Flush mov cl,BaudN ; turn on requested speed!!! call InitPort mov al,lf call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte mov cx,TimeOut BWait: push cx call RxByte pop cx dec cx jz Try2 cmp ah,0 je BWait mov cx,TimeOut cmp al,']' jne BWait Try2: mov al,lf call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte mov cx,TimeOut BWait2: push cx call RxByte pop cx dec cx jz SendBaud cmp ah,0 je BWait2 mov cx,TimeOut cmp al,']' jne BWait2 jmp KeepBaud ; already at speed SendBaud: call Flush mov cl,DefaultN ; turn on faster speed!!! call InitPort mov al,lf call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte mov cx,TimeOut SWait: push cx call RxByte pop cx dec cx jz STry2 cmp ah,0 je SWait mov cx,TimeOut cmp al,']' jne SWait STry2: mov al,lf call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte call TxByte mov cx,TimeOut SWait2: push cx call RxByte pop cx dec cx jz SlaveErr cmp ah,0 je SWait2 mov cx,TimeOut cmp al,']' jne SWait2 call Flush ; wait until empty! mov cl,BaudN ; set baud rate... cmp cl,DefaultN ; is it existing baud!!! je KeepBaud push cx mov al,'n' push cx call TxByte pop cx mov al,cl shr al,4 and ax,0fh lea di,HexTable add di,ax mov al,byte ptr ds:[di] push cx call TxByte pop cx mov al,cl and ax,0fh lea di,HexTable add di,ax mov al,byte ptr ds:[di] call TxByte mov al,lf call TxByte call Flush pop cx call InitPort ; init port now, then it's ready! KeepBaud: mov ax,SafeAx mov di,SafeDi cmp al,0 ; make sure there is a filename jne IsFilename cmp FileServerF,1 ; if no filename, then maybe fileserver? je DoFileServer ; yep! cmp ConsoleF,1 ; if no filename, then maybe console? je Console ; yep! jmp MissingErr ; missing parameter if no console, or name IsFilename: mov si, di ; Filename source mov di, offset DCFile ; Name buffer destination mov bx, ds ; Save segment registers mov dx, es mov ds, dx ; DS = ES mov es, bx ; ES = DS mov cx, name_max ; Count = max filename allowed .repeat lodsb ; Copy characters .break .if (al == ' ') || (al == 0) ; Stop at space or null stosb .untilcxz ; Until name exceeds max mov ds, bx ; Restore segments mov es, dx mov byte ptr [di],0 mov byte ptr [di+1],cr mov byte ptr [di+2],lf mov byte ptr [di+3],"$" stc ; set the carry flag mov ax,7160h ; dos 7 call to convert to short name mov cl,1 mov ch,0 push es mov dx,ds mov es,dx lea si,DCFile ; possible long name lea di,DCFile2 ; destination of shortname int 21h pop es lea dx,DCFile2 jnc TryNew ; either error, or not dos 7! ; get filesize, work out k size lea dx,DCFile TryNew: mov ah,3dh ; open file mov al,0 ; read only int 21h jnc FileOkay @ShowStr FileNotFound @ShowStr Filename jmp ExitOkay FileOkay: mov Handle,ax mov bx,ax mov ah,42h ; seek mov al,2 ; move to end of file mov cx,0 ; no offset mov dx,0 int 21h rol edx,16 mov dx,ax ; edx now has 32bit file length cmp edx,0 je FileErr mov FileSize,edx shr edx,10 mov EndK,dx ; save k size! @ShowStr DCSpeed mov eax,0 mov al,BaudN call PutNumber @ShowStr DCIs mov ebx,0 mov bl,BaudN inc ebx mov eax,1562500 mov edx,0 div ebx mov ebx,1000 mov edx,0 div ebx call PutNumber @ShowStr DCKbps cmp BinaryF,0 je SRecTransfer @ShowStr BinaryMode ; display transfering mov al,"B" ; binary transfer call TxByte ; send to serial port mov eax,BinaryA ; addr call TxLong mov eax,FileSize ; length call TxLong @ShowStr FileName ; display filename jmp TransferNow SRecTransfer: cmp SlowF,0 je AccSRec @ShowStr Transfering ; display transfering TransferNow: mov bx,Handle mov ah,42h ; seek mov al,0 ; move to beginning of file! mov cx,0 ; no offset mov dx,0 int 21h Transfer: mov eax,0 mov ax,LastK call PutNumber @ShowStr DCOf ; transfer # of bytes mov eax,0 mov ax,EndK call PutNumber @ShowStr DCBytes mov cx,1024 call BufferedRead cmp ax,0 je TransferComplete mov di,dx NextByte: cmp ax,1024 jne NoInc inc LastK NoInc: push di push ax mov al,byte ptr [di] call TxByte ; send to serial port call RxByte ; recieve any replies... pop ax pop di dec ax inc di cmp ax,0 jne NextByte mov ah,11h ; has a key been pressed? int 16h jz Transfer ; not pressed!!! mov ah,10h ; grab the key! int 16h cmp ax,011bh ; "esc" pressed? je TransErr jmp Transfer AccSRec: @ShowStr TransAcc @ShowStr FileName ; display filename mov bx,Handle mov ah,42h ; seek mov al,0 ; move to beginning of file! mov cx,0 ; no offset mov dx,0 int 21h ATransfer: mov ah,11h ; has a key been pressed? int 16h jz AcarryOn ; not pressed!!! mov ah,10h ; grab the key! int 16h cmp ax,011bh ; "esc" pressed? je TransErr ACarryOn: mov eax,CurrentRead mov ebx,CurrentWritten shr eax,10 shr ebx,10 cmp ax,LastK jne AWriteText cmp bx,WriteK je ASkipText AWriteText: mov LastK,ax mov WriteK,bx call PutNumber @ShowStr DCOf2 ; transfer # of bytes mov eax,0 mov ax,EndK call PutNumber @ShowStr DCBytes2 mov eax,0 mov ax,WriteK call PutNumber @ShowStr DCBytes3 ASkipText: AReadAgain: mov cx,1 call BufferedRead cmp ax,0 je TransferComplete inc CurrentRead mov di,dx mov al,ds:[di] ; get character cmp al,cr je AReadAgain cmp al,lf jne ATry inc LineNo jmp AReadAgain ATry: cmp al,"S" jne AccError mov cx,1 call BufferedRead cmp ax,0 je AccError inc CurrentRead mov di,dx mov al,ds:[di] ; get character cmp al,"0" je AType0 cmp al,"3" je AType3 cmp al,"7" jne AccError mov cx,13 call BufferedRead cmp ax,13 jne AccError add CurrentRead,13 mov di,dx mov al,ds:[di+12] cmp al,lf je ACrOkay7 cmp al,cr jne AccError ACrOkay7: inc LineNo push dx mov al,"G" call TxByte pop dx add dx,2 call CreateByte shl eax,8 call CreateByte shl eax,8 call CreateByte shl eax,8 call CreateByte call TxLong call RxByte add CurrentWritten,5 jmp ATransfer AType0: mov cx,1 call BufferedRead cmp ax,0 je AccError inc CurrentRead mov di,dx mov al,ds:[di] cmp al,cr je ATransfer cmp al,lf jne AType0 inc LineNo jmp ATransfer AType3: mov cx,10 call BufferedRead cmp ax,10 jne AccError add CurrentRead,10 call CreateByte mov TransLen,al push dx mov al,"B" call TxByte pop dx call CreateByte shl eax,8 call CreateByte shl eax,8 call CreateByte shl eax,8 call CreateByte call TxLong call RxByte mov eax,0 mov al,TransLen sub al,5 call TxLong call RxByte add CurrentWritten,9 mov cx,0 mov cl,TransLen sub cl,4 shl cx,1 call BufferedRead and eax,0ffffh add CurrentRead,eax sub TransLen,5 ANextByte: cmp TransLen,0 je ADone3 call CreateByte push dx call TxByte call RxByte inc CurrentWritten pop dx dec TransLen jmp ANextByte ADone3: mov cx,1 call BufferedRead cmp ax,0 je AccError inc CurrentRead mov di,dx mov al,ds:[di] cmp al,lf je ACrOkay3 cmp al,cr jne AccError ACrOkay3: inc LineNo jmp ATransfer AccError: mov ah,3eh ; close file mov bx,Handle int 21h @ShowStr UnknownSRec mov eax,LineNo call PutNumber jmp ExitOkay TransferComplete: cmp GoF,0 je NoGo mov al,"G" ; jump to address call TxByte mov eax,GoA call TxLong NoGo: mov ah,3eh ; close file mov bx,Handle int 21h ; get clock again... mov ah,0 int 1ah shl ecx,16 and edx,0ffffh or ecx,edx mov eax,StartClock sub ecx,eax mov StartClock,ecx @ShowStr DCTime mov ebx,10 mov eax,StartClock mul ebx mov ebx,182 div ebx mov StartClock,edx call PutNumber cmp StartClock,0 je DoneTime @ShowStr DCTime2 mov ebx,10 mov eax,StartClock mul ebx mov ebx,182 div ebx mov StartClock,edx call PutNumber mov eax,StartClock cmp eax,0 je DoneTime mov ebx,10 mul ebx mov ebx,182 div ebx mov StartClock,edx call PutNumber mov eax,StartClock cmp eax,0 je DoneTime mov ebx,10 mul ebx mov ebx,182 div ebx mov StartClock,edx call PutNumber DoneTime: @ShowStr DCTime3 Console: cmp FileServerF,0 jne DoFileServer cmp ConsoleF,0 je ExitOkay call Flush call Empty @ShowStr ConsoleMode ; display title! CLoop: mov ah,11h ; has a key been pressed? int 16h jz NotPressed ; not pressed!!! mov ah,10h ; grab the key! int 16h cmp ax,011bh ; "esc" pressed? je ExitOkay push ax mov dl,al ; local echo mov ah,2 int 21h pop ax cmp al,cr jne NotCR mov dl,lf ; local line feed! mov ah,2 int 21h mov al,lf NotCR: call TxByte NotPressed: call RxByte and al,7fh ; limit things that can be displayed on screen cmp ah,0 je CLoop mov dl,al mov ah,2 int 21h jmp NotPressed ; fileserver - experimental DoFileServer: call Flush call Empty @ShowStr FileServerMode ; display title! FSLoop: call RxPause ; get command mov dl,al mov dh,al call SafeRxPause ; get inverted command xor dl,al cmp dl,0ffh jne FileServerErr mov ah,0 mov al,dh shl ax,1 lea si,FSTable add si,ax mov dx,cs:[si] jmp (dx) FSExit: jmp ExitOkay ; low level DCXfer control - Port = 268h (port 1) or 260h (port 2 - pro only) ; empty rx buffer Empty: mov cx,TimeOut/4 ELoop: call RxByte dec cx jz EExit cmp ah,0 je ELoop jmp Empty EExit: retn ; empty output buffer Flush: mov dx,Port add dx,5 FlWait: in al,dx ; check bit 6 and al,40h je FlWait retn ; cx=DC's N rate 0-ffh (0 being fastest) ; returns bx (0=no card, 1=okay, 2=no cable) InitPort: mov dx,Port add dx,7 ; load test location mov bx,0 ; default to card not present mov al,55h out dx,al mov al,0 in al,dx cmp al,55h jne IPExit ; card not present! mov al,0aah ; 2nd check!!! out dx,al mov al,0 in al,dx cmp al,0aah jne IPExit ; card not present! mov bx,1 ; passed checks! sub dx,4 mov al,80h ; set baud rate out dx,al sub dx,3 mov ax,cx inc ax out dx,al ; output 'N' inc dx mov al,0 out dx,al ; clear next location add dx,2 mov al,0bfh out dx,al dec dx mov al,0d0h ; enable rts & cts!!! out dx,al inc dx mov al,3 ; protocol out dx,al dec dx mov al,7 ; fifo mode + reset fifo's out dx,al add dx,2 mov al,0 out dx,al sub dx,3 out dx,al add dx,3 out dx,al ; cable check add dx,2 in al,dx and al,20h jne IPNoCable mov al,1 sub dx,2 out dx,al add dx,2 in al,dx and al,20h jne IPExit IPNoCable: mov bx,2 ; cable missing IPExit: retn ; input al, ah=1 if valid RxByte: mov dx,Port add dx,5 mov ax,0 RxWait: in al,dx and al,01h jz RxExit sub dx,5 in al,dx ; get character mov ah,1 RxExit: retn RxCxDx: call SafeRxPause mov ch,al call SafeRxPause mov cl,al RxDx: call SafeRxPause mov dh,al call SafeRxPause mov dl,al retn SafeRxPause: push dx call RxPause pop dx retn RxPause: call RxByte ; wait for character cmp ah,0 je Rxpause retn ; output eax TxLong: mov ebx,eax shr eax,24 call TxByte ; send 4 bytes in hi 1st order mov eax,ebx shr eax,16 call TxByte mov ax,bx shr ax,8 call TxByte mov ax,bx call TxByte retn TxCxDx: mov al,ch call SafeTxByte mov al,cl call SafeTxByte TxDx: mov al,dh call SafeTxByte mov al,dl call SafeTxByte retn ; tx, but preserve cx & dx SafeTxByte: push cx push dx call TxByte pop dx pop cx retn ; output al!!! TxByte: mov cl,al mov dx,Port add dx,5 TxWait: in al,dx and al,20h jz TxWait sub dx,5 mov al,cl out dx,al TxExit: retn ; dx point to data, put byte in al, inc dx by 2 CreateByte: and eax,0ffffff00h mov ebx,0 mov di,dx mov bl,ds:[di] cmp bl,"9" ja CBLetter1 sub bl,"0" shl bl,4 or eax,ebx jmp CB2 CBLetter1: sub bl,"A"-10 shl bl,4 or eax,ebx CB2: mov bl,ds:[di+1] add dx,2 cmp bl,"9" ja CBLetter2 sub bl,"0" or eax,ebx retn CBLetter2: sub bl,"A"-10 or eax,ebx retn ; in cx with amount to read (upto 1k), out dx with position, ax with bytes read ; this will be better later! BufferedRead: cmp BufferDone,0 jne BRDone cmp BufferLeft,1300 ja BRDone push cx lea di,FastBuffer mov si,di add si,BufferPos mov cx,BufferLeft BRShift: mov al,ds:[si] mov ds:[di],al inc si inc di dec cx jnz BRShift mov dx,di mov ah,3fh ; read data mov bx,Handle mov cx,BufferSize-2048 int 21h cmp ax,BufferSize-2048 je BRReadOkay mov BufferDone,1 BRReadOkay: add BufferLeft,ax mov BufferPos,0 pop cx BRDone: lea si,FastBuffer mov di,dx add si,BufferPos lea dx,FastBuffer add dx,BufferPos add BufferPos,cx mov ax,BufferLeft cmp BufferLeft,cx jb BRError sub BufferLeft,cx mov ax,cx retn BRError: mov BufferLeft,0 retn Command: inc di ; skip "/" or "-" mov al,es:[di] cmp al,"n" je CMD_SetBaud cmp al,"c" je CMD_Console cmp al,"f" je CMD_FileServer cmp al,"u" je CMD_Update cmp al,"b" je CMD_Binary cmp al,"g" je CMD_Go cmp al,"2" je CMD_Port2 cmp al,"3" je CMD_Port3 cmp al,"4" je CMD_Port4 cmp al,"s" je CMD_Slow @ShowStr Usage ; display title jmp ExitOkay CMD_SetBaud: call GetNumber mov BaudN,al jmp NextCmd CMD_Slow: mov SlowF,1 jmp NextCmd CMD_Console: mov ConsoleF,1 jmp NextCmd CMD_FileServer: mov FileServerF,1 jmp NextCmd CMD_Update: mov UpdateF,1 jmp NextCmd CMD_Binary: mov BinaryF,1 call GetHex cmp dx,-1 je NextCmd mov BinaryA,eax mov GoA,eax jmp NextCmd CMD_Go: mov GoF,1 call GetHex cmp dx,-1 je NextCmd mov GoA,eax jmp NextCmd CMD_Port2: mov Port,260h jmp NextCmd CMD_Port3: mov Port,2e0h jmp NextCmd CMD_Port4: mov Port,258h jmp NextCmd FileServerErr: @ShowStr BadFSCmd ; bad fileserver command! jmp ExitOkay NoCableErr: @ShowStr NoCable ; no cable inserted! jmp ExitOkay SlaveErr: @ShowStr NoDCExe ; can't talk to serial slave! jmp ExitOkay NoCardErr: @ShowStr NoCard ; card missing jmp ExitOkay TransErr: mov ah,3eh ; close file mov bx,Handle int 21h @ShowStr TransferInt ; transfer interrupted jmp ExitOkay FileErr: mov ah,3eh ; close file mov bx,Handle int 21h @ShowStr ZeroLen @ShowStr Filename jmp ExitOkay MissingErr: @ShowStr Missing ; missing message! ExitOkay: mov al,00h ; result 0!!! Exit: @Exit ; gets a hex number pointed to by di, stops on last digit GetHex: mov eax,0 mov ebx,16 mov ecx,0 mov dx,-1 GHLoop: mov cl,es:[di+1] cmp cl,"0" ; < 0? jb GHExit cmp cl,"9"+1 ; < 9+1? jb GHOkay cmp cl,"a" ; < a? jb GHExit cmp cl,"f" ; > f? ja GHExit sub cl,"a"-10 jmp GHOkay2 GHOkay: sub cl,"0" GHOkay2: mul ebx add eax,ecx inc di mov dx,0 jmp GHLoop GHExit: retn ; gets a decimal number pointed to by di, stops on last digit GetNumber: mov eax,0 mov ebx,10 mov ecx,0 mov dx,-1 GNLoop: mov cl,es:[di+1] cmp cl,"0" ; < 0? jb GNExit cmp cl,"9" ; > 9? ja GNExit sub cl,"0" mul ebx add eax,ecx inc di mov dx,0 jmp GNLoop GNExit: retn ; displays a decimal number "eax" on the screen PutNumber: mov ebx,10 lea di,DCNumber+16 mov byte ptr [di],"$" PNLoop: dec di mov edx,0 div ebx add dx,"0" mov byte ptr [di],dl cmp eax,0 jne PNLoop mov dx,di mov ah, 9 int 21h retn ; converts to a hex number "eax" to the dc PutHex: mov ebx,16 lea di,DCNumber+16 mov byte ptr [di],"$" PHLoop: dec di mov edx,0 div ebx mov si,dx mov dl,byte ptr [si+HexTable] mov byte ptr [di],dl cmp eax,0 jne PHLoop mov dx,di mov ah, 9 int 21h retn RecieveString: call RxPause mov ds:[di],al inc di or al,al jne RecieveString retn ; fileserver table semi based on psexe FSTable: dw FSNop ;00 dw FSPutchar ;01 dw FSGetchar ;02 dw FSOpen ;03 dw FSCreate ;04 dw FSRead ;05 dw FSWrite ;06 dw FSSeek ;07 dw FSClose ;08 dw FSDelete ;09 dw FSRename ;0a dw FSExit ;0b dw FSWriteBlank ;0c ; dw FSFiles ;0d ; dw FSNFiles ;0e ; dw FSChdir ;0f ; dw FSCurdir ;10 ; dw FSChdrv ;11 ; dw FSCurdrv ;12 FSNop: jmp FSLoop FSPutchar: call RxPause ; wait for character cmp al,lf ; je FSPCLf ; linefeed mov ah,2 ; putchar mov dl,al ; chr int 21h ; jmp FSLoop FSPCLf: mov ah,2 ; putchar mov dl,cr ; chr=cr int 21h ; mov ah,02h ; putchar mov dl,lf ; chr=lf int 21h jmp FSLoop FSGetchar: mov ax,0C07h ; keyflush & getchar int 21h cmp al,1Bh ; esc? je FSGCEsc ; exit fs mode call TxByte jmp FSLoop FSGCEsc: call TxByte ; send Esc! jmp FSExit FSOpen: lea di,DCFile call RecieveString ; get filename call RxPause ; get open mode mov ah,3dh ; open int 21h mov dx,ax call TxDx ; send handle jmp FSLoop FSCreate: lea di,DCFile call RecieveString ; get filename call RxDx ; get file attribute mov cx,dx lea dx,DCFile mov ah,3ch ; create int 21h mov dx,ax call TxDx ; send handle jmp FSLoop FSRead: call RxDx ; get handle mov bx,dx call RxCxDx ; get number of bytes mov LengthH,cx mov LengthL,dx RSRLoop: mov cx,BufferSize mov ax,LengthH or ax,ax jne RSRSkip cmp LengthL,cx jnc RSRSkip mov cx,LengthL RSRSkip: lea dx,FastBuffer mov ah,3fh ; read int 21h jc RSRDone or ax,ax je RSRDone xor cx,cx ; fs read reply with length 1st, high is zero mov dx,ax call TxCxDx mov cx,dx lea di,FastBuffer RSRUpload: mov al,[di] inc di call SafeTxByte dec cx cmp cx,0 jne RSRUpload sub LengthL,dx ; 32-bit subtract sbb LengthH,0 jmp RSRLoop RSRDone: mov cx,0 mov dx,0 call TxCxDx ; send a zero to mark end of transfer... jmp FSLoop FSWrite: call RxDx ; get handle mov bx,dx call RxCxDx ; get number of bytes mov LengthH,cx mov LengthL,dx RSWLoop: mov cx,BufferSize mov ax,LengthH or ax,ax jne RSWSkip cmp LengthL,cx jnc RSWSkip mov cx,LengthL mov dx,cx RSWSkip: cmp cx,0 je FSLoop ; nothing to transfer left lea di,FastBuffer RSWDownload: call SafeRxPause mov [di],al inc di dec dx cmp dx,0 jne RSWDownload lea dx,FastBuffer mov ah,40h ; write int 21h sub LengthL,ax ; 32-bit subtract sbb LengthH,0 jmp RSWLoop FSSeek: call RxDx ; get handle mov bx,dx call RxCxDx ; get position call SafeRxpause ; get parameter mov ah,42h int 21h jmp FSLoop FSClose: call RxDx ; get handle mov bx,dx mov ah,3eh int 21h jmp FSLoop FSDelete: lea di,DCFile call RecieveString ; get filename mov ah,41h ; delete int 21h jmp FSLoop FSRename: lea di,DCFile call RecieveString ; get filename lea di,DCFile2 call RecieveString ; get filename mov ah,56h ; rename int 21h jmp FSLoop FSWriteBlank: call RxDx ; get handle mov bx,dx call RxCxDx ; get number of bytes mov LengthH,cx mov LengthL,dx RSWBLoop: mov cx,BufferSize mov ax,LengthH or ax,ax jne RSWBSkip cmp LengthL,cx jnc RSWBSkip mov cx,LengthL mov dx,cx RSWBSkip: cmp cx,0 je FSLoop ; nothing to transfer left lea di,FastBuffer RSWBDownload: mov al,0 mov [di],al inc di dec dx cmp dx,0 jne RSWBDownload lea dx,FastBuffer mov ah,40h ; write int 21h sub LengthL,ax ; 32-bit subtract sbb LengthH,0 jmp RSWBLoop SerialInc: include serial.inc db 0 dw 0 Start endp cseg ends end Start