crc_i86.asm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. ;===========================================================================
  2. ; Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
  3. ;
  4. ; See the accompanying file LICENSE, version 2000-Apr-09 or later
  5. ; (the contents of which are also included in zip.h) for terms of use.
  6. ; If, for some reason, all these files are missing, the Info-ZIP license
  7. ; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
  8. ;===========================================================================
  9. ; Created by Christian Spieler, last modified 07 Jan 2007.
  10. ;
  11. TITLE crc_i86.asm
  12. NAME crc_i86
  13. ;
  14. ; Optimized 8086 assembler version of the CRC32 calculation loop, intended
  15. ; for real mode Info-ZIP programs (Zip 2.1, UnZip 5.2, and later versions).
  16. ; Supported compilers are Microsoft C (DOS real mode) and Borland C(++)
  17. ; (Turbo C). Watcom C (16bit) should also work.
  18. ; This module was inspired by a similar module for the Amiga (Paul Kienitz).
  19. ;
  20. ; It replaces the `ulg crc32(ulg crc, ZCONST uch *buf, extent len)' function
  21. ; in crc32.c.
  22. ;
  23. ; In March/April 1997, the code has been revised to incorporate Rodney Brown's
  24. ; ideas for optimized access to the data buffer. For 8086 real mode code,
  25. ; the data buffer is now accessed by aligned word-wide read operations.
  26. ; This new optimization may be turned off by defining the macro switch
  27. ; NO_16_BIT_LOADS.
  28. ;
  29. ; In December 1998, the loop branch commands were changed from "loop dest"
  30. ; into "dec cx; jnz dest". On modern systems (486 and newer), the latter
  31. ; code is usually much faster (e.g. 1 clock cycle compared to 5 for "loop"
  32. ; on Pentium MMX). For the 286, the penalty of "dec cx; jnz" is one clock
  33. ; cycle (12 vs. 11 cycles); on an 8088 the cycle counts are 22 (dec cx; jnz)
  34. ; vs. 18 (loop). I decided to optimize for newer CPU models by default, because
  35. ; I expect that old 80286 or 8088 dinosaurier machines may be rarely used
  36. ; nowadays. In case you want optimum performance for these old CPU models
  37. ; you should define the OPTIMIZE_286_88 macro switch on the assembler's
  38. ; command line.
  39. ; Likewise, "jcxz" was replaced by "jz", because the latter is faster on
  40. ; 486 and newer CPUs (without any penalty on 80286 and older CPU models).
  41. ;
  42. ; In January 2007, the "hand-made" memory model setup section has been guarded
  43. ; against redefinition of @CodeSize and @DataSize symbols, to work around a
  44. ; problem with current Open Watcom (version 1.6) wasm assembler.
  45. ;
  46. ; The code in this module should work with all kinds of C memory models
  47. ; (except Borland's __HUGE__ model), as long as the following
  48. ; restrictions are not violated:
  49. ;
  50. ; - The implementation assumes that the char buffer is confined to a
  51. ; 64k segment. The pointer `s' to the buffer must be in a format that
  52. ; all bytes can be accessed by manipulating the offset part, only.
  53. ; This means:
  54. ; + no huge pointers
  55. ; + char buffer size < 64 kByte
  56. ;
  57. ; - Since the buffer size argument `n' is of type `size_t' (= unsigned short)
  58. ; for this routine, the char buffer size is limited to less than 64 kByte,
  59. ; anyway. So, the assumption above should be easily fulfilled.
  60. ;
  61. ;==============================================================================
  62. ;
  63. ; Do NOT assemble this source if external crc32 routine from zlib gets used,
  64. ; or only the precomputed CRC_32_Table is needed.
  65. ;
  66. ifndef USE_ZLIB
  67. ifndef CRC_TABLE_ONLY
  68. ;
  69. ; Setup of amount of assemble time informational messages:
  70. ;
  71. ifdef DEBUG
  72. VERBOSE_INFO EQU 1
  73. else
  74. ifdef _AS_MSG_
  75. VERBOSE_INFO EQU 1
  76. else
  77. VERBOSE_INFO EQU 0
  78. endif
  79. endif
  80. ;
  81. ; Selection of memory model, and initialization of memory model
  82. ; related macros:
  83. ;
  84. ifndef __SMALL__
  85. ifndef __COMPACT__
  86. ifndef __MEDIUM__
  87. ifndef __LARGE__
  88. ifndef __HUGE__
  89. ; __SMALL__ EQU 1
  90. endif
  91. endif
  92. endif
  93. endif
  94. endif
  95. ifdef __HUGE__
  96. ; .MODEL Huge
  97. ifndef @CodeSize
  98. @CodeSize EQU 1
  99. endif
  100. ifndef @DataSize
  101. @DataSize EQU 1
  102. endif
  103. Save_DS EQU 1
  104. if VERBOSE_INFO
  105. if1
  106. %out Assembling for C, Huge memory model
  107. endif
  108. endif
  109. else
  110. ifdef __LARGE__
  111. ; .MODEL Large
  112. ifndef @CodeSize
  113. @CodeSize EQU 1
  114. endif
  115. ifndef @DataSize
  116. @DataSize EQU 1
  117. endif
  118. if VERBOSE_INFO
  119. if1
  120. %out Assembling for C, Large memory model
  121. endif
  122. endif
  123. else
  124. ifdef __COMPACT__
  125. ; .MODEL Compact
  126. ifndef @CodeSize
  127. @CodeSize EQU 0
  128. endif
  129. ifndef @DataSize
  130. @DataSize EQU 1
  131. endif
  132. if VERBOSE_INFO
  133. if1
  134. %out Assembling for C, Compact memory model
  135. endif
  136. endif
  137. else
  138. ifdef __MEDIUM__
  139. ; .MODEL Medium
  140. ifndef @CodeSize
  141. @CodeSize EQU 1
  142. endif
  143. ifndef @DataSize
  144. @DataSize EQU 0
  145. endif
  146. if VERBOSE_INFO
  147. if1
  148. %out Assembling for C, Medium memory model
  149. endif
  150. endif
  151. else
  152. ; .MODEL Small
  153. ifndef @CodeSize
  154. @CodeSize EQU 0
  155. endif
  156. ifndef @DataSize
  157. @DataSize EQU 0
  158. endif
  159. if VERBOSE_INFO
  160. if1
  161. %out Assembling for C, Small memory model
  162. endif
  163. endif
  164. endif
  165. endif
  166. endif
  167. endif
  168. if @CodeSize
  169. LCOD_OFS EQU 2
  170. else
  171. LCOD_OFS EQU 0
  172. endif
  173. IF @DataSize
  174. LDAT_OFS EQU 2
  175. else
  176. LDAT_OFS EQU 0
  177. endif
  178. ifdef Save_DS
  179. ; (di,si,ds)+(size, return address)
  180. SAVE_REGS EQU 6+(4+LCOD_OFS)
  181. else
  182. ; (di,si)+(size, return address)
  183. SAVE_REGS EQU 4+(4+LCOD_OFS)
  184. endif
  185. ;
  186. ; Selection of the supported CPU instruction set and initialization
  187. ; of CPU type related macros:
  188. ;
  189. ifdef __686
  190. Use_286_code EQU 1
  191. Align_Size EQU 4 ; dword alignment on Pentium II/III/IV
  192. Alig_PARA EQU 1 ; paragraph aligned code segment
  193. else
  194. ifdef __586
  195. Use_286_code EQU 1
  196. Align_Size EQU 4 ; dword alignment on Pentium
  197. Alig_PARA EQU 1 ; paragraph aligned code segment
  198. else
  199. ifdef __486
  200. Use_286_code EQU 1
  201. Align_Size EQU 4 ; dword alignment on 32 bit processors
  202. Alig_PARA EQU 1 ; paragraph aligned code segment
  203. else
  204. ifdef __386
  205. Use_286_code EQU 1
  206. Align_Size EQU 4 ; dword alignment on 32 bit processors
  207. Alig_PARA EQU 1 ; paragraph aligned code segment
  208. else
  209. ifdef __286
  210. Use_286_code EQU 1
  211. Align_Size EQU 2 ; word alignment on 16 bit processors
  212. Alig_PARA EQU 0 ; word aligned code segment
  213. else
  214. ifdef __186
  215. Use_186_code EQU 1
  216. Align_Size EQU 2 ; word alignment on 16 bit processors
  217. Alig_PARA EQU 0 ; word aligned code segment
  218. else
  219. Align_Size EQU 2 ; word alignment on 16 bit processors
  220. Alig_PARA EQU 0 ; word aligned code segment
  221. endif ;?__186
  222. endif ;?__286
  223. endif ;?__386
  224. endif ;?__486
  225. endif ;?__586
  226. endif ;?__686
  227. ifdef Use_286_code
  228. .286
  229. Have_80x86 EQU 1
  230. else
  231. ifdef Use_186_code
  232. .186
  233. Have_80x86 EQU 1
  234. else
  235. .8086
  236. Have_80x86 EQU 0
  237. endif ;?Use_186_code
  238. endif ;?Use_286_code
  239. ;
  240. ; Declare the segments used in this module:
  241. ;
  242. if @CodeSize
  243. if Alig_PARA
  244. CRC32_TEXT SEGMENT PARA PUBLIC 'CODE'
  245. else
  246. CRC32_TEXT SEGMENT WORD PUBLIC 'CODE'
  247. endif
  248. CRC32_TEXT ENDS
  249. else ;!@CodeSize
  250. if Alig_PARA
  251. _TEXT SEGMENT PARA PUBLIC 'CODE'
  252. else
  253. _TEXT SEGMENT WORD PUBLIC 'CODE'
  254. endif
  255. _TEXT ENDS
  256. endif ;?@CodeSize
  257. _DATA SEGMENT WORD PUBLIC 'DATA'
  258. _DATA ENDS
  259. _BSS SEGMENT WORD PUBLIC 'BSS'
  260. _BSS ENDS
  261. DGROUP GROUP _BSS, _DATA
  262. if @DataSize
  263. ASSUME DS: nothing, SS: DGROUP
  264. else
  265. ASSUME DS: DGROUP, SS: DGROUP
  266. endif
  267. if @CodeSize
  268. EXTRN _get_crc_table:FAR
  269. else
  270. EXTRN _get_crc_table:NEAR
  271. endif
  272. Do_CRC MACRO
  273. mov bl,al
  274. sub bh,bh
  275. if Have_80x86
  276. shl bx,2
  277. else
  278. shl bx,1
  279. shl bx,1
  280. endif
  281. mov al,ah
  282. mov ah,dl
  283. mov dl,dh
  284. sub dh,dh
  285. xor ax,WORD PTR [bx][si]
  286. xor dx,WORD PTR [bx+2][si]
  287. ENDM
  288. ;
  289. Do_1 MACRO
  290. if @DataSize
  291. xor al,BYTE PTR es:[di]
  292. else
  293. xor al,BYTE PTR [di]
  294. endif
  295. inc di
  296. Do_CRC
  297. ENDM
  298. ;
  299. Do_2 MACRO
  300. ifndef NO_16_BIT_LOADS
  301. if @DataSize
  302. xor ax,WORD PTR es:[di]
  303. else
  304. xor ax,WORD PTR [di]
  305. endif
  306. add di,2
  307. Do_CRC
  308. Do_CRC
  309. else
  310. Do_1
  311. Do_1
  312. endif
  313. ENDM
  314. ;
  315. Do_4 MACRO
  316. Do_2
  317. Do_2
  318. ENDM
  319. ;
  320. IF @CodeSize
  321. CRC32_TEXT SEGMENT
  322. ASSUME CS: CRC32_TEXT
  323. else
  324. _TEXT SEGMENT
  325. ASSUME CS: _TEXT
  326. endif
  327. ; Line 37
  328. ;
  329. ;ulg crc32(ulg crc,
  330. ; ZCONST uch *buf,
  331. ; extent len)
  332. ;
  333. PUBLIC _crc32
  334. if @CodeSize
  335. _crc32 PROC FAR
  336. else
  337. _crc32 PROC NEAR
  338. endif
  339. if Have_80x86
  340. enter WORD PTR 0,0
  341. else
  342. push bp
  343. mov bp,sp
  344. endif
  345. push di
  346. push si
  347. if @DataSize
  348. ; crc = 4+LCOD_OFS DWORD (unsigned long)
  349. ; buf = 8+LCOD_OFS DWORD PTR BYTE (uch *)
  350. ; len = 12+LCOD_OFS WORD (unsigned int)
  351. else
  352. ; crc = 4+LCOD_OFS DWORD (unsigned long)
  353. ; buf = 8+LCOD_OFS WORD PTR BYTE (uch *)
  354. ; len = 10+LCOD_OFS WORD (unsigned int)
  355. endif
  356. ;
  357. if @DataSize
  358. mov ax,WORD PTR [bp+8+LCOD_OFS] ; buf
  359. or ax,WORD PTR [bp+10+LCOD_OFS] ; == NULL ?
  360. else
  361. cmp WORD PTR [bp+8+LCOD_OFS],0 ; buf == NULL ?
  362. endif
  363. jne crc_update
  364. sub ax,ax ; crc = 0
  365. cwd
  366. ifndef NO_UNROLLED_LOOPS
  367. jmp fine
  368. else
  369. jmp SHORT fine
  370. endif
  371. ;
  372. crc_update:
  373. call _get_crc_table
  374. ; When used with compilers that conform to the Microsoft/Borland standard
  375. ; C calling convention, model-dependent handling is not needed, because
  376. ; _get_crc_table returns NEAR pointer.
  377. ; But Watcom C is different and does not allow one to assume DS pointing to
  378. ; DGROUP. So, we load DS with DGROUP, to be safe.
  379. ;if @DataSize
  380. ; push ds
  381. ; mov ds,dx
  382. ; ASSUME DS: nothing
  383. ;endif
  384. mov si,ax ;crc_table
  385. if @DataSize
  386. push ds
  387. mov ax,SEG DGROUP
  388. mov ds,ax
  389. ASSUME DS: DGROUP
  390. endif
  391. ;
  392. mov ax,WORD PTR [bp+4+LCOD_OFS] ;crc
  393. mov dx,WORD PTR [bp+6+LCOD_OFS]
  394. not ax
  395. not dx
  396. if @DataSize
  397. les di,DWORD PTR [bp+8+LCOD_OFS] ;buf
  398. mov cx,WORD PTR [bp+12+LCOD_OFS] ;len
  399. else
  400. mov di,WORD PTR [bp+8+LCOD_OFS] ;buf
  401. mov cx,WORD PTR [bp+10+LCOD_OFS] ;len
  402. endif
  403. ;
  404. ifndef NO_UNROLLED_LOOPS
  405. ifndef NO_16_BIT_LOADS
  406. test cx,cx
  407. jnz start
  408. jmp done
  409. start: test di,1
  410. jz is_wordaligned
  411. dec cx
  412. Do_1
  413. mov WORD PTR [bp+10+LDAT_OFS+LCOD_OFS],cx
  414. is_wordaligned:
  415. endif ; !NO_16_BIT_LOADS
  416. if Have_80x86
  417. shr cx,2
  418. else
  419. shr cx,1
  420. shr cx,1
  421. endif
  422. jz No_Fours
  423. ;
  424. align Align_Size ; align destination of branch
  425. Next_Four:
  426. Do_4
  427. ifndef OPTIMIZE_286_88
  428. dec cx ; on 286, "loop Next_Four" needs 11
  429. jnz Next_Four ; clocks, one less than this code
  430. else
  431. loop Next_Four
  432. endif
  433. ;
  434. No_Fours:
  435. if @DataSize
  436. mov cx,WORD PTR [bp+12+LCOD_OFS] ;len
  437. else
  438. mov cx,WORD PTR [bp+10+LCOD_OFS] ;len
  439. endif
  440. and cx,00003H
  441. endif ; !NO_UNROLLED_LOOPS
  442. jz done
  443. ;
  444. align Align_Size ; align destination of branch
  445. Next_Byte:
  446. Do_1
  447. ifndef OPTIMIZE_286_88
  448. dec cx ; on 286, "loop Next_Four" needs 11
  449. jnz Next_Byte ; clocks, one less than this code
  450. else
  451. loop Next_Four
  452. endif
  453. ;
  454. done:
  455. if @DataSize
  456. pop ds
  457. ; ASSUME DS: DGROUP
  458. ASSUME DS: nothing
  459. endif
  460. not ax
  461. not dx
  462. ;
  463. fine:
  464. pop si
  465. pop di
  466. if Have_80x86
  467. leave
  468. else
  469. mov sp,bp
  470. pop bp
  471. endif
  472. ret
  473. _crc32 ENDP
  474. if @CodeSize
  475. CRC32_TEXT ENDS
  476. else
  477. _TEXT ENDS
  478. endif
  479. ;
  480. endif ;!CRC_TABLE_ONLY
  481. endif ;!USE_ZLIB
  482. ;
  483. END