pcgen.s
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:20k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. ; Collection of assembler support routines for NOS
  2. ; Copyright 1991 Phil Karn, KA9Q
  3. include asmglobal.h
  4. LOCALS
  5. extrn ctick:proc
  6. extrn kbpoll:proc
  7. extrn kbsave:proc
  8. extrn ksignal:proc
  9. public eoi
  10. ; Hardware vector for timer linkage
  11. ; We use the timer hardware channel here instead of the indirect BIOS
  12. ; channel (1ch) because the latter is sluggish when running under DoubleDos
  13. TIMEVEC EQU 08h
  14. .DATA
  15. public Intstk,Stktop,Spsave,Sssave,Mtasker,Hashtab,Kbvec
  16. extrn Isat:word
  17. Spsave dw ? ; Save location for SP during interrupts
  18. Sssave dw ? ; Save location for SS during interrupts
  19. Intstk dw 1024 dup(?) ; Interrupt working stack
  20. Stktop equ $ ; SP set here when entering interrupt
  21. Mtasker db ? ; Type of higher multitasker, if any
  22. Hashtab db 256 dup(?) ; Modulus lookup table for iphash()
  23. Kbvec dd ? ; Address of BIOS keyboard handler
  24. .CODE
  25. dbase dw @Data
  26. jtable dw l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15
  27. vector dd ? ; place to stash chained vector
  28. vectlo equ word ptr vector
  29. vecthi equ word ptr vector+2
  30. ; Re-arm 8259 interrupt controller(s)
  31. ; Should be called just after taking an interrupt, instead of just
  32. ; before returning. This is because the 8259 inputs are edge triggered, and
  33. ; new interrupts arriving during an interrupt service routine might be missed.
  34. eoi proc
  35. cmp Isat,1
  36. jnz @@1 ; Only one 8259, so skip this stuff
  37. mov al,0bh ; read in-service register from
  38. out 0a0h,al ; secondary 8259
  39. nop ; settling delay
  40. nop
  41. nop
  42. in al,0a0h ; get it
  43. or al,al ; Any bits set?
  44. jz @@1 ; nope, not a secondary interrupt
  45. mov al,20h ; Get EOI instruction
  46. out 0a0h,al ; Secondary 8259 (PC/AT only)
  47. @@1: mov al,20h ; 8259 end-of-interrupt command
  48. out 20h,al ; Primary 8259
  49. ret
  50. eoi endp
  51. ; common routine for interrupt return
  52. ; Note that all hardware interrupt handlers are expected to return
  53. ; the original vector found when the device first attached. We branch
  54. ; to it just after we've cleaned up here -- this implements shared
  55. ; interrupts through vector chaining. If the original vector isn't
  56. ; available, the interrupt handler must return NULL to avoid a crash!
  57. public doret
  58. label doret far
  59. cmp ax,0 ; is a chained vector present?
  60. jne @@1 ; yes
  61. if @Datasize NE 0
  62. cmp dx,ax
  63. jne @@1 ; yes
  64. endif
  65. pop es ; nope, return directly from interrupt
  66. POPALL
  67. mov ss,Sssave
  68. mov sp,Spsave ; restore original stack context
  69. pop ds
  70. iret
  71. ; Code to handle vector chaining
  72. @@1: mov cs:vectlo,ax ; stash vector for later branch
  73. if @Datasize NE 0
  74. mov cs:vecthi,dx
  75. endif
  76. pop es
  77. POPALL
  78. mov ss,Sssave
  79. mov sp,Spsave ; restore original stack context
  80. pop ds
  81. if @Datasize NE 0
  82. jmp cs:[vector] ; jump to the original interrupt handler
  83. else
  84. jmp cs:[vectlo]
  85. endif
  86. ; istate - return current interrupt state
  87. public istate
  88. istate proc
  89. pushf
  90. pop ax
  91. and ax,200h
  92. jnz @@1
  93. ret
  94. @@1: mov ax,1
  95. ret
  96. istate endp
  97. ; dirps - disable interrupts and return previous state: 0 = disabled,
  98. ; 1 = enabled
  99. public dirps
  100. dirps proc
  101. pushf ; save flags on stack
  102. pop ax ; flags -> ax
  103. and ax,200h ; 1<<9 is IF bit
  104. jz @@1 ; ints are already off; return 0
  105. mov ax,1
  106. cli ; interrupts now off
  107. @@1: ret
  108. dirps endp
  109. ; restore - restore interrupt state: 0 = off, nonzero = on
  110. public restore
  111. restore proc
  112. arg is:word
  113. test is,0ffffh
  114. jz @@1
  115. sti
  116. ret
  117. @@1: cli ; should already be off, but just in case...
  118. ret
  119. restore endp
  120. ; multitasker types
  121. NONE equ 0
  122. DOUBLEDOS equ 1
  123. DESQVIEW equ 2
  124. WINDOWS3 equ 3
  125. OS2 equ 4
  126. ; Relinquish processor so other task can run
  127. public giveup
  128. giveup proc
  129. pushf ;save caller's interrupt state
  130. sti ;re-enable interrupts
  131. cmp mtasker, DOUBLEDOS
  132. jnz @@1
  133. mov al,2 ; 110 ms
  134. mov ah,0eeh
  135. int 21h
  136. POPFLAGS ; restore caller's interrupt state
  137. ret
  138. @@1: cmp mtasker, DESQVIEW
  139. jnz @@2
  140. mov ax, 1000h
  141. int 15h
  142. POPFLAGS ; restore interrupts
  143. ret
  144. @@2: cmp mtasker, WINDOWS3
  145. jnz @@3
  146. mov ax, 1680h
  147. int 2fh
  148. cmp al, 80h ; call supported?
  149. jz @@3 ; nope
  150. POPFLAGS ; yes - restore interrupts
  151. ret
  152. @@3: cmp mtasker, OS2
  153. jnz @@4
  154. mov ax, 1680h
  155. int 2fh
  156. POPFLAGS ; restore interrupts
  157. ret
  158. @@4: hlt ; wait for an interrupt
  159. POPFLAGS ; restore interrupts
  160. ret
  161. giveup endp
  162. ; check for a multitasker running
  163. public chktasker
  164. chktasker proc
  165. mov mtasker,NONE
  166. ; Check for OS/2
  167. mov ax,3000h ; Get MS-DOS Version Number call
  168. int 21h
  169. cmp al,20 ; Version 20 = OS/2 2.0
  170. jnz @@5
  171. mov mtasker, OS2
  172. ret
  173.    ; Check for Microsoft Windows
  174. @@5: mov ax,1600h
  175. ; Check for Microsoft Windows
  176. mov ax,1600h
  177. int 2fh
  178. cmp al, 00h ; 0 means windows multitasking not running
  179. jz @@4
  180. cmp al, 80h ; ditto for 80h return
  181. jz @@4
  182. mov mtasker, WINDOWS3
  183. ret
  184. ; Check for DoubleDos
  185. @@4: mov ah,0e4h
  186. int 21h
  187. cmp al,1
  188. jz @@1
  189. cmp al,2
  190. jnz @@2
  191. @@1: mov mtasker, DOUBLEDOS
  192. ret
  193. ; Check for DESQVIEW
  194. @@2: mov ax, 2b01h
  195. mov cx, 4445h
  196. mov dx, 5351h
  197. int 21h
  198. cmp al, 0ffh
  199. jnz @@3
  200. ret
  201. @@3: mov mtasker, DESQVIEW
  202. ret
  203. chktasker endp
  204. ; getss - Read SS for debugging purposes
  205. public getss
  206. getss proc
  207. mov ax,ss
  208. ret
  209. getss endp
  210. ; clockbits - Read low order bits of timer 0 (the TOD clock)
  211. ; This works only for the 8254 chips used in ATs and 386s.
  212. ;
  213. ; The timer runs in mode 3 (square wave mode), counting down
  214. ; by twos, twice for each cycle. So it is necessary to read back the
  215. ; OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
  216. ; pin forms the most significant bit of the count. Unfortunately,
  217. ; the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
  218. ;
  219. ; The PC's clock design is soooo brain damaged...
  220. public clockbits
  221. clockbits proc
  222. mov al,0c2h ; latch timer 0 count and status for reading
  223. @@1: pushf
  224. cli ; make chip references atomic
  225. out 43h,al ; send latch command
  226. in al,40h ; get status of timer 0
  227. mov bl,al ; save status
  228. in al,40h ; get lsb of count
  229. mov ah,al ; save lsb
  230. in al,40h ; get msb of count
  231. POPFLAGS ; no more chip references
  232. test bl,40h ; test NULL COUNT bit
  233. jnz @@1 ; count is invalid, try again
  234. and bl,80h ; we're only interested in the OUT bit
  235. xchg ah,al ; ax = count in correct order
  236. shr ax,1 ; count /= 2
  237. jz @@3 ; zero count requires carry propagation
  238. @@2: or ah,bl ; combine with OUT bit as most sig bit of count
  239. ret
  240. @@3: xor bl,80h ; propagate carry by toggling OUT bit when cnt == 0
  241. or ah,bl ; combine with !OUT bit as most sig bit of count
  242. ret
  243. clockbits endp
  244. ; Internet checksum subroutine
  245. ; Compute 1's-complement sum of data buffer
  246. ; Uses an unwound loop inspired by "Duff's Device" for performance
  247. ;
  248. ; Called from C as
  249. ; unsigned short
  250. ; lcsum(buf,cnt)
  251. ; unsigned short *buf;
  252. ; unsigned short cnt;
  253. public lcsum
  254. lcsum proc
  255. arg buf:ptr,cnt:word
  256. if @Datasize NE 0
  257. uses ds,si
  258. lds si,buf ; ds:si = buf
  259. else
  260. uses si
  261. mov si,buf ; ds:si = buf (ds already set)
  262. endif
  263. mov cx,cnt ; cx = cnt
  264. cld ; autoincrement si
  265. mov ax,cx
  266. shr cx,1 ; cx /= 16, number of loop iterations
  267. shr cx,1
  268. shr cx,1
  269. shr cx,1
  270. inc cx ; make fencepost adjustment for 1st pass
  271. and ax,15 ; ax = number of words modulo 16
  272. shl ax,1 ; *=2 for word table index
  273. lea bx,jtable ; bx -> branch table
  274. add bx,ax ; index into jump table
  275. clc ; initialize carry = 0
  276. mov dx,0 ; clear accumulated sum
  277. jmp word ptr cs:[bx] ; jump into loop
  278. ; Here the real work gets done. The numeric labels on the lodsw instructions
  279. ; are the targets for the indirect jump we just made.
  280. ;
  281. ; Each label corresponds to a possible remainder of (count / 16), while
  282. ; the number of times around the loop is determined by the quotient.
  283. ;
  284. ; The loop iteration count in cx has been incremented by one to adjust for
  285. ; the first pass.
  286. deloop: lodsw
  287. adc dx,ax
  288. l15: lodsw
  289. adc dx,ax
  290. l14: lodsw
  291. adc dx,ax
  292. l13: lodsw
  293. adc dx,ax
  294. l12: lodsw
  295. adc dx,ax
  296. l11: lodsw
  297. adc dx,ax
  298. l10: lodsw
  299. adc dx,ax
  300. l9: lodsw
  301. adc dx,ax
  302. l8: lodsw
  303. adc dx,ax
  304. l7: lodsw
  305. adc dx,ax
  306. l6: lodsw
  307. adc dx,ax
  308. l5: lodsw
  309. adc dx,ax
  310. l4: lodsw
  311. adc dx,ax
  312. l3: lodsw
  313. adc dx,ax
  314. l2: lodsw
  315. adc dx,ax
  316. l1: lodsw
  317. adc dx,ax
  318. l0: loop deloop ; :-)
  319. adc dx,0 ; get last carries
  320. adc dx,0
  321. mov ax,dx ; result into ax
  322. xchg al,ah ; byte swap result (8088 is little-endian)
  323. ret
  324. lcsum endp
  325. ; Link timer handler into timer chain
  326. ; Arg == address of timer handler routine
  327. ; MUST be called exactly once before uchtimer is called!
  328. toff dw ? ; save location for old vector
  329. tseg dw ? ;  must be in code segment
  330. public chtimer
  331. chtimer proc
  332. arg vec:far ptr
  333. uses ds
  334. mov ah,35h ; get current vector
  335. mov al,TIMEVEC
  336. int 21h ; puts vector in es:bx
  337. mov cs:tseg,es ; stash
  338. mov cs:toff,bx
  339. mov ah,25h
  340. mov al,TIMEVEC
  341. lds dx,vec ; ds:si = vec
  342. int 21h ; set new vector
  343. ret
  344. chtimer endp
  345. ; unchain timer handler from timer chain
  346. ; MUST NOT be called before chtimer!
  347. public uchtimer
  348. uchtimer proc
  349. uses ds
  350. mov ah,25h
  351. mov al,TIMEVEC
  352. mov dx,toff
  353. mov ds,tseg
  354. int 21h ; restore old vector
  355. ret
  356. uchtimer endp
  357. ; Keyboard hardware interrupt handler.
  358. ; First pass the interrupt to the original handler in the BIOS,
  359. ; then do a ksignal() to wake up any task sleeping on it.
  360. public kbint
  361. label kbint far
  362. cld
  363. push ds
  364. mov ds,cs:dbase ; establish interrupt data segment
  365. pushf ; Make it look like a hardware interrupt
  366. call dword ptr [Kbvec] ; Call BIOS handler
  367. mov Sssave,ss ; stash user stack context
  368. mov Spsave,sp
  369. mov ss,cs:dbase ; switch to interrupt stack
  370. lea sp,Stktop
  371. PUSHALL
  372. push es
  373. ; ksignal(&Kbvec,1);
  374. mov ax,1
  375. push ax
  376. push ds
  377. mov ax,offset DGROUP:Kbvec
  378. push ax
  379. call ksignal
  380. add sp,6 ; remove args
  381. pop es
  382. POPALL
  383. mov ss,Sssave
  384. mov sp,Spsave ; restore original stack context
  385. pop ds
  386. iret
  387. ; Poll keyboard through BIOS. Returns ascii char in low byte, scan code
  388. ; in high byte. If low byte == 0, character is "extended ascii"
  389. public kbraw
  390. kbraw proc
  391. mov ah,1 ; poll BIOS for character
  392. int 16h
  393. jz nochar ; no character available
  394. mov ah,0
  395. int 16h ; get it for real: ah = scan code, al = ascii char (or 0)
  396. ret
  397. nochar: xor ax,ax
  398. ret
  399. kbraw endp
  400. ; Clock tick interrupt handler. Note the use of "label" rather than "proc"
  401. ; here, necessitated by the fact that "proc" automatically generates BP-saving
  402. ; code that we don't want here.
  403. public btick
  404. label btick far
  405. pushf
  406. cld
  407. push ds
  408. cli
  409. mov ds,cs:dbase ; establish interrupt data segment
  410. mov Sssave,ss ; stash user stack context
  411. mov Spsave,sp
  412. mov ss,cs:dbase
  413. lea sp,Stktop
  414. PUSHALL
  415. push es
  416. call ctick
  417.   pop es
  418. POPALL
  419. mov ss,Sssave
  420. mov sp,Spsave ; restore original stack context
  421. pop ds
  422. POPFLAGS
  423. jmp dword ptr [toff] ; link to previous vector
  424. ; Convert 32-bit int in network order to host order (dh, dl, ah, al)
  425. ; Called from C as
  426. ; int32 get32(char *cp);
  427. public get32
  428. get32 proc
  429. arg cp:ptr
  430. if @Datasize NE 0
  431. uses ds,si
  432. lds si,cp ; ds:si = cp
  433. else
  434. uses si
  435. mov si,cp ; ds:si = cp (ds already set)
  436. endif
  437. cld
  438. lodsw
  439. mov dh,al ; high word to dx, a-swapping as we go
  440. mov dl,ah
  441. lodsw
  442. xchg al,ah ; low word stays in ax, just swap
  443. ret
  444. get32 endp
  445. ; Convert 16-bit int in network order to host order (ah, al)
  446. ; Called from C as
  447. ; int16 get16(char *cp);
  448. public get16
  449. get16 proc
  450. arg cp:ptr
  451. if @Datasize NE 0
  452. uses ds,si
  453. lds si,cp ; ds:si = cp
  454. else
  455. uses si
  456. mov si,cp ; ds:si = cp (ds already set)
  457. endif
  458. lodsw ; note: direction flag is don't-care
  459. xchg al,ah ; word stays in ax, just swap
  460. ret
  461. get16 endp
  462. ; Convert 32-bit int to network order, returning new pointer
  463. ; Called from C as
  464. ; char *put32(char *cp,int32 x);
  465. public put32
  466. put32 proc
  467. arg cp:ptr,x:dword
  468. if @Datasize NE 0
  469. uses ds,di
  470. les di,cp ; es:di = cp
  471. mov ax,ss ; our parameter is on the stack, and ds might not
  472. mov ds,ax ;   be pointing to ss.
  473. else
  474. uses di
  475. mov di,cp ; es:di = cp
  476. mov ax,ds ; point es at data segment
  477. mov es,ax
  478. endif
  479. cld
  480. mov ax,word ptr (x+2) ; read high word of machine version
  481. xchg ah,al ; swap bytes
  482. stosw ; output in network order
  483. mov ax,word ptr x ; read low word of machine version
  484. xchg ah,al ; swap bytes
  485. stosw ; put in network order
  486. mov ax,di ; return incremented output pointer
  487. if @Datasize NE 0
  488. mov dx,es ; upper half of pointer
  489. endif
  490. ret
  491. put32 endp
  492. ; Convert 16-bit int to network order, returning new pointer
  493. ; Called from C as
  494. ; char *put16(char *cp,int16 x);
  495. public put16
  496. put16 proc
  497. arg cp:ptr,x:word
  498. uses di
  499. if @Datasize NE 0
  500. les di,cp ;es:di = cp
  501. else
  502. mov di,cp ; es:di = cp
  503. mov ax,ds
  504. mov es,ax
  505. endif
  506. cld
  507. mov ax,x ; fetch source word in machine order
  508. xchg ah,al ; swap bytes
  509. stosw ; save in network order
  510. mov ax,di ; return new output pointer to user
  511. if @Datasize NE 0
  512. mov dx,es ; upper half of pointer
  513. endif
  514. ret
  515. put16 endp
  516. if @CPU AND 2
  517. ; fast I/O buffer routines
  518. ; version for 80[1234]86 (uses ins, outs instructions)
  519. ; outbuf - put a buffer to an output port
  520. public outbuf
  521. outbuf proc
  522. arg port:word,buf:ptr,cnt:word
  523. if @Datasize NE 0
  524. uses ds,si
  525. lds si,buf ; ds:si = buf
  526. else
  527. uses si
  528. mov si,buf ;ds:si = buf (ds already set)
  529. endif
  530. mov dx,port
  531. mov cx,cnt
  532. cld
  533. rep outsb ; works only on PC/AT (80286)
  534. mov dx,ds
  535. mov ax,si ; return pointer just past end of buffer
  536. ret
  537. outbuf endp
  538. ; inbuf - get a buffer from an input port
  539. public inbuf
  540. inbuf proc
  541. arg port:word,buf:ptr,cnt:word
  542. uses di
  543. if @Datasize NE 0
  544. les di,buf ; es:di = buf
  545. else
  546. mov di,buf ; es:di = buf
  547. mov ax,ds
  548. mov es,ax
  549. endif
  550. mov dx,port
  551. mov cx,cnt
  552. cld
  553. rep insb ; works only on PC/AT (80286)
  554. mov dx,es
  555. mov ax,di ; return pointer just past end of buffer
  556. ret
  557. inbuf endp
  558. else
  559. ; fast buffer I/O routines
  560. ; version for 8086/8
  561. ; outbuf - put a buffer to an output port
  562. public outbuf
  563. outbuf proc
  564. arg port:word,buf:ptr,cnt:word
  565. if @Datasize NE 0
  566. uses ds,si
  567. lds si,buf ; ds:si = buf
  568. else
  569. uses si
  570. mov si,buf ; ds:si = buf (ds already set)
  571. endif
  572. mov dx,port
  573. mov cx,cnt
  574. cld
  575. ; If buffer doesn't begin on a word boundary, send the first byte
  576. test si,1 ; (buf & 1) ?
  577. jz @@even ; no
  578. lodsb ; al = *si++;
  579. out dx,al ; out(dx,al);
  580. dec cx ; cx--;
  581. mov cnt,cx ; save for later test
  582. @@even:
  583. shr cx,1 ; cx = cnt >> 1; (convert to word count)
  584. ; Do the bulk of the buffer, a word at a time
  585. jcxz @@nobuf ; if(cx != 0){
  586. @@deloop:
  587. lodsw ; do { ax = *si++; (si is word pointer)
  588. out dx,al ; out(dx,lowbyte(ax));
  589. mov al,ah
  590. out dx,al ; out(dx,hibyte(ax));
  591. loop @@deloop ; } while(--cx != 0); }
  592. ; now check for odd trailing byte
  593. @@nobuf:
  594. mov cx,cnt
  595. test cx,1
  596. jz @@cnteven
  597. lodsb ; al = *si++;
  598. out dx,al
  599. @@cnteven:
  600. mov dx,ds
  601. mov ax,si ; return pointer just past end of buffer
  602. ret
  603. outbuf endp
  604. ; inbuf - get a buffer from an input port
  605. public inbuf
  606. inbuf proc
  607. arg port:word,buf:ptr,cnt:word
  608. uses di
  609. if @Datasize NE 0
  610. les di,buf ; es:di = buf
  611. else
  612. mov di,buf ; es:di = buf
  613. mov ax,ds
  614. mov es,ax
  615. endif
  616. mov dx,port
  617. mov cx,cnt
  618. cld
  619. ; If buffer doesn't begin on a word boundary, get the first byte
  620. test di,1 ; if(buf & 1){
  621. jz @@bufeven ;
  622. in al,dx ; al = in(dx);
  623. stosb ; *di++ = al
  624. dec cx ; cx--;
  625. mov cnt,cx ; cnt = cx; } save for later test
  626. @@bufeven:
  627. shr cx,1 ; cx = cnt >> 1; (convert to word count)
  628. ; Do the bulk of the buffer, a word at a time
  629. jcxz @@nobuf ; if(cx != 0){
  630. @@deloop:
  631. in al,dx ; do { al = in(dx);
  632. mov ah,al
  633. in al,dx ; ah = in(dx);
  634. xchg al,ah
  635. stosw ; *si++ = ax; (di is word pointer)
  636. loop @@deloop ; } while(--cx != 0);
  637. ; now check for odd trailing byte
  638. @@nobuf:
  639. mov cx,cnt
  640. test cx,1
  641. jz @@cnteven
  642. in al,dx
  643. stosb ; *di++ = al
  644. @@cnteven:
  645. mov dx,es
  646. mov ax,di ; return pointer just past end of buffer
  647. ret
  648. inbuf endp
  649. endif
  650. public longdiv
  651. ; long unsigned integer division - divide an arbitrary length dividend by
  652. ; a 16-bit divisor. Replaces the dividend with the quotient and returns the
  653. ; remainder. Called from C as
  654. ;
  655. ; unsigned short
  656. ; longdiv(unsigned short divisor,int cnt,unsigned short *dividend);
  657. ;
  658. ;Register usage:
  659. ; di - divisor
  660. ; si - pointer into dividend array
  661. ; cx - loop counter, initialized to the number of 16-bit words in the dividend
  662. ; ax - low word of current dividend before each divide, current quotient after
  663. ; dx - remainder from previous divide carried over, becomes high word of
  664. ;      dividend for next divide
  665. longdiv proc
  666. arg divisor:word,cnt:word,dividend:ptr
  667. if @Datasize NE 0
  668. uses ds,si,di
  669. lds si,dividend
  670. else
  671. uses si,di
  672. mov si,dividend ;si -> dividend array
  673. endif
  674. cmp divisor,0 ; divisor == 0?
  675. jne @2 ; no, ok
  676. xor ax,ax ; yes, avoid divide-by-zero trap
  677. jmp short @1
  678. @2: mov dx,0 ; init remainder = 0
  679. mov cx,cnt ; init cnt
  680. mov di,divisor ; cache divisor in register
  681. @@deloop:
  682. mov ax,word ptr [si] ; fetch current word of dividend
  683. cmp ax,0 ; dividend == 0 ?
  684. jne @7 ; nope, must do division
  685. cmp dx,0 ; remainder also == 0?
  686. je @4 ; yes, skip division, continue
  687. @7: div di ; do division
  688. mov word ptr [si],ax ; save quotient
  689. @4: inc si ; next word of dividend
  690. inc si
  691. loop  @@deloop
  692. mov ax,dx ; return last remainder
  693. @1: ret
  694. longdiv endp
  695. ; long unsigned integer multiplication - multiply an arbitrary length
  696. ; multiplicand by a 16-bit multiplier, leaving the product in place of
  697. ; the multipler, returning the carry. Called from C as
  698. ;
  699. ; unsigned short
  700. ; longmul(unsigned short multiplier,int cnt,unsigned short *multiplier);
  701. ;
  702. ; Register usage:
  703. ; di = multiplier
  704. ; si = pointer to current word of multiplicand
  705. ; bx = carry from previous round
  706. ; cx = count of words in multiplicand
  707. ; dx,ax = scratch for multiply
  708. public longmul
  709. longmul proc far
  710. arg multiplier:word,n:word,multiplicand:ptr
  711. if @Datasize NE 0
  712. uses ds,si,di
  713. lds si,multiplicand
  714. else
  715. uses si,di
  716. mov si,multiplicand ; si -> multiplicand array
  717. endif
  718. mov di,multiplier ; cache multiplier in register
  719. xor bx,bx ; init carry = 0
  720. mov cx,n ; fetch n
  721. mov ax,cx
  722. shl ax,1 ; *2 = word offset
  723. add si,ax ; multiplicand += n
  724. @@deloop:
  725. dec si
  726. dec si ; work from right to left
  727. mov ax,word ptr [si] ; fetch current multiplicand
  728. or ax,ax ; skip multiply if zero
  729. jz @@nomult
  730. mul di ; dx:ax <- ax * di
  731. @@nomult:
  732. add ax,bx ; add carry from previous multiply
  733. mov word ptr [si],ax ; save low order word of product
  734. mov bx,0 ; clear previous carry, leaving CF alone
  735. adc bx,dx ; save new carry
  736. xor dx,dx ; clear in case we skip the next mult
  737. loop @@deloop
  738. mov ax,bx ; return final carry
  739. ret
  740. longmul endp
  741. ifdef notdef
  742. ; divide 32 bits by 16 bits, returning both quotient and remainder
  743. ; This allows C programs that need both to avoid having to do two divisions
  744. ;
  745. ; Called from C as
  746. ; long divrem(dividend,divisor)
  747. ; long dividend;
  748. ; short divisor;
  749. ;
  750. ; The quotient is returned in the low 16 bits of the result,
  751. ; and the remainder is returned in the high 16 bits.
  752. public divrem
  753. divrem proc
  754. arg dividend:dword,divisor:word
  755. mov ax,word ptr dividend
  756. mov dx,word ptr (dividend+2)
  757. div divisor
  758. ret
  759. divrem endp
  760. endif
  761. ; General purpose hash function for IP addresses
  762. ; Uses lookup table Hashtab[] initialized in iproute.c
  763. ; Called from C as
  764. ; char hash_ip(int32 ipaddr);
  765. public hash_ip
  766. hash_ip proc
  767. arg ipaddr:dword
  768. lea bx,Hashtab
  769. mov ax,word ptr ipaddr
  770. xor ax,word ptr (ipaddr+2)
  771. xor al,ah
  772. xlat
  773. xor ah,ah
  774. ret
  775. hash_ip endp
  776. ; Compute int(log2(x))
  777. ; Called from C as
  778. ; int ilog2(int16 x);
  779. public ilog2
  780. ilog2 proc
  781. arg x:word
  782. mov cx,16
  783. mov ax,x
  784. @@2: rcl ax,1 
  785. jc @@1
  786. loop @@2
  787. @@1: dec cx
  788. mov ax,cx
  789. ret
  790. ilog2 endp
  791. end