; =====> STIMER.ASM ;*************************************** ;* TIPC Scheme '84 Things That Could * ;* Have Been Done in C but Why Waste * ;* Execution Time and Codespace? * ;* * ;* (C) Copyright 1984,1985 by Texas * ;* Instruments Incorporated. * ;* All rights reserved. * ;* * ;* Date Written: July 1985 * ;* Last Modification: 8 October 1985 * ;*************************************** include scheme.equ DGROUP group data data segment word public 'DATA' assume DS:DGROUP ;Table of strange characters stranges db " ,'" db ';":()`' db 13,12,11,10,9,0 ;Random number registers krala dw 22425 kralb dw 30029 ;RANDOMIZE puts seed value here ;Random number table kraltbl dw 4053,32361,7773,17385,11177,20413,27513,16501 dw 5953,17673,20725,12247,28429,30861,16849,22375 ;Copy of random number registers and table. krala1 dw 22425 kralb2 dw 30029 kraltbl1 dw 4053,32361,7773,17385,11177,20413,27513,16501 dw 5953,17673,20725,12247,28429,30861,16849,22375 kral_len equ krala1-krala data ends PGROUP group prog prog segment byte public 'PROG' assume CS:PGROUP ;For space and performance reasons, some procedures have been written in the ; following style: the arguments are popped off the stack, and the ; procedure may end in an indirect JMP instead of a RET. In this source file, ; the following are such procedures: ; toblock, gvchars, blk2pbuf, putlong, thefix, ldlong, msubstr, ; mcmpstr, ldreg, pt_flds4, pt_flds6, str2str, adj4bord ; Convert flonum to bignum ; Calling sequence: flotobig(flo,bigbuf) ; Where ---- flo: double-length flonum such that abs(flo)>=1 ; bigbuf: pointer to buffer for bignum formation fbargs struc dw ? ;Return address flo dw ?,?,?,? ;Flonum bigbuf dw ? ;Pointer to bignum buffer fbargs ends public flotobig flotobig proc near mov BX,SP lea SI,[BX].flo ;Fetch pointer to flonum mov DI,[BX].bigbuf ;Fetch buffer pointer inc DI ;Point DI to sign byte inc DI cld ;Direction forward mov AX,[BX+6].flo ;Fetch exponent word to CX mov CX,AX and AX,0fh ;Save mantissa part back or AL,10h mov [BX+6].flo,AX mov AL,AH ;Zero AL test CH,80h ;Negative flonum? jz ftb1 ;Jump if not inc AL ;Otherwise, set AL to 1 ftb1: stosb ;Store sign byte mov BX,DI ;Save address of first word in BX mov AL,AH ;Zero AL again and CX,7ff0h ;Discard sign byte and mantissa sub CX,3ff0h ;Remove exponent bias shl CX,1 ;At this stage, CH+1==number of bytes for bignum, CL shows how much to ; shift mantissa left (once per 20h) mov DX,CX ;Use DX to count the shifts xor DH,DH ;Set up shift count add DX,80h ;Account for placing leading 1 in high byte ftb2: shl word ptr[SI],1 ;Shift mantissa left rcl word ptr[SI+2],1 rcl word ptr[SI+4],1 rcl word ptr[SI+6],1 sub DX,20h ;Repeat until done jnz ftb2 mov CL,CH ;Set CX to number of bignum bytes xor CH,CH inc CX sub CX,8 ;Check for leading zeros js ftb3 ;Jump if not all the mantissa will be done jz ftb3 ;Jump if no trailing zeros exist rep stosb ;Else store as many zeros as necessary ftb3: sub SI,CX ;Point SI to eligible part of mantissa add CX,8 ;Set mantissa byte count rep movsb ;Copy flonum mantissa to bignum mov CX,DI ;Find number of bytes in bignum proper sub CX,BX shr CX,1 ;Find number of words jnc ftb4 ;If a whole number of words, do nothing mov byte ptr[DI],0 ;Otherwise, pad with a 0 inc CX ;Adjust word count ftb4: mov [BX-3],CX ;Save size of bignum ret flotobig endp ; Find the size of a flonum ; Calling sequence: flosiz(flo); ; Where ---- flo: double-length flonum ; Returns the number of bytes needed for a working flonum formed from ; trunc(flonum) fsargs struc dw ? ;Return address fl dw ?,?,?,? ;Double-length flonum fsargs ends public flosiz flosiz proc near mov SI,SP mov AX,[SI+6].fl ;Fetch word containing exponent and AX,7ff0h ;Drop sign and mantissa sub AX,3ff0h ;Is abs(flo) < 1? jc small ;Jump if small mov AL,AH ;Otherwise, return number of bytes xor AH,AH shl AL,1 add AL,5 ret small: xor AX,AX ;Return 0 for smallness ret flosiz endp ; Move bytes from buffer to allocated Scheme block ; Calling sequence: toblock(reg,offs,buf,q) ; Where ---- reg: Scheme register pointing to block ; offs: Offset into block to begin transfer ; buf: Buffer pointer ; q: Number of bytes to move ;Stack elements in order of popping: ; Return address, register, offset, buffer address, number of bytes public toblock toblock proc near pop DX ;Save return address in DX pop BX ;Get register address mov DI,[BX].C_disp ;Put 8088 address in ES:DI mov BX,[BX].C_page mov AX,ES LoadPage ES,BX ;;; mov ES,pagetabl+[BX] pop CX ;Get offset add DI,CX ;Add to DI pop SI ;Get source address (buffer ptr) pop CX ;Get number of bytes jcxz tbskip ;If no bytes, don't move cld ;Direction forward rep movsb ;Move bytes tbskip: mov ES,AX ;Restore ES jmp DX ;Return toblock endp IFNDEF PROMEM ; Give characters from a C string ; Calling sequence: gvchars(str,len) ; Where ---- str: C string address ; len: Number of characters to give ;Stack elements in order of popping: ; Return address, string address, number of chars extrn givechar:near public gvchars gvchars proc near pop DI ;Get return address pop SI ;Get string address pop CX ;Get number of chars push DI ;Put return address back jcxz given ;If no chars, stop cld ;Direction forward gvlp: push CX ;Save count lodsb ;Fetch string character push SI ;Save pointer to next char push AX call givechar ;Give it inc SP ;Restore stack inc SP pop SI ;Restore address and count pop CX loop gvlp ;Give 'til done given: ret ;Return gvchars endp ; Move characters from block (symbol or string) to print buffer ; Calling sequence: blk2pbuf(pg,ds,buf,len,ch,display) ; Where ---- pg: logical page of the block ; ds: block displacement ; buf: address of print buffer ; len: number of chars in the block ; ch: character to escape (| for syms, " for strs) ; display: whether to use escape characters ; Returns the number 2n+s, where n is the number of characters in the ; print buffer, and s=1 if strange chars were encountered, 0 otherwise. ; Popping order: return address, pg, ds, buf, len, ch, display public blk2pbuf extrn hicases:byte blk2pbuf proc near pop DX ;Pop return address pop BX ;Pop page shl BX,1 ;Put segment of block in DS LoadPage DS,BX ;;; mov DS,pagetabl+[BX] pop SI ;Pop block displacement pop DI ;Pop print buffer pop CX ;Pop character count pop BX ;Pop must-be-escaped character pop AX ;Pop whether to use escapes mov BH,AL ;Save escape boolean in BX and BH,7fh ;Save bit in BH for strangeness push DX ;Push return address push ES ; Save caller's ES register mov DX,DI ;Save start address of print buffer in DX jcxz zstrng ;If len=0, mark strangeness cmp BL,'"' ;Are we looking at a string? jne b2plp ;Skip if not zstrng: or BH,80h ;Otherwise, mark as strange jcxz done ;If len=0, forget everything else b2plp: lodsb ;Fetch char from block test BH,7fh ;Are we displaying escape chars? jz storit ;Jump if not cmp AL,BL ;Does the char need escaping? je escit ;If needed, do so cmp AL,'\' jne storit ;If not, just store it escit: mov AH,AL ;Save char in AH mov AL,'\' ;Store escape character stosb mov AL,AH ;Restore char storit: stosb ;Store it test BH,80h ;Do we already know that atom's strange? jnz skptest ;If so, don't bother testing push SI ;Else save SI mov SI,offset DGROUP:hicases ;Point SI to table of upper cases xchg BX,SI mov AH,AL ;Save char in AH xlat ES:hicases ;Fetch upper-case equivalent xchg BX,SI ;Restore BX cmp AH,AL jne mrkstrng ;If chars different, mark as strange mov SI,offset stranges ;Point SI to strange-character string strnglp: lods byte ptr ES:[SI] ;Fetch strange char or AL,AL ;End of string? jz notstrng ;Jump if so cmp AH,AL ;Is AH strange? jne strnglp ;If not, try again mrkstrng: or BH,80h ;Mark strange bit notstrng: pop SI ;Restore SI skptest: loop b2plp ;Repeat until done done: push ES ;Restore DS pop DS pop ES ; Restore caller's ES register mov byte ptr[DI],0 ;Put null at end of string mov AX,DI ;Return 2*(# of chars in string)+strangeness sub AX,DX shl BH,1 rcl AX,1 ret ;Return blk2pbuf endp ENDIF ; Load bignum block with long integer ; Calling sequence: putlong(reg,longi) ; Where ----- reg: register pointing to a bignum block ; longi: 32-bit integer to store ; Popping order: return address, register address, low & high integer words public putlong putlong proc near pop DX ;Fetch return address pop DI ;Fetch register address mov BX,[DI].C_page ;Point ES:DI to bignum block LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov DI,[DI].C_disp add DI,3 ;Point ES:DI to block data area pop BX ;Put long integer in CX:BX pop CX xor AL,AL ;Sign byte - default positive test CH,80h ;Integer negative? jz poslong ;Jump if not inc AL ;Otherwise, set sign negative xor BX,-1 ;Negate long integer xor CX,-1 add BX,1 adc CX,0 poslong: cld ;Direction forward stosb ;Store sign byte mov AX,BX ;Store least significant word stosw jcxz notlong ;If most signif. word=0, don't store it mov AX,CX stosw notlong: push DS ;Restore ES pop ES jmp DX ;Return putlong endp ; Add word of zeros, if necessary, to bignum buffer ; Calling sequence: thefix(buf) ; Where ----- buf: address of bignum buffer ; THEFIX is intended to alleviate a problem in the bignum division package. ; Popping order: return address, buf public thefix thefix proc near pop DI ;Return address in DX pop SI ;Fetch bignum buffer address mov BX,[SI] ;Get bignum size in words inc BX ;Point BX+SI to last bignum byte shl BX,1 test byte ptr[BX+SI],80h ;Is most signif. bit set? jz fixed ;If not, nothing to fix inc word ptr[SI] ;Otherwise, increase bignum size inc BX ;Add word of 0 to most significant end mov word ptr[BX+SI],0 fixed: jmp DI ;Return thefix endp ; Load a long integer value with a bignum ; Calling sequence: ldlong(v, reg) ; Where ----- v: pointer to a long integer ; reg: register pointing to a bignum ; Returns 0 if the load was successful, 1 otherwise ; Popping order: return address, v, reg public ldlong ldlong proc near pop DX ;Pop return address pop DI ;Pop longint destination pop BX ;Pop register address push DS ;Save DS mov SI,[BX].C_disp ;Point DS:SI to bignum object mov BX,[BX].C_page LoadPage DS,BX ;;; mov DS,pagetabl+[BX] cld ;Direction forward inc SI ;Put bignum length in CX lodsw mov CX,AX lodsb ;Put bignum sign in BL mov BL,AL cmp CX,6 ;Check size je big6 cmp CX,8 je big8 mov AX,1 ;If here, bignum wrong size: error pop DS ;Restore DS jmp DX ;Return big6: lodsw ;Put bignum in CX:AX xor CX,CX jmp short havenum big8: lodsw ;Put bignum in CX:AX mov CX,AX lodsw xchg CX,AX havenum: test BL,1 ;Was bignum negative? jz storenum ;No, skip xor CX,-1 ;Otherwise, negate xor AX,-1 add AX,1 adc CX,0 storenum: stosw ;Store to long integer mov AX,CX stosw xor AX,AX ;All's well pop DS ;Restore DS jmp DX ;Return ldlong endp ; Move string bytes from one part of PCS memory to another ; Calling sequence: msubstr(to_reg, from_reg, start, end) ; Where ----- to_reg: register pointing to destination string ; from_reg: register pointing to source string ; start: offset at which to start copying ; end: byte after the last to be copied ; Popping order: return address, from_reg, to_reg, start, end public msubstr msubstr proc near pop DX ;Pop return address (temporarily) pop DI ;Pop destination register address pop SI ;Pop source register address pop AX ;Pop start index pop CX ;Pop end index push DS ;Save caller's DS & ES push ES mov BX,[DI].C_page ;Point ES:DI to destination object mov DI,[DI].C_disp LoadPage ES,BX ;;; mov ES,pagetabl+[BX] add DI,BLK_OVHD ;Adjust DI past string overhead mov BX,[SI].C_page ;Point DS:SI to source object mov SI,[SI].C_disp LoadPage DS,BX ;;; mov DS,pagetabl+[BX] add SI,BLK_OVHD ;Adjust SI past string overhead add SI,AX ;Point SI to start of substring sub CX,AX ;Set number of bytes to move cld ;Direction forward rep movsb pop ES ;Restore caller's DS & ES pop DS jmp DX ;Return msubstr endp ; Compare two Scheme bignums or strings for equal?-ness ; Calling sequence: mcmpstr(reg1,reg2) ; Where ----- reg1,reg2: registers pointing to objects to be compared ; Returns 1 if the objects are equal?, 0 otherwise public mcmpstr mcmpstr proc near pop DX ;Pop return address pop SI ;Pop register addresses pop DI push DS ;Save caller's DS and ES push ES mov BX,[DI].C_page ;Point ES:DI to second object mov DI,[DI].C_disp LoadPage ES,BX ;;; mov ES,pagetabl+[BX] mov BX,[SI].C_page ;Point DS:SI to the first object mov SI,[SI].C_disp LoadPage DS,BX ;;; mov DS,pagetabl+[BX] mov CX,[SI].str_len ;Fetch byte count from source's length cmp CX,0 ;;; check for small string jge mcm_010 add CX,BLK_OVHD+PTRSIZE mcm_010: xor AX,AX ;Default AX to FALSE cld ;Direction forward repe cmpsb ;Compare jne cmpskp ;If not equal, return FALSE inc AX ;Otherwise return TRUE cmpskp: pop ES ;Restore caller's ES and DS pop DS jmp DX ;Return mcmpstr endp ; Load a register with a pointer from Scheme memory ; Calling sequence: ldreg(reg,pg,ds) ; Where ----- reg: register to be loaded ; pg,ds: page and displacement of Scheme pointer ; Popping order: return address, reg, pg, ds public ldreg ldreg proc near pop DX ;Pop return address pop DI ;Pop destination register pop BX ;Pop page and displacement pop SI mov CX,DS ;Save caller's DS shl BX,1 ;Point DS:SI to Scheme pointer LoadPage DS,BX ;;; mov DS,pagetabl+[BX] cld ;Direction forward lodsb ;Load register's page field xor AH,AH mov ES:[DI].C_page,AX lodsw ;Load displacement field mov ES:[DI].C_disp,AX mov DS,CX ;Restore caller's DS jmp DX ;Return ldreg endp ; Generate pseudorandom numbers in the range 0-16,383 ; ; Author: John C. Jensen (converted to assembly lang. by Mark Meyer) ; Date Written: 9 January 1985 ; Last Modification: 9 July 1985 ; ; Calling Sequence: krandom() ; ; Note: the following random number generator is due to Jaroslav ; Kral. It was adapted to 16 bit words and proven both efficient ; and statistically satisfactory by Overstreet and Nance of SMU. ; See Karl's paper for initialization values for other word ; lengths. ; ; -- Kral, Jaroslav. "A New Additive Pseudorandom Number ; Generator for Extremely Short Word-Lengths," Information ; Processing Letters, 1 (1972), 164-167 (erratum noted in 1 ; (1972), 216). ; ; -- Overstreet, C. and Nance, R.E., "A Random Number Generator ; for Small Word-Length Computers," Proceedings of the ACM '73 ; Conference, p. 219-223. ; public krandom krandom proc near mov AX,krala ;Put old KRALA in AX, old KRALB in BX mov BX,kralb mov CX,BX ;KRALC = KRALB add BX,AX ;KRALB = (KRALA+KRALB) mod 2^n and BH,3fh ; (Currently, n=14) mov kralb,BX mov BL,BH ;J = KRALB / 2^(n-4) shr BL,1 and BX,01eh mov AX,[BX]+offset kraltbl ;KRALA = KRALTBL[J] mov krala,AX add AX,CX ;KRALTBL[J] = (KRALA+KRALC) mod 2^n and AH,3fh mov [BX]+offset kraltbl,AX ret ;Return KRALTBL[J] krandom endp ; RANDOMIZE - Reset the random number registers and table back to their ; original values, then put the seed value into "kralb". ; Calling sequence: randomize(seed) ;seed = normal C int public randomiz randz_args struc dw ? ;caller's ES dw ? ;caller's BP dw ? ;return address rseed dw ? ;argument 1 (seed) randz_args ends randomiz proc near push BP ;save caller's BP push ES ;save ES mov BP,SP ;establish local addressability mov AX,DS ;copy DS to ES mov ES,AX mov CX,kral_len/2 ;restore random state to its original state lea SI,krala1 lea DI,krala rep movsw mov BX,[BP].rseed ;get seed cmp BX,0 ;is it zero? jnz randz_1 ;no, jump; use the seed directly mov AX,2C00h ;get the time from DOS int 21h push DX ;tempsave DX (seconds, hundredths) xor AX,AX mov AL,CH ;determine #sec-in-hours mov DX,3600 mul DX mov BX,AX xor AX,AX mov AL,CL ;determine #sec-in-minutes mov DX,60 mul DX add BX,AX ;#sec-in-hours + #sec-in-minutes pop DX ;restore seconds (and hundredths, but ignore it) xchg DH,DL mov DH,0 add BX,DX ;add in seconds randz_1: mov kralb,BX ;set seed pop ES ;wrap up pop BP ret randomiz endp ; Set the cdr field of a list cell ; Calling sequence: asetcdr(creg, preg) ; Where ---- creg: register pointing to cell ; preg: register holding new pointer ; Popping order: Return address, destination register, pointer register public asetcdr asetcdr proc near pop DX ;Pop return address pop DI ;Pop address of register mov CX,ES ;Save caller's ES mov BX,[DI].C_page ;Point ES:DI to list cell mov DI,[DI].C_disp LoadPage ES,BX ;;; mov ES,pagetabl+[BX] add DI,PTRSIZE ;Adjust for cdr field pop SI ;Pop address of pointer cld ;Direction forward mov AX,[SI].C_page ;Store into cdr field stosb mov AX,[SI].C_disp stosw mov ES,CX ;Restore ES jmp DX ;Return asetcdr endp ; Get field values from a port object ; Calling sequence: pt_flds4(reg, &ull, &ulc, &nl, &nc) ; pt_flds6(reg, &cl, &cc, &ull, &ulc, &nl, &nc) ; Where ----- reg: register pointing to port ; cl: variable to receive CUR_LINE value ; cc: ... CUR_COL value ; ull: ... UL_LINE value ; ulc: ... UL_COL value ; nl: ... N_LINES value ; nc: ... N_COLS value ; Warning: This routine expects these six fields to be contiguous ; Popping order: return address, reg, (&cl, &cc,) &ull, &ulc, &nl, &nc public pt_flds4,pt_flds6 pt_flds proc near pt_flds6: mov CX,pt_cline ;Set CX to offset of first field jmp fldsmrg pt_flds4: mov CX,pt_ullin ;Set CX to offset of first field fldsmrg: pop DX ;Pop return address mov AX,DS ;Save caller's DS pop BX ;Pop register address mov SI,[BX].C_disp ;Point DS:SI to first field mov BX,[BX].C_page LoadPage DS,BX ;;; mov DS,pagetabl+[BX] add SI,CX cld ;Direction forward sub CX,pt_cline ;Set CX to number of fields to do shr CX,1 ; (6 - (1/2)(CX - pt_cline)) neg CX add CX,6 fldslp: pop DI ;Pop destination variable address movsw ;Transfer value loop fldslp ;Repeat until done mov DS,AX ;Restore DS jmp DX ;Return pt_flds endp ; Copy bytes from one C location to another ; Calling sequence: str2str(dest_adr, src_adr, n) ; Where ----- dest_adr: destination address ; src_adr: source address ; n: number of bytes to copy ; Popping order: return address, dest_adr, src_adr, n public str2str str2str proc near pop DX ;Pop return address pop DI pop SI pop CX cld ;Direction forward rep movsb ;Copy bytes jmp DX ;Return str2str endp ; Adjust window region variables for presence of a border ; Calling sequence: adj4bord(&ull, &nl, &ulc, &nc) ; Where ----- ull: Upper-left-line variable ; nl: Number-of-lines variable ; ulc: Upper-left-column variable ; nc: Number-of-columns variable ; Popping order: return address, &ull, &nl, &ulc, &nc public adj4bord max_lines equ 25 max_cols equ 80 adj4bord proc near pop DX ;Pop return address mov BX,max_lines ;Expand HEIGHT of window region expand: pop SI ;Pop upper-left parameter pop DI ;Pop extent parameter mov AX,[SI] ;Get value of upper-left parm or AX,AX ;If zero, jz expand1 ; skip next two instructions dec word ptr[SI] ;Else, expand backward inc word ptr[DI] dec AX ;Adjust AX to match upper-left parm expand1: add AX,[DI] ;Find opposite edge cmp AX,BX ;If edge too far, jae expand2 ; skip next instruction inc word ptr[DI] ;Else, expand forward expand2: cmp BX,max_cols ;If we're finished, je adjex ; jump out mov BX,max_cols ;Else, expand WIDTH of window region jmp expand adjex: jmp DX ;Return adj4bord endp prog ends end