;*** TURBO PASCAL version 3.01 A source code ;*** ;*** commented by Pascal Dornier ;*** all rights reserved ;"*** cseg $100 ;"COM file... ; ;I/O port equates ; timerfrq = $0042 ;timer: frequency timercmd = $0043 ;timer: command timerflg = $0061 ;"PPI: sound enable ; ;interrupt numbers ; bioscrt = $0010 ;BIOS: CRT driver bioskbd = $0016 ;BIOS: KBD driver msdos = $0021 ;"MS-DOS entry ; ;variable definitions ; attnrm = $0000 ;attribute NormVideo attlow = $0001 ;attribute LowVideo att2 = $0002 ;attribute #2 (used by editor) att3 = $0003 ;attribute #3 txwinx1 = $0004 ;upper left edge current window txwiny1 = $0005 scrmod = $0006 ;video mode coltxt = $0007 ;color or text ? attcur = $0008 ;current attribute grmod = $0009 ;graphics mode grwinx1 = $000A ;graphics window: upper left edge grwinx2 = $000C grwiny1 = $000E ; bottom right edge grwiny2 = $0010 delaycnt = $0012 ;number of loop's for 1 ms collin = $0014 ;line color lnxdir = $0016 ;X direction lnydir = $0018 ;Y direction lnxpos = $001A ;X position lnypos = $001C ;Y position lndda = $001E ;DDA register grback = $0020 ;"graphics: background color ;heap pointer hpstrt = $0022 ;beginning of heap hpstrt1 = $0024 hpdstpt = $0026 ;^ destination pointer hpdstpt1 = $0028 hpesize = $002A ;size of entry to delete hpesize1 = $002C hplast = $002E ;^ previous entry hplast1 = $0030 hpmerg = $0032 ;length of entry to be merged hpmerg1 = $0034 ;"with next entry coninbuf = $0036 ;CON input buffer pnbuf0 = $00B5 pnbuf = $00B6 ;buffer for filename etc. pnbuf1 = $00B7 pnbuf2 = $00B8 pnbuf3 = $00B9 pndiratt = $00CB ;for Dir: file attribute pndirnm = $00D4 ;name of file pndirpad = $00E4 ;^ end for formatting pnbufend = $0135 ;"end of buffer ;I/O vectors vkbdstat = $0136 ;KBD stat (ConStPtr) vkbdget = $0138 ;KBD get (ConInPtr) vconput = $013A ;CON put (ConOutPtr) vprnput = $013C ;PRN put (LstOutPtr) vauxput = $013E ;AUX put (AuxOutPtr) vauxget = $0140 ;AUX get (AuxInPtr) vusrput = $0142 ;USR put (UsrOutPtr) vusrget = $0144 ;"USR get (UsrInPtr) ;file entries for std files filcon = $0146 ;CON, TRM filkbd = $014A ;KBD fillst = $014E ;LST filaux = $0152 ;AUX filusr = $0156 ;USR stdin = $015A ;MS-DOS input file stdinfl = $015C ;flag stdinof = $015E ;^ buffer stdinsz = $0160 ;buffer size stdout = $0166 ;MS-DOS output file stdoutfl = $0168 ;flag stdoutof = $016A ;^ buffer stdoutsz = $016C ;"buffer size modeflg = $0172 ;option flag - see initmem spval = $0174 ;SP on initialisation turbocs = $0176 ;CS for return to Turbo turbods = $0178 ;DS for return to Turbo filtabpt = $017A ;^ into list of open files filemax = $017C ;max number of open files verror = $017E ;ErrorPtr errnum = $0180 ;error number conbufln = $0181 ;BufLen (for ReadLn) conbufpt = $0182 ;^ into input buffer conbfend = $0184 ;end of input buffer errpos = $0186 ;return address -> errpos2 = $0188 ;position of error hptop = $018A ;HeapPtr: ^ end of heap hptop1 = $018C svintv = $018E ;buffer for vector: svintv1 = $0190 ;DIV/0 interrupt lastkey = $0192 ;code of last key pressed cbreak = $0194 ;CBreak ovrpnbuf = $0196 ;"buffer for overlay filename fmtfield = $01E6 ;formatting: field size fmttype = $01E7 ;type of conversion fmtsdst = $01E8 ;^ dest string (STR) fmtsdst1 = $01EA fmtvdst = $01EC ;^ dest var (VAL) fmtvdst1 = $01EE fmtpdst = $01F0 ;^ error var (VAL) fmtpdst1 = $01F2 recvbuf = $01F4 ;"real buffer: number to convert errio = $01FA ;flag: return because of error rndseed = $01FC ;random seed: last random number rndseed1 = $01FE strdstln = $0200 ;string operations: max. length of result strpos = $0202 ;Pos strnum = $0204 ;Num strtrgt = $0206 ;^ dest string strtrgt1 = $0208 strobj = $020A ;^ object string strobj1 = $020C ;" remul11 = $020E ;real arithmetics remul11a = $020F ;first number * / remul12 = $0210 remul13 = $0212 remul21b = $0213 remul21 = $0214 ;second number * / remul21a = $0215 remul22 = $0216 remul23 = $0218 retrc1 = $021A ;number for Sqrt, ArcTan, polynomials retrc2 = $021C retrc3 = $021E resign = $0220 ;sign for + - resave = $0221 remant = $0222 ;mantissa + - remant1 = $0223 ;" cvdecexp = $0224 ;real -> ASCII: decimal exponent cvexpcnt = $0225 ;ASCII -> real: counter for exponent cvoutbuf = $0226 ;output buffer for result currfil = $0232 ;^ current file var currfil1 = $0234 filfunc = $0238 ;function code file operation filerr = $0239 ;error code, if failure prnum = $023A ;real: number to print filetab = $0240 ;"table of open files (file handles) ;kernel variables freemem = $0260 ;free memory (paragraphs) stackseg = $0262 ;stack segment on start stackpt = $0264 ;stack pointer destseg = $0266 ;segment of compiled program codesize = $0268 ;code size (paragraphs) datasize = $026A ;data size (paragraphs) minstksz = $026C ;min size stack + heap mincssz = $026E ;min size CS mindssz = $0270 ;min size DS minhpsz = $0272 ;min size free heap maxhpsz = $0274 ;max size free heap txbeg = $0276 ;^ beginning of text txend = $0278 ;^ end of text txmemend = $027A ;^ end of text memory txerrpos = $027C ;^ error in text vfilbig = $027E ;vector: file too big vnewfil = $0280 ;vector: file not found txcomp = $0282 ;0 = text not translated cpmode = $0283 ;(0 memory, 1 find error, 2 COM, 3 CHN) cperr = $0284 ;compiler's error number txchg = $0285 ;0 = text not changed defdrv = $0286 ;number of default drive scrpn = $0287 ;buffer for filename processing scrpnend = $02C6 ;end of buffer workpn = $02C7 ;filename work file mainpn = $0307 ;filename main file mainflg = $0347 ;0 = work file used msgflg = $0348 ;0 = error messages not read codedest = $0349 ;(1 = memory, 2 = COM, 3 = CHN) parmlin = $034A ;buffer: input line for program knumbuf = $0386 ;number output buffer curatt = $038E ;"number current video attribute ;editor variables srend = $0390 ;^ block end for search srbeg = $0392 ;^ block beg for search bkbeg = $0394 ;^ block beg bkend = $0396 ;^ block end lnupper = $0398 ;^ line above disbeg = $039A ;^ beginning of text displayed oldpos = $039C ;old position eolpos = $039E ;^ end of line srpos = $03A0 ;current search pos srcnt = $03A2 ;search counter horscr = $03A4 ;horizontal scrolling attflg = $03A5 ;(1 = block beg, 2 = block end in curr line) phrow = $03A6 ;cursor position phcol = $03A7 statobs = $03A8 ;0 = invalid status line edcol = $03A9 ;column attchg = $03AA ;FF = attribute changes in curr line sropt = $03AB ;options for search ; 1=entire words, 2=replace without query ; 4=upper = lower, 8=global ;10=backwards 20=L (?) srmode = $03AC ;0=search, FF=search and replace editflg = $03AD ;? never referenced ! bkhide = $03AE ;FF = invisible block scrfl1 = $03AF ;FF = short redisplay statera = $03B0 ;# chars to delete in status line oldlen = $03B1 ;old length curr line dislin = $03B2 ;redisplay from line ... overflg = $03B3 ;0 = overwrite, FF = insert indntflg = $03B4 ;0 = normal, FF = indent disflg = $03B6 ;FF = don't display scrfl2 = $03B7 ;redisplay: 0 = small displacement bkbegl = $03BA ;^ block beg in curr line bkendl = $03BC ;^ block end in curr line edpos = $03BE ;^ current line lnpos = $03C0 ;pos in line buffer posfifo = $03C2 ;old position for ^QP pfifosrc = $03C5 qppos = $03C6 qppos1 = $03C8 pfifodst = $03C9 ;(for block transfer) cmdbuf = $03CA ;buffer for command entry cmdbuf1 = $03CB srword = $03CE ;max length of search word srword1 = $03CF ;length srword2 = $03D0 ;string srrepl = $03EF ;replace word srrepl1 = $03F0 srrepl2 = $03F1 stopt = $0410 ;options for search / replace sropt1 = $0411 fnbuf = $041D ;buffer for filename entry fnbuf2 = $041F fnbufend = $0460 nbkbeg = $0461 ;block transfer destination nbk = $0463 ;block sepptr = $0465 ;^ word separator table explen = $0467 ;expected length curpast = $0469 ;1 = cursor past end of line line0 = $046B line = $046C ;buffer: current line lineend0 = $04E9 lineend1 = $04EA lineend = $04EB dmabuf = $04EE ;buffer for redisplay scrseg = $0590 ;segment of video memory scrrow = $0592 ;video row scrbad = $0593 ;"FF = snowy screen ;compiler variables spsav = $0594 ;SP at start symtop = $0596 ;current end of symbol table symtop2 = $0598 ;end of symbol table ptcbeg = $059A ;^ beg symbol table, patch list tyfence = $059C ;limit for undefined pointer types fence = $059E ;limit for search on new definition pc = $05A0 ;PC of emitted code dc = $05A2 ;data offset of emitted code varspc = $05A4 ;space used on stack cdptr = $05A6 ;^ into code buffer cdbufpt = $05A8 ;PC of beg code buffer cdbegpt = $05AA ;^ code buffer cdfoff = $05AC ;buffer's offset in file cdprcoff = $05AD ;offset for overlay cdfoff1 = $05AE lincnt = $05B0 ;line counter cdinval = $05B2 ;<> 0: invalid code recnum = $05B3 ;number of current record reccnt = $05B4 ;record counter scalcnt = $05B5 ;enumeration type counter srcend = $05B6 ;<> 0: end of source reached lexnest = $05B7 ;lexical nesting flgpshax = $05B8 ;<> 0: save AX on stack flgpshes = $05B9 ;<> 0: save ES on stack flgpshdi = $05BA ;<> 0: save DI on stack usrint = $05BB ;<> 0: user interrupt used ovrcnt = $05BC ;overlay counter inclflg = $05BD ;FF = include file used cmaxfil = $05BF ;max number of open files cinpsize = $05C1 ;size of std input buffer coutsize = $05C3 ;size of std output buffer direct = $05C5 ;compiler directives: ; 1 = I/O check ; 2 = range check ; 4 = I/O mode (CON or TRM) ; 8 = value for CBreak ;10 = user interrupt ;20 = stack check ;40 = type check ;80 = device check destpn = $05C7 ;object filename destpne = $0603 dstfile = $0607 ;object file handle ptctop = $0609 ;current end of patch list ptcend = $060B ;limit for patch list srcptr = $060D ;^ into text srclnbeg = $060F ;^ beg of source line chptr = $0611 ;^ into line buffer ;variable entry 1: indflg = $0615 ;<> 0: indexed var indptflg = $0616 ;<> 0: indirect via pointer varseg = $0617 ;segment (FF=DS, FE=CS, FD=ES, else: ;lexical nesting varofs = $0618 ;variable offset vartp = $061A ;type varctp = $061C ;element type varnest = $061D ;<>0: record #, FF: undef pointer lower = $061E ;lower bound or ^ index type upper = $0620 ;upper bound or ^ element type varsize = $0622 ;variable size parm1end = $0624 parm2 = $0625 ;variable entry 2 var2ctp = $062C ;type lower2 = $062E ;lower bound upper2 = $0630 ;upper bound var2size = $0632 ;size maxsize = $0634 ;max size for variant records uncrlink = $0636 ;link for uncrunch list flgvar = $0638 ;F = VAR parameter vrecflg = $0639 ;number of record variant procfnc = $063A ;procedure or function ovrproc = $063B ;<>0: overlay procedure absflg = $0647 ;FF = Absolute variable var3ofs = $0648 ;offset var3seg = $064A ;segment ovrlen = $064C ;max length of overlay procedures in a file creal1 = $064E ;buffer for real constant creal2 = $0650 creal3 = $0652 cresign = $0653 stklev = $0654 ;stack use (WITH, FOR, display) casectp = $0655 ;CASE element type direcsv = $0656 ;directives at beg of statement brnchop = $0658 ;branch op on comparision rdlnflg = $0659 ;flag: Read / ReadLn forptr = $065A ;pointer for FOR: TO / DOWNTO withnest = $065C ;WITH nesting inlinflg = $065D ;inline flag withtab = $065E ;WITH table: record number, segment withtab1 = $0660 ;offset, FFFF = indexed functp = $069E ;^ result type comptp = $06A0 ;^ type for comparison oldpc = $06A2 ;PC before translation of this atom negflg = $06A4 ;negation flag exres = $06A6 ;integer constant cxbuf = $06A8 ;buffer for CX direcin = $06AA ;directives before include semiflg = $06AC ;flag for missing ; error wordflg = $06AD ;type of word read typept = $06AE ;^ type sympos = $06B0 ;^ into symbol table wrdend = $06B2 ;end of word read retbuf = $06B4 ;buffer for return address inclpn = $06B6 ;include filename incfile = $06F6 ;include file handle bufpt = $06F8 ;include pointer bufend = $06FA ;end of include buffer srclnbg = $06FC ;beg of line in buffer frelpos = $06FE ;relative position in file ptcbuf1 = $0700 ;buffer for patch wordbuf = $0702 ;buffer for word, filename, string... wrdbuf1 = $0703 inclbuf = $0782 ;include buffer txstrt = $0802 ;"beg of text space / error messages JMP start ;"jump to main code B $90,$90,$CD,$AB B "Copyright (C) 1985 BORLAND Inc" B $02,$04,$00 W ecmd1 ;ptrs for TINST.COM B $00 W errpath B $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 B $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 B $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 displstr B $14,"Default display mod" B $65 txwinx2 B $50 ;lower edge of text window txwiny2 B $19 B $01,$FF,$FF attmono B $0F,$07,$07,$70 ;monochrome attributes attbwgr B $0F,$07,$07,$70 ;mono graphic atts attcolgr B $0E,$07,$07,$4F ;"color graphic atts putstr CS: ;put attribute string MOV.B AH,[BX] ;length OR.B AH,AH STC JZ puts2 ;nothing to put putstrl INC BX ;next char CS: MOV.B AL,[BX] ;get it PUSH AX ;save cnt CALL conput ;put CRT POP AX DEC.B AH ;another one ? JNZ putstrl ;:yes CLC puts2 RET ;" meascnt W $0000 measdone B $00 vtimer W $0000 ;"space for timer int vector vtimer1 W $0000 msspeed MOV delaycnt,#$006E ;measure CPU speed CS: ;measurement value MOV.B measdone,#$00 ;flag:not done MOV SI,#timvec ;ptr to timer INT ES: MOV AX,[SI] CS: MOV vtimer,AX ;save it ES: MOV AX,[SI]$02 CS: MOV vtimer1,AX CLI ES: MOV [SI],#msint1 ES: MOV [SI]$02,CS STI ;INT ok again JMP.b mssploop ;"measurement loop msint1 PUSH DS ;first INT entry PUSH AX XOR AX,AX MOV DS,AX MOV timvec,#msint2 ;set second vector CS: MOV meascnt,AX ;clear counter POP AX POP DS CS: JMPF [vtimer] ;"do timer routine msint2 CS: ;second INT entry MOV.B measdone,#$FF ;set flag:done CS: JMPF [vtimer] ;"do timer routine mssploop CALL delay1ms ;wait one step CS: INC meascnt ;count those steps CS: CMP.B measdone,#$FF ;done ? JNZ mssploop ;no, continue counting CS: MOV AX,vtimer1 ;restore timer INT vec CLI ES: MOV [SI]$02,AX CS: MOV AX,vtimer ES: MOV [SI],AX STI ;INT ok again CS: MOV AX,meascnt ;number of steps done ADD AX,AX ;*2 MOV delaycnt,AX ;-> result RET ;" delaybx MOV AX,BX ;Delay(BX) xdelay MOV CX,AX ;DELAY(AX) JCXZ delay2 ;:no delay delay1 CALL delay1ms ;delay 1ms LOOP delay1 delay2 RET ;" delay1ms PUSH CX ;Delay 1 ms MOV CX,delaycnt ;get count for 1ms delay3 LOOP delay3 ;do it POP CX ;restore cnt RET ;" xclrscr PUSH BP ;CLRSCR MOV AH,#$0F ;get screen stat INT bioscrt POP BP CMP.B AL,scrmod ;= current screen mode ? JZ clrscr1 ;:ok MOV AL,scrmod ;no: do set it JMP xtxtmode ;' clrscr1 PUSH BP MOV AX,#$0600 ;scroll window up, 0 lines MOV.B BH,attcur MOV CX,txwinx1 ;upper left edge CS: MOV DX,txwinx2 ;lower right edge DEC.B DH DEC.B DL INT bioscrt ;clear window MOV AH,#$02 ;set cursor position MOV DX,txwinx1 ;upper left edge XOR.B BH,BH INT bioscrt ;do it POP BP RET ;" xdelline PUSH BX ;DelLine PUSH CX PUSH DX PUSH BP CALL getcpos ;get cursor pos MOV AH,#$06 ;scroll window up doscroll MOV AL,#$01 ;one line MOV.B BH,attcur MOV.B CH,DH MOV.B CL,txwinx1 ;upper left edge CS: MOV DX,txwinx2 ;lower right of window DEC.B DH DEC.B DL CMP.B CH,DH ;same ? JNZ dellin1 ;:no XOR.B AL,AL ;no lines dellin1 INT bioscrt ;do it POP BP POP DX POP CX POP BX RET ;" xinsline PUSH BX ;InsLine insline2 PUSH CX PUSH DX PUSH BP CALL getcpos ;get cursor pos MOV AH,#$07 ;scroll window down JMP doscroll ;"as above xlowvid PUSH AX ;LowVideo MOV AL,attlow ;set low attribute MOV attcur,AL POP AX RET ;" xnormvid PUSH AX ;NormVideo, HighVideo MOV AL,attnrm ;set normal attribute MOV attcur,AL POP AX RET ;" getcpos MOV AH,#$03 ;get cursor position XOR.B BH,BH ;page 0 INT bioscrt ;do it RET ;" xclreol PUSH BX ;ClrEol PUSH CX PUSH DX PUSH BP CALL getcpos ;get cursor pos MOV AX,#$0600 ;clear window MOV.B BH,attcur MOV CX,DX ;pos -> upper left CS: MOV.B DL,txwinx2 ;X-position DEC.B DL ;Y-pos from current pos INT bioscrt ;do it POP BP POP DX POP CX POP BX RET ;" xcrtinit CALL xnosound ;CrtInit CS: ;Screen mode MOV AL,scrmodch ;defined with TINST CMP AL,#$FF JNZ xtxtmode ;do change it PUSH BP MOV AH,#$0F ;get current screen mode INT bioscrt POP BP xtxtmode MOV.B txwinx1,#$00 ;TextMode MOV.B txwiny1,#$00 ;set window MOV.B grmod,#$FF ;no graphics mode CMP AL,#$07 ;monochrome ? MOV BH,#$50 MOV BL,#$00 MOV SI,#attmono ;ptr to screen attributes JZ txtmd3 ;:yes, mono MOV SI,#attcolgr CMP AL,#$02 ;BW80 ? JZ txtmd2 ;:yes CMP AL,#$04 JB txtmd1 ;:C80, C40, BW40 MOV AL,#$03 txtmd1 MOV BL,#$FF CMP AL,#$03 ;C80 ? JZ txtmd3 ;:yes MOV BH,#$28 CMP AL,#$01 ;C40 ? JZ txtmd3 ;:yes XOR.B AL,AL ;monochrome MOV BL,#$00 txtmd2 MOV SI,#attbwgr txtmd3 MOV scrmod,AL ;set screen mode MOV.B coltxt,BL ;color or mono CS: MOV.B txwinx2,BH ;set screen size CS: MOV AX,[SI] ;get screen attributes MOV attnrm,AX CS: MOV AX,[SI]$02 MOV att2,AX PUSH BP MOV AH,#$0F ;get screen status INT bioscrt CMP.B AL,scrmod ;correct mode ? JZ txtmd4 ;:yes MOV AL,scrmod XOR.B AH,AH ;set screen mode INT bioscrt txtmd4 POP BP JMP xnormvid ;" xcrtexit RET ;"CrtExit setcpos PUSH AX ;Set cursor position PUSH BX ;DL=row PUSH CX ;DH=col PUSH DX ;pos relative to curr window PUSH SI PUSH DI PUSH BP PUSHF XCHG.B DL,DH ADD DX,txwinx1 ;add window pos CS: CMP.B DH,txwiny2 ;over edge of screen ? JNB setcbad ;:yes CS: CMP.B DL,txwinx2 JNB setcbad ;:yes MOV AH,#$02 ;set cursor XOR.B BH,BH ;page 0 INT bioscrt setcbad POPF POP BP POP DI POP SI POP DX POP CX POP BX POP AX RET ;" xupcase JMP upcase ;"UpCase xwherex CALL getcpos ;WhereX MOV.B AL,DL ;get cursor pos SUB.B AL,txwinx1 ;col-window col INC.B AL ;+1 XOR.B AH,AH RET ;" xwherey CALL getcpos ;WhereY MOV.B AL,DH ;get cursor pos SUB.B AL,txwiny1 ;row-window row INC.B AL ;+1 XOR.B AH,AH RET ;" xwindow POP BX ;Window CMP AL,#$19 ;Row 2 - limit to 25 JA window1 ;:too much CS: MOV txwiny2,AL ;set it window1 POP AX ;Col 2 CMP AL,#$50 ;limit to 80 JA window2 ;:too much CS: MOV txwinx2,AL ;set it window2 POP AX ;Row 1 CS: CMP.B AL,txwiny2 ;> row 2 ? JNB window3 ;: no good DEC.B AL MOV txwiny1,AL ;set it window3 POP AX ;Col 1 CS: CMP.B AL,txwinx2 ;> col 2 JNB window4 ;:no good DEC.B AL MOV txwinx1,AL ;set it window4 JMP BX ;"return xtxtcol AND AL,#$1F ;TextColor TEST AL,#$10 ;Blink ? JZ txtcol1 ;:no AND AL,#$0F OR AL,#$80 ;set blink flag txtcol1 AND.B attcur,#$70 OR.B attcur,AL ;set new attribute RET ;" xtxtbg AND AL,#$07 ;TextBackground MOV CL,#$04 SHL.B AL,CL AND.B attcur,#$8F OR.B attcur,AL ;set attribute RET ;" setgmod PUSH BP ;Set graphic mode MOV grwinx2,AX ;X-size MOV grwinx1,#$0000 ;clear window MOV grwiny1,#$0000 MOV grwiny2,#$00C7 ;Y-size = 199 MOV AL,grmod XOR.B AH,AH INT bioscrt ;set graph mode XOR BX,BX MOV.B grback,BL ;clear background MOV AH,#$0B ;set palette -> backgrnd INT bioscrt INC.B BH ;set foregrnd MOV AH,#$0B INT bioscrt ;set palette POP BP RET ;" xgrcolmd MOV.B grmod,#$04 ;GraphColorMode setgmod2 MOV AX,#$013F ;X-size = 319 JMP setgmod ;'set it xgrmode MOV.B grmod,#$05 ;GraphMode JMP setgmod2 ;"set it xhires MOV.B grmod,#$06 ;Hires MOV AX,#$027F ;X-size = 639 CALL setgmod ;set it MOV AX,#$000F ;set background JMP.b xhirscol ;" xgrbg AND AL,#$0F ;GraphBackground MOV.B AH,grback ;get old color AND.B AH,#$10 OR.B AL,AH MOV grback,AL ;store it setbg PUSH BP ;set graph background XOR.B BH,BH MOV.B BL,grback MOV AH,#$0B ;set palette INT bioscrt ;do it POP BP RET ;" xpalette PUSH BP ;set palette AL MOV.B BL,grback ;get current color AND.B BL,#$EF ;clear palette MOV AH,#$02 CMP.B grmod,#$04 ;color graphics ? JZ setpal1 ;yes MOV AH,#$01 setpal1 CMP.B AL,AH JB setpal2 SUB.B AL,AH ;upper bit: part of backgnd OR.B BL,#$10 setpal2 MOV.B grback,BL ;set it MOV BH,#$01 ;set palette MOV.B BL,AL ;palette number MOV AH,#$0B INT bioscrt ;do it POP BP JMP setbg ;"set backgnd color xhirscol PUSH BP ;HiresColor MOV BX,AX ;as background MOV AH,#$0B ;set palette INT bioscrt ;do it POP BP RET ;" xgrwindw POP BX ;GraphWindow MOV CX,#$027F ;max. X = 639 CMP.B grmod,#$06 ;Hires ? JZ gwind1 ;:yes MOV CX,#$013F ;max. X = 319 gwind1 CMP AX,#$00C7 ;Y2 > 199 JA gwind2 ;:no good MOV grwiny2,AX ;set Y2 gwind2 POP AX ;X2 CMP AX,CX ;> max X ? JA gwind3 ;:no good MOV grwinx2,AX ;set X2 gwind3 POP AX ;Y1 CMP AX,grwiny2 ;>= Y2 ? JNB gwind4 ;:no good MOV grwiny1,AX ;set Y1 gwind4 POP AX ;X1 CMP AX,grwinx2 ;>= X2 ? JNB gwind5 ;:no good MOV grwinx1,AX ;set X1 gwind5 JMP BX ;"return xplot POP BX ;Plot POP DX ;Y-pos POP CX ;X-pos PUSH BX ;restore return addr MOV AH,#$0C ;set point, AL is color doplot OR CX,CX ;test X-pos (do clipping) JS noplot ;negative: clip it ADD CX,grwinx1 ;add window offset CMP CX,grwinx2 ;outside window ? JA noplot ;yes: clip it OR DX,DX ;test Y-pos JS noplot ;negative: clip it ADD DX,grwiny1 ;add window offset CMP DX,grwiny2 ;outside window ? JA noplot ;yes: clip it PUSH BP INT bioscrt ;do plot POP BP noplot RET ;" xdraw MOV AH,#$0C ;Line. AL is color MOV collin,AX ;set color, command:plot POP DI ;return addr POP AX ;Y2 POP DX ;X2 POP BX ;Y1 MOV lnypos,BX ;store it CALL getdelta ;calculate direction MOV lnydir,CX ;store it CALL iabs ;ABS(AX) XCHG AX,DX ;DX:=Y-distance YD POP BX ;X1 PUSH DI ;restore ret addr MOV lnxpos,BX ;store X1 CALL getdelta ;calculate direction MOV lnxdir,CX ;store it CALL iabs ;ABS(AX) MOV BX,AX ;BX:=X-distance XD CMP BX,DX ;XD <= YD ? JLE lnyline ;yes:Y-oriented line MOV AX,DX ;X-oriented line ADD AX,AX SUB AX,BX MOV lndda,AX ;DDA:=YD+YD-XD MOV CX,BX ;XD -> count INC CX lnxloop CALL lnplot ;plot point with clipping MOV AX,lndda ;test DDA OR AX,AX JLE lnxnostp ;:no step ADD AX,DX ;DDA:=DDA+YD+YD-XD-XD ADD AX,DX SUB AX,BX SUB AX,BX MOV lndda,AX MOV AX,lnydir ;Ypos:=Ypos+Ydir ADD lnypos,AX JMP.b lnxcont ;' lnxnostp ADD AX,DX ;DDA:=DDA+YD+YD; ADD AX,DX MOV lndda,AX lnxcont MOV AX,lnxdir ;Xpos:=Xpos+Xdir ADD lnxpos,AX LOOP lnxloop ;another step RET ;' lnyline MOV AX,BX ;Y-oriented line ADD AX,AX SUB AX,DX MOV lndda,AX ;DDA:=XD+XD-YD MOV CX,DX ;YD -> count INC CX lnyloop CALL lnplot ;plot point with clipping MOV AX,lndda ;test DDA OR AX,AX JLE lnynostp ;:no step ADD AX,BX ;DDA:=DDA+XD+XD-YD-YD ADD AX,BX SUB AX,DX SUB AX,DX MOV lndda,AX MOV AX,lnxdir ;Xpos:=Xpos+Xdir ADD lnxpos,AX JMP.b lnycont ;' lnynostp ADD AX,BX ;DDA:=DDA+XD+XD ADD AX,BX MOV lndda,AX lnycont MOV AX,lnydir ;Ypos:=Ypos+Ydir ADD lnypos,AX LOOP lnyloop ;:another one RET ;" getdelta XOR CX,CX ;calculate direction -> CX SUB AX,BX ;compare them JZ deltazer ;equal: CX=0 JS deltaneg ;:negative INC CX ;positive: CX=1 RET ;' deltaneg DEC CX ;negative: CX=-1 deltazer RET ;" lnplot PUSH CX ;Set line point with clipping PUSH DX ;save count, YD MOV AX,collin ;color, command MOV CX,lnxpos ;Xpos MOV DX,lnypos ;Ypos CALL doplot ;plot that point POP DX POP CX RET ;" xsound MOV BX,AX ;Sound MOV AX,#$34DD ;for frequency calculation MOV DX,#$0012 CMP DX,BX ;frequency < 12 Hz ? JNB sounddis ;:might damage speaker DIV BX ;calculate timer value MOV BX,AX IN AL,timerflg ;sound on ? TEST AL,#$03 JNZ soundon ;:yes OR AL,#$03 ;switch it on OUT timerflg,AL MOV AL,#$B6 ;set frequency OUT timercmd,AL soundon MOV.B AL,BL ;set freq lo OUT timerfrq,AL MOV.B AL,BH ;set freq hi OUT timerfrq,AL sounddis RET ;" xnosound IN AL,timerflg ;NoSound AND AL,#$FC ;switch it off OUT timerflg,AL RET ;" xgetmem XCHG AX,CX ;GetMem, AX=length requested POP BX ;ret addr POP DI ;dest ptr JMP.b new1 ;"like New hpconv PUSH AX ;change representation: PUSH CX ;AX=ofs 0..15, BX=seg MOV CL,#$04 SHR AX,CL ADD BX,AX ;seg:=seg+ofs DIV 16 POP CX POP AX AND AX,#$000F ;ofs:=ofs MOD 16 RET ;" hpcmp CMP BX,DX ;Compare BX:AX with DX:CX JNZ hpcmp1 CMP AX,CX hpcmp1 RET ;" hpadd ADD AX,CX ;BX:AX + DX:CX -> BX:AX ADD BX,DX JMP hpconv ;"change representation hplen ES: ;Get length of entry MOV AX,[DI]$04 ES: MOV BX,[DI]$06 PUSH AX OR AX,BX ;test if end of heap = 0 POP AX RET ;" xnew POP BX ;New new1 POP ES ;dest ptr PUSH BX ;restore ret MOV hpdstpt,DI ;save addr dest ptr MOV hpdstpt1,ES MOV AX,CX ;number of bytes wanted ADD AX,#$0007 ;+7 MOV BX,#$1000 ;carry ? JB new2 ;:yes XOR BX,BX ;no carry new2 AND AL,#$F8 ;space allocated is n*8 CALL hpconv ;convert to seg,ofs MOV CX,AX ;needed size MOV DX,BX MOV hplast,#$0022 ;last entry MOV hplast1,DS LES DI,hpstrt ;get start of heap newseek CALL hplen ;get len of entry JZ newend ;:end of heap CALL hpcmp ;sufficient size ? JNB newfnd ;:large enough MOV hplast,DI ;remember last entry MOV hplast1,ES ES: ;get next entry LES DI,[DI] JMP newseek ;'continue searching newfnd CALL newdest ;store ES:DI to dest ptr JZ newfits ;equal - nothing to crunch SUB AX,CX ;calculate superfluous mem SBB BX,DX AND AX,#$000F JMP.b newrem ;'mark the remainder as free newfits ES: ;get next entry LES DI,[DI] JMP.b newlink ;'set link to it newend CALL newdest MOV AX,DI MOV BX,ES CALL hpadd ;sum up sizes MOV hptop,AX ;new heap top MOV hptop1,BX PUSH CX ;save size of entry PUSH DX MOV CX,AX ;test if heap overflow MOV DX,BX MOV AX,SP ;heap top - stack top MOV BX,SS SUB BX,#$0E CALL hpconv ;convert sp XOR AX,AX CALL hpcmp ;compare them POP DX POP CX JA newmemok ;:ok JMP chkstk1 ;'Error FF - memory overflow newmemok XOR AX,AX ;mark next entry XOR BX,BX ;as end of heap newrem PUSH BX ;save length PUSH AX ES: ;save ptr to next entry PUSH [DI]$02 ES: PUSH [DI] MOV AX,DI ;try to put together with MOV BX,ES ;next entry CALL hpadd ;calc end of this entry MOV DI,AX ;new top MOV ES,BX ES: ;now produce that entry POP [DI] ;link ES: POP [DI]$02 ES: POP [DI]$04 ;length ES: POP [DI]$06 newlink PUSH ES ;save ES PUSH ES LES SI,hplast ;store ES:DI in last ES: ;entry as link to next entry MOV [SI],DI ES: POP [SI]$02 POP ES ;restore ES RET ;" newdest PUSH ES ;store ES:DI in dest ptr PUSH ES LES SI,hpdstpt ES: MOV [SI],DI ES: POP [SI]$02 POP ES RET ;" xfreemem XCHG AX,CX ;FreeMem POP BX ;ret addr POP DI ;get ptr JMP.b disp1 ;'like Dispose xdispose POP BX ;Dispose disp1 POP ES ;get dest ptr PUSH BX ;restore ret MOV AX,CX ;number of bytes ES: MOV CX,[DI] ;get value of ptr ES: MOV DX,[DI]$02 ADD AX,#$0007 ;size+7 MOV BX,#$1000 ;carry ? JB disp2 ;:yes XOR BX,BX ;no carry disp2 AND AL,#$F8 CALL hpconv MOV hpesize,AX ;save size of MOV hpesize1,BX ;entry to erase LES DI,hpstrt ;start at the beginning MOV AX,DI MOV BX,ES CALL hpcmp ;= entry to erase ? JNB dispdel ;:no free space before dispseek ES: ;get link MOV AX,[DI] ES: MOV BX,[DI]$02 CALL hpcmp ;compare with our entry JNB dispfnd MOV DI,AX ;go to next entry MOV ES,BX JMP dispseek ;'continue dispfnd PUSH ES ;ES:DI last entry MOV SI,CX ;DX:CX searched one MOV ES,DX ;AX:BX current entry PUSH hpesize1 PUSH hpesize ES: ;store link in disposed entry MOV [SI],AX ES: MOV [SI]$02,BX ES: ;store length POP [SI]$04 ES: POP [SI]$06 POP ES ;restore ES ES: MOV [DI],CX ;store addr in last entry ES: MOV [DI]$02,DX ES: MOV AX,[DI]$04 ;get length of this entry ES: MOV BX,[DI]$06 CALL dispmerg ;try to put them together JZ dispdone ;:end of heap ES: ;get addr of next one LES DI,[DI] dispdone ES: ;get length of this entry MOV AX,[DI]$04 ES: MOV BX,[DI]$06 ES: ;get link of this entry MOV CX,[DI] ES: MOV DX,[DI]$02 JMP.b dispmerg ;'try to put them together dispdel MOV hpstrt,CX ;link to next entry MOV hpstrt1,DX MOV DI,CX ;ptr to this entry MOV ES,DX ES: ;store link to next one MOV [DI],AX ES: MOV [DI]$02,BX MOV CX,AX ;link for collect MOV DX,BX MOV AX,hpesize ;store its len MOV BX,hpesize1 ES: MOV [DI]$04,AX ES: MOV [DI]$06,BX ;try to merge contiguous entries - thus reducing ;fragmentation of the heap. dispmerg MOV hpmerg,AX ;length of this entry MOV hpmerg1,BX ADD AX,DI ;+ its address MOV BX,ES ADD BX,hpmerg1 CALL hpconv ;convert CALL hpcmp ;= next entry ? JNZ disprt ;no:cannot put them together MOV AX,hptop ;= heap top ? MOV BX,hptop1 CALL hpcmp JZ disptop ;yes:set new, lower heap top PUSH ES ;save ES MOV SI,CX ;addr of next entry MOV ES,DX ES: ;get link to next entry MOV AX,[SI] ES: MOV BX,[SI]$02 ES: ;get length MOV CX,[SI]$04 ES: MOV DX,[SI]$06 POP ES ;restore ES ES: ;store link MOV [DI],AX ES: MOV [DI]$02,BX MOV AX,hpmerg ;get length MOV BX,hpmerg1 CALL hpadd ;add them ES: ;store new length MOV [DI]$04,AX ES: MOV [DI]$06,BX XOR AX,AX RET ;' disptop MOV hptop,DI ;set new heap top MOV hptop1,ES PUSH DI ;clear 8 bytes XOR AX,AX ;= marker for end of heap CLD MOV CX,#$0004 REPZ STOS POP DI ;restore XOR AX,AX disprt RET ;" xmemavl XOR CX,CX ;MemAvail XOR DX,DX ;clear sum XOR SI,SI LES DI,hpstrt ;get heap start memav1 CALL hplen ;get length JZ memav2 ;:end of heap CALL hpaddcmp ;sum it up, test size ES: ;get next entry LES DI,[DI] JMP memav1 ;'continue memav2 MOV AX,SP ;last entry: free space MOV BX,SS ;between stack and heap SUB BX,#$10 ;leave some space CALL hpconv ;convert XOR AX,AX ;clear offset SUB BX,hptop1 ;subtract heap top JB memav3 ;:nothing left CALL hpaddcmp ;sum it up memav3 MOV AX,DX ;space left (paragraphs) RET ;" hpaddcmp CMP SI,BX ;is it the largest one ? JNB hpac2 ;:no MOV SI,BX ;yes, remember its size hpac2 CALL hpadd ;sum it up MOV CX,AX ;remember sum MOV DX,BX RET ;" xmaxavl CALL xmemavl ;MaxAvail: do MemAvail MOV AX,SI ;get largest size RET ;" xmark POP BX ;Mark POP ES ;get ptr MOV AX,hptop ;Heap top -> ptr ES: MOV [DI],AX MOV DX,hptop1 ES: MOV [DI]$02,DX JMP BX ;"return xrelease POP BX ;Release POP ES ;ptr addr ES: ;get pointer LES DI,[DI] MOV hptop,DI ;-> heap top MOV hpstrt,DI ;-> heap start MOV hptop1,ES MOV hpstrt1,ES XOR AX,AX ;clear 8 bytes in entry LES DI,hpstrt ;= marker for end of heap MOV CX,#$0004 CLD REPZ STOS JMP BX ;"return kbdstat CMP.B lastkey,#$00 ;Get key stat MOV AL,#$FF ;something there ? JNZ kbdst2 ;:true MOV AH,#$01 ;test kbd stat INT bioskbd MOV AL,#$00 ;false JZ kbdst2 ;:nothing available DEC.B AL ;true kbdst2 AND AX,#$0001 RET $0001 ;" kbdget MOV AL,lastkey ;Get KBD char MOV.B lastkey,#$00 ;clear last key code OR.B AL,AL JNZ kbdg3 ;:was full - take it XOR.B AH,AH ;get key INT bioskbd OR.B AL,AL ;test it JNZ kbdg2 ;:normal char MOV.B lastkey,AH ;store scan code MOV AL,#$1B ;return ESC OR.B AH,AH JNZ kbdg3 MOV AL,#$03 ;Break ! kbdg2 CMP.B cbreak,#$01 ;Break allowed ? JNZ kbdg3 ;:no CMP AL,#$03 ;Break ? JNZ kbdg3 ;:no JMP brkmsg ;' kbdg3 XOR.B AH,AH ;clear hi byte RET $0001 ;" crtput POP AX ;Print char to screen POP DX ;char to be printed PUSH AX ;restore ret PUSH DX ;save regs PUSH BP PUSH DX CALL getcpos ;get cursor pos POP AX ;char to be printed CMP AL,#$0D ;Carriage Return ? JNZ crtlf ;:no MOV.B DL,txwinx1 ;go to left margin JMP.b crtsetps ;'set new pos crtlf CMP AL,#$0A ;Line Feed ? JNZ crtbs ;:no INC.B DH ;add 1 to line CS: CMP.B DH,txwiny2 ;>= bottom ? JB crtsetps ;:no, set pos JMP.b crtscrol ;'scroll up crtbs CMP AL,#$08 ;Backspace ? JNZ crtbell ;:no CMP.B DL,txwinx1 ;at the left ? JZ crtsetps ;yes, no change DEC.B DL ;go back JMP.b crtsetps ;'set cursor pos crtbell CMP AL,#$07 ;Bell ? JNZ crtchar ;:no MOV AH,#$0E ;write char XOR.B BH,BH INT bioscrt JMP.b crttest ;'no pos change crtchar PUSH DX ;remember position - put char MOV AH,#$09 ;write char XOR.B BH,BH ;screen page 0 MOV CX,#$0001 ;1 char MOV.B BL,attcur ;current attribute INT bioscrt ;do it POP DX ;restore pos INC.B DL ;go right one char CS: CMP.B DL,txwinx2 ;= right margin ? JB crtsetps ;:no, set new pos MOV.B DL,txwinx1 ;go to the left INC.B DH ;next line CS: CMP.B DH,txwiny2 ;= bottom ? JB crtsetps ;no: set pos crtscrol DEC.B DH ;scroll up PUSH DX ;save pos MOV AX,#$0601 ;scroll up one line MOV.B BH,attcur ;att for empty line MOV CX,txwinx1 ;position upper left CS: MOV DX,txwinx2 ;position lower right DEC.B DH DEC.B DL INT bioscrt ;do it POP DX crtsetps MOV AH,#$02 ;set cursor pos XOR.B BH,BH ;screen 0 INT bioscrt ;do it crttest POP BP CMP.B cbreak,#$01 ;test for break ? JNZ crtnobrk ;:no DEC SP CALL kbdstat ;get key stat JZ crtnobrk ;:nothing DEC SP CALL kbdget ;get key CMP AL,#$13 ;^S ? JNZ crtnobrk ;:no DEC SP CALL kbdget ;get key crtnobrk POP AX ;restore char RET ;" lstput POP AX ;put to LST POP DX ;get char PUSH AX ;restore ret MOV AH,#$05 ;operation JMP.b dos ;'do MS-DOS NOP ;Courtesy of LINK auxput POP AX ;put to AUX POP DX ;get char PUSH AX ;restore ret MOV AH,#$04 ;operation JMP.b dos ;'do MS-DOS NOP auxget MOV AH,#$03 ;Get from AUX CALL dos ;do MS-DOS XOR.B AH,AH ;clear hi byte RET $0001 ;' dos CMP.B AH,#$3D ;do MS-DOS-operation JZ openfil ;:Open file CMP.B AH,#$3C JZ openfil ;:Create file CMP.B AH,#$3E JZ closfil ;:Close file CMP.B AH,#$80 JZ closeall ;:Close all files dodos PUSH BP ;save this INT msdos POP BP ;restore it RET ;' openfil PUSH SI ;put file into table of PUSH CX ;open files, open/create it MOV SI,filtabpt ;start of file table MOV CX,filemax openlp CMP [SI],#$00 ;empty ? JZ opendoit ;:yes INC SI INC SI LOOP openlp ;another one POP CX ;restore regs POP SI MOV AX,#$0004 ;Error: file not open STC RET ;' opendoit POP CX ;get offset to filename PUSH DS ;save DS PUSH ES ;ES -> DS POP DS CALL dodos ;open file POP DS ;restore DS JB openerr ;:error MOV [SI],AX ;file handle -> file list openerr POP SI ;restore RET ;" closfil PUSH CX ;Close file PUSH SI MOV SI,filtabpt ;start of file table MOV CX,filemax closlp CMP [SI],BX ;is it this file ? JNZ clsother ;:no MOV [SI],#$0000 ;clear its entry clsother INC SI ;next one INC SI LOOP closlp ;:not yet done POP SI ;restore regs POP CX JMP dodos ;'do it closeall MOV SI,filtabpt ;Close all files MOV CX,filemax clall1 MOV BX,[SI] ;test all file handles OR BX,BX JZ clall2 ;:not open MOV AH,#$3E ;close file CALL dodos ;do it MOV [SI],#$0000 ;store a 0: closed clall2 INC SI ;next one INC SI LOOP clall1 ;:continue RET ;" initio XOR AX,AX ;Init files, I/O initiofl MOV modeflg,AX ;clear flag MOV DI,#filetab ;set pt to file tab MOV filtabpt,DI MOV filemax,CX ;CX=max number of open files XOR AX,AX ;clear file list PUSH DS ;DS -> ES POP ES CLD REPZ STOS MOV ES,AX ;segment 0: ES: MOV verrhnd,#errhndl ;set vector: ES: ;error handler MOV verrhnd1,CS CALL msspeed ;measure CPU speed reinit1 MOV.B cbreak,#$00 ;no test for break reinit2 MOV SI,#inittab ;transfer vectors into table MOV DI,#vkbdstat PUSH DS ;DS -> ES POP ES PUSH CS ;CS -> DS POP DS MOV CX,#$001E ;count CLD REPZ ;move it MOVS PUSH ES ;restore DS POP DS XOR AX,AX ;clear vars MOV lastkey,AX ;no key stored MOV errnum,AL ;no error MOV conbufpt,AX ;no con buf MOV conbfend,AX MOV.B conbufln,#$7E MOV.B coninbuf,#$0D ;mark end of buffer RET ;" inittab W kbdstat,kbdget,crtput,lstput,auxput,auxget,crtput,kbdget W $FFFF,$00C1,$FFFF,$0082,$FFFF,$0043,$FFFF,$00C4,$FFFF W $00C5,$FFFF,$00C1,$0000,$0000,$0000,$0000,$FFFF,$00C1 W $0000,$0000,$0000,$0000 ;" errhndl IRET ;"Error handler conput PUSH BX ;put to CON PUSH CX ;save registers PUSH DX PUSH DI PUSH SI XOR.B AH,AH PUSH AX ;char to put CALL [vconput] ;put it conret POP SI ;restore regs POP DI POP DX POP CX POP BX RET ;" keyget PUSH BX ;Get from KBD PUSH CX ;save regs PUSH DX PUSH DI PUSH SI DEC SP CALL [vkbdget] ;do it JMP conret ;"restore prints PUSH BP ;Print inline string MOV BP,SP XCHG BX,[BP]$02 ;return addr -> BX prsl CS: MOV.B AL,[BX] ;get char INC BX ;go to next one OR.B AL,AL ;test it JZ prsend ;0:end CALL conput ;put to CRT JMP prsl ;'continue prsend XCHG BX,[BP]$02 ;restore ret to pos after text POP BP RET ;" xwriteln CALL prints ;Writeln CRT B $0D,$0A,$00 ;print string: CR,LF RET ;" upcase CMP AL,#$61 ;UpCase. < a ? JB upcas1 ;:not lower case CMP AL,#$7A ;> z ? JA upcas1 ;yes:not lower case SUB AL,#$20 ;change to upper upcas1 RET ;" whexword PUSH AX ;Write Hex number: save it MOV.B AL,AH ;do hi byte CALL whexbyte ;do it POP AX ;restore lo byte whexbyte PUSH AX ;write hex byte: save low nibble ROR.B AL,1 ;get hi nibble ROR.B AL,1 ROR.B AL,1 ROR.B AL,1 CALL whexnib ;do digit POP AX ;get lo nibble whexnib AND AL,#$0F ;mask it ADD AL,#$90 ;convert to hex - tricky DAA ADC AL,#$40 DAA JMP conput ;"now print it limstind OR.B AH,AH ;limit string index JZ limst1 ;:ok STC ;hi <> 0: error MOV AX,#$0000 ;clear it JS limst1 ;negative:0 DEC.B AL ;+:255 limst1 RET ;" ;Init Memory - with inline parms: ;+ 0:mode flag ; 1=direct mode; 2=no device checking; ; 4=test for break; 8=set breakpoint interrupt ;+ 2:CS for returning to Turbo ;+ 4:DS for returning to Turbo ;+ 6:CS size ;+ 8:DS size ;+ A:heap, stack size ;+ C:max. heap, stack size ;+ E:max. number of open files ;+10:size of std input buffer ;+12:size of std output buffer initmem CALL readvers ;Init memory - with inline parms POP SI ;ret addr MOV AX,CS ;calculate segments CS: ADD AX,[SI]$06 ;+CS size CS: ADD AX,[SI]$08 ;+DS size CS: ADD AX,[SI]$0A ;+heap, stack size CS: CMP AX,availmem ;> available memory ? JBE memin1 ;:no JMP memerr ;'Not enough memory memin1 MOV BX,CS ;CS + CS size -> DS CS: ADD BX,[SI]$06 MOV DS,BX CS: ;DS + DS size -> beg of free mem ADD BX,[SI]$08 CS: MOV DX,availmem SUB DX,BX ;how much is left ? CS: CMP DX,[SI]$0C ;> max size ? JB memin2 ;:no CS: MOV DX,[SI]$0C ;limit to max size memin2 MOV DI,DX ;DI: heap size MOV AX,#$FFFE ;value for full stack SUB DX,#$1000 ;64 K free ? JNB memin3 ;:yes MOV AX,DX ;calculate stack size -> AX ADD AX,#$1000 MOV CL,#$04 SHL AX,CL XOR DX,DX ;at beg of heap segment memin3 ADD DX,BX ;+ heap segment MOV SS,DX ;-> SS MOV SP,AX ;set SP MOV spval,AX ;remember SP XOR AX,AX ;clear heap: MOV hptop,AX ;ptrs to beg of free memory MOV hptop1,BX MOV hpstrt,AX MOV hpstrt1,BX PUSH DI ;save heap size LES DI,hpstrt ;init heap: MOV CX,#$0004 ;mark heap top CLD REPZ STOS POP DI ;restore heap size CS: ;return excess memory ? TEST [SI],#$0001 JNZ memin4 ;direct mode:no MOV AX,CS ;CS -> ES MOV ES,AX ADD BX,DI ;Heap pos + Heap size SUB BX,AX ;-> top of used memory MOV AH,#$4A ;change memory blocks CALL dos ;do MS-DOS memin4 CS: ;set variables MOV AX,[SI]$02 ;CS for return MOV turbocs,AX CS: MOV AX,[SI]$04 ;DS for return MOV turbods,AX CS: MOV AX,[SI] ;main flag CS: MOV CX,[SI]$0E ;max file count PUSH CX PUSH SI CALL initiofl ;init files, I/O POP SI POP CX MOV DI,#filetab ;get end addr ADD DI,CX ;of file tab ADD DI,CX MOV stdinof,DI ;buffer addr std input CS: MOV AX,[SI]$10 ;set std in buffer MOV stdinsz,AX ADD DI,AX