ariphmetic.asm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. ;***
  2. ; двухбайтное сравнение
  3. ldi r16,low(777)
  4. cpi zh,high(777)
  5. cpc zl,r16
  6. ==========
  7. .def dataL = r4 ; multiplicand low byte
  8. .def dataH = r5 ; multiplicand high byte
  9. .def KoeffL = r2 ; multiplier low byte
  10. .def koeffH = r3 ; multiplier high byte
  11. .def temp = r16 ; result byte 0 (LSD)
  12. .def temp1 = r17 ; result byte 1
  13. .def temp2 = r18 ; result byte 2 (MSD)
  14. ;**************************************************************************
  15. ; умножение двух 16-разрядных величин, только для Mega
  16. ; исходные величины dataH-dataL и KoeffH-KoeffL
  17. ; результат 3 байта temp2:temp1:temp
  18. Mul16:
  19. clr temp2 ; очистить старший
  20. mul dataL,KoeffL ; умножаем младшие
  21. mov temp,r0 ; в R0 младший результата операции mul
  22. mov temp1,r1 ; в R1 старший результата операции mul
  23. mul dataH,KoeffL ; умножаем старший на младший
  24. add temp1,r0 ; в R0 младший результата операции mul
  25. adc temp2,r1 ; в R1 старший результата операции mul
  26. mul dataL,KoeffH ; умножаем младший на старший
  27. add temp1,r0 ; в R0 младший результата операции mul
  28. adc temp2,r1 ; в R1 старший результата операции mul
  29. mul dataH,KoeffH ; умножаем старший на старший
  30. add temp2,r0 ; 4-й разряд нам тут не требуется, но он - в R1
  31. ret
  32. ;**************************************************************************
  33. ==================================
  34. ;***************************************************************************
  35. ; перемножение двух 16-разрядных величин,
  36. ; результат 3 байта
  37. mpy16u: clr tmp2
  38. ldi count,16 ;init loop counter
  39. m16u_1: lsr KoeffH
  40. ror KoeffL
  41. brcc noad8 ;if bit 0 of multiplier set
  42. add tmpm,IzmL ;add multiplicand Low to byte 2 of res
  43. adc tmp2,IzmH ;add multiplicand high to byte 3 of res
  44. noad8: ror tmp2 ;rotate right result byte 2
  45. ror tmpm ;rotate result byte 1 and multiplier High
  46. ror temp ;rotate result byte 0 and multiplier Low
  47. dec count ;decrement loop counter
  48. brne m16u_1 ;if not done, loop more
  49. ret
  50. ;***************************************************************************
  51. ; перемножение двух 16-разрядных величин, результат 4 байта, рабочая
  52. ; множимое KoeffH:KoeffL, множитель IzmH:IzmL, результат tmp3:tmp2:tmpm:temp
  53. ; использует count
  54. ; слов: 14 + return. циклов: 153 + return + rcall
  55. mpy16u: clr tmp3 ;clear 2 highest bytes of result
  56. clr tmp2
  57. ldi count,16 ;init loop counter
  58. m16u_1: lsr KoeffH
  59. ror KoeffL
  60. brcc noad8 ;if bit 0 of multiplier set
  61. add tmp2,IzmL ;add multiplicand Low to byte 2 of res
  62. adc tmp3,IzmH ;add multiplicand high to byte 3 of res
  63. noad8: ror tmp3 ;shift right result byte 3
  64. ror tmp2 ;rotate right result byte 2
  65. ror tmpm ;rotate result byte 1 and multiplier High
  66. ror temp ;rotate result byte 0 and multiplier Low
  67. dec count ;decrement loop counter
  68. brne m16u_1 ;if not done, loop more
  69. ret
  70. ==================================
  71. ;***************************************************
  72. ;* Mutiply 32x32 -> 64 bit
  73. ;* A B C
  74. ;* R24:R21 x R5:R2 -> R15:R8
  75. ;*
  76. ;* 88 cycles + 4 (RET) = 92 Cycles
  77. ;*
  78. mult32:
  79. clr R16
  80. mul R21,R2 ; умножили A1 на Б1
  81. movw R8,R0 ; рез положили в Ц1-2
  82. clr R10
  83. clr R11
  84. clr R12
  85. clr R13
  86. clr R14
  87. clr R15
  88. mul R22,R2 ; умн А2 на Б1
  89. add R9,R0 ; рез1 доб к Ц2
  90. adc R10,R1 ; рез2 доб к Ц3
  91. mul R23,R2 ; умн А3 на Б1
  92. add R10,R0 ; рез1 доб к Ц3
  93. adc R11,R1 ; рез2 доб к Ц4
  94. mul R24,R2 ; А4 умн на Б1
  95. add R11,R0 ; рез1 доб к Ц4
  96. adc R12,R1 ; рез2 доб к Ц5
  97. mul R21,R3
  98. add R9,R0
  99. adc R10,R1
  100. adc R11,R16
  101. adc R12,R16
  102. adc R13,R16
  103. mul R22,R3
  104. add R10,R0
  105. adc R11,R1
  106. adc R12,R16
  107. adc R13,R16
  108. mul R23,R3
  109. add R11,R0
  110. adc R12,R1
  111. adc R13,R16
  112. mul R24,R3
  113. add R12,R0
  114. adc R13,R1
  115. mul R21,R4
  116. add R10,R0
  117. adc R11,R1
  118. adc R12,R16
  119. adc R13,R16
  120. adc R14,R16
  121. mul R22,R4
  122. add R11,R0
  123. adc R12,R1
  124. adc R13,R16
  125. adc R14,R16
  126. mul R23,R4
  127. add R12,R0
  128. adc R13,R1
  129. adc R14,R16
  130. mul R24,R4
  131. add R13,R0
  132. adc R14,R1
  133. mul R21,R5
  134. add R11,R0
  135. adc R12,R1
  136. adc R13,R16
  137. adc R14,R16
  138. adc R15,R16
  139. mul R22,R5
  140. add R12,R0
  141. adc R13,R1
  142. adc R14,R16
  143. adc R15,R16
  144. mul R23,R5
  145. add R13,R0
  146. adc R14,R1
  147. adc R15,R16
  148. mul R24,R5
  149. add R14,R0
  150. adc R15,R1
  151. ret
  152. ==================================
  153. ;***************************************************
  154. ;* Mutiply 24x16 -> 40 bit (3*2=5 Bytes)
  155. ;* A B C
  156. ;* R23:R21 x R3:R2 -> R12:R8
  157. ;*
  158. ;* 30 cycles + 4 (RET) = 34 Cycles
  159. ;*
  160. mul24x16:
  161. clr R16
  162. mul R21,R2 ; A1*B1
  163. movw R8,R0 ; Rez->C1C2
  164. clr R10
  165. clr R11
  166. clr R12
  167. mul R22,R2 ; A2*B1
  168. add R9,R0 ; C2+=Rez1
  169. adc R10,R1 ; C3+=Rez2
  170. mul R23,R2 ; A3*B1
  171. add R10,R0 ; C3+=Rez1
  172. adc R11,R1 ; C4+=Rez2
  173. mul R21,R3 ; A1*B2
  174. add R9,R0 ; C2+=Rez1
  175. adc R10,R1 ; C3+=Rez2
  176. adc R11,R16 ; C4+=C flag
  177. adc R12,R16 ; C5+=C flag
  178. mul R22,R3 ; A2*B2
  179. add R10,R0 ; C3+=Rez1
  180. adc R11,R1 ; C4+=Rez2
  181. adc R12,R16 ; C5+=C flag
  182. mul R23,R3 ; A3*B2
  183. add R11,R0 ; C4+=Rez1
  184. adc R12,R1 ; C5+=Rez2
  185. ret
  186. ;***************************************************************************
  187. ;*
  188. ;* "mpy16u8" - 16x8 Bit Unsigned Multiplication
  189. ;*
  190. ;* This subroutine multiplies 16-bit and 8-bit register variables
  191. ;* mp16uH:mp16uL and mc16uL
  192. ;* The result is placed in m16u2:m16u1:m16u0.
  193. ;*
  194. ;* Number of words :13 + return
  195. ;* Number of cycles :137? + return
  196. ;* Low registers used :1 (R0)
  197. ;* High registers used :5 (mc16uL,mp16uL/m16u0,mp16uH/m16u1,m16u2,mcnt16u)
  198. ;*
  199. ;***************************************************************************
  200. ;***** Subroutine Register Variables
  201. .def mc16uL =r16 ;multiplicand low byte
  202. .def mp16uL =r18 ;multiplier low byte
  203. .def mp16uH =r19 ;multiplier high byte
  204. .def m16u0 =r18 ;result byte 0 (LSB)
  205. .def m16u1 =r19 ;result byte 1
  206. .def m16u2 =r20 ;result byte 2
  207. .def mcnt16u =r22 ;loop counter
  208. ;***** Code
  209. mpy16u8:clr R0
  210. clr m16u2 ;clear high byte of result
  211. ldi mcnt16u,16 ;init loop counter
  212. m16u_1: lsr mp16uH
  213. ror mp16uL
  214. brcc noad8 ;if bit 0 of multiplier set
  215. add m16u1,mc16uL ;add multiplicand Low to byte 1 of res
  216. adc m16u2,R0 ;add multiplicand high to byte 2 of res
  217. noad8: ror m16u2 ;rotate right result byte 2
  218. ror m16u1 ;rotate result byte 1 and multiplier High
  219. ror m16u0 ;rotate result byte 0 and multiplier Low
  220. dec mcnt16u ;decrement loop counter
  221. brne m16u_1 ;if not done, loop more
  222. ret
  223. ==================================
  224. ;*************************************************************************
  225. ; div32x8 - 32/8 деление беззнаковых чисел
  226. ; Делимое и результат в countHH (старший), countTH,
  227. ; countTM, countTL (младший)
  228. ; делитель в cikle
  229. ; требуется четыре рабочих регистра dremL — dremHH
  230. ; из диапазона R16-R31 для хранения остатка
  231. div32x8:
  232. clr temp ; "ZERO"
  233. clr dremL ;clear remainder Low byte
  234. clr dremM ;clear remainder
  235. clr dremH ;clear remainder
  236. sub dremHH,dremHH ;clear remainder High byte and carry
  237. ldi cnt,33 ;init loop counter
  238. d_1: rol countTL ;shift left dividend
  239. rol countTM
  240. rol countTH
  241. rol countHH
  242. dec cnt ;decrement counter
  243. brne d_2 ;if done
  244. ret ;return
  245. d_2: rol dremL ;shift dividend into remainder
  246. rol dremM
  247. rol dremH
  248. rol dremHH
  249. sub dremL,cikle ;remainder = remainder — divisor
  250. sbc dremM,temp
  251. sbc dremH,temp
  252. sbc dremHH,temp
  253. brcc d_3 ;if result negative
  254. add dremL,cikle ;restore remainder
  255. adc dremM,temp
  256. adc dremH,temp
  257. adc dremHH,temp
  258. clc ;clear carry to be shifted into result
  259. rjmp d_1 ;else
  260. d_3: sec ; set carry to be shifted into result
  261. rjmp d_1
  262. ; ************************************************************** конец 32/8
  263. ====================================
  264. ;***************************************************************************
  265. ;*
  266. ;* "div24u16" - 24/16 Bit Unsigned Division
  267. ;* (по сути это 24/24)
  268. ;* Эта процедура делит 3-х байтное число на 2-х байтное
  269. ;* "dd16uH:dd16uM:dd16uL" (dividend) and "dv16uH:dv16uL" (divisor).
  270. ;* The result is placed in "dres16uH:dres16uM:dres16uL" and the remainder in
  271. ;* "drem16uH:drem16uM:drem16uL".
  272. ;*
  273. ;* Number of words :25 (50 bytes)
  274. ;* Number of cycles :?/? (Min/Max)
  275. ;* Low registers used :7 (drem16uL,drem16uM,drem16uH,dres16uL/dd16uL,dres16uM/dd16uM,dres16uH/dd16uH,ZERO)
  276. ;* High registers used :3 (dv16uL,dv16uH,dcnt16u)
  277. ;*
  278. ;***************************************************************************
  279. ;***** Subroutine Register Variables
  280. .def ZERO =R12
  281. .def drem16uL=r13
  282. .def drem16uM=r14
  283. .def drem16uH=r15
  284. .def dres16uL=r16
  285. .def dres16uM=r17
  286. .def dres16uH=r18
  287. .def dd16uL =r16
  288. .def dd16uM =r17
  289. .def dd16uH =r18
  290. .def dv16uL =r19
  291. .def dv16uH =r20
  292. .def dcnt16u =r21
  293. ;***** Code
  294. div24u: clr ZERO
  295. clr drem16uL ;clear remainder Low byte
  296. clr drem16uM ;clear remainder Middle byte
  297. sub drem16uH,drem16uH;clear remainder High byte and carry
  298. ldi dcnt16u,25 ;init loop counter
  299. d24u_1: rol dd16uL ;shift left dividend
  300. rol dd16uM
  301. rol dd16uH
  302. dec dcnt16u ;decrement counter
  303. brne d24u_2 ;if done
  304. ret ; return
  305. d24u_2: rol drem16uL ;shift dividend into remainder
  306. rol drem16uM
  307. rol drem16uH
  308. sub drem16uL,dv16uL ;remainder = remainder - divisor
  309. sbc drem16uM,dv16uH
  310. sbc drem16uH,ZERO
  311. brcc d24u_3 ;if result negative
  312. add drem16uL,dv16uL ; restore remainder
  313. adc drem16uM,dv16uH
  314. adc drem16uH,ZERO
  315. clc ; clear carry to be shifted into result
  316. rjmp d24u_1 ;else
  317. d24u_3: sec ; set carry to be shifted into result
  318. rjmp d24u_1
  319. ; *************************************************************************
  320. ; процедура деления 24/8 отличается от 24/16 только тем,
  321. ; что старший байт делителя всегда равен 0
  322. ; *************************************************************************
  323. ; div24u8 - 24/8 деление беззнаковых чисел
  324. ; Делимое и результат в countH (старший), countTM, countTL (младший)
  325. ; делитель в divisor, использует R0, cnt
  326. ; требуется три рабочих регистра dremL — dremH для хранения остатка
  327. ; 25 слов, 5+24*(17-19)+5+4=(408-456)+14=422--470 тактов
  328. ; + 3 такта на rcall :-)
  329. div24u8:clr R0
  330. clr dremL ;clear remainder Low byte
  331. clr dremM ;clear remainder Midle byte
  332. sub dremH,dremH ;clear remainder High byte and carry
  333. ldi cnt,25 ;init loop counter
  334. d_1: rol countTL ;shift left dividend
  335. rol countTM
  336. rol countTH
  337. dec cnt ;decrement counter
  338. brne d_2 ;if done
  339. ret ;return
  340. d_2: rol dremL ;shift dividend into remainder
  341. rol dremM
  342. rol dremH
  343. sub dremL,divisor ;remainder = remainder — divisor
  344. sbc dremM,R0
  345. sbc dremH,R0
  346. brcc d_3 ;if result negative
  347. add dremL,divisor ;restore remainder
  348. adc dremM,R0
  349. adc dremH,R0
  350. clc ;clear carry to be shifted into result
  351. rjmp d_1 ;else
  352. d_3: sec ; set carry to be shifted into result
  353. rjmp d_1
  354. ; ************************************************************** конец 24/8
  355. ;***************************************************************************
  356. ;*
  357. ;* "div16u8" - 16/8 Bit Unsigned Division
  358. ;*
  359. ;* This subroutine divides the 16-bit / 8-bit numbers
  360. ;* "dd16uH:dd16uL" (dividend) and "dv16uL" (divisor).
  361. ;* The result is placed in "dres16uH:dres16uL" and the remainder in
  362. ;* "drem16uH:drem16uL".
  363. ;*
  364. ;* Number of words :19
  365. ;* Number of cycles :235/251 (Min/Max)
  366. ;* Low registers used :2 (drem16uL,drem16uH)
  367. ;* High registers used :4 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dcnt16u)
  368. ;*
  369. ;***************************************************************************
  370. ;***** Subroutine Register Variables
  371. .def drem16uL=r14
  372. .def drem16uH=r15
  373. .def dres16uL=r16
  374. .def dres16uH=r17
  375. .def dd16uL =r16
  376. .def dd16uH =r17
  377. .def dv16uL =r18
  378. .def dcnt16u =r19
  379. ;***** Code
  380. div16u: clr R0
  381. clr drem16uL ;clear remainder Low byte
  382. sub drem16uH,drem16uH;clear remainder High byte and carry
  383. ldi dcnt16u,17 ;init loop counter
  384. d16u_1: rol dd16uL ;shift left dividend
  385. rol dd16uH
  386. dec dcnt16u ;decrement counter
  387. brne d16u_2 ;if done
  388. ret ; return
  389. d16u_2: rol drem16uL ;shift dividend into remainder
  390. rol drem16uH
  391. sub drem16uL,dv16uL ;remainder = remainder - divisor
  392. sbc drem16uH,R0 ;
  393. brcc d16u_3 ;if result negative
  394. add drem16uL,dv16uL ; restore remainder
  395. adc drem16uH,R0
  396. clc ; clear carry to be shifted into result
  397. rjmp d16u_1 ;else
  398. d16u_3: sec ; set carry to be shifted into result
  399. rjmp d16u_1
  400. ====================================
  401. ;******************************
  402. ; делим двубайтное число на 10
  403. ; вход: JobH:JobL
  404. ; выход: XH:XL, остаток может быть в JobL
  405. ; использует:
  406. DIV16_10:
  407. clr XL ; инициируем счётчик десятков
  408. clr XH
  409. sbiw X,1
  410. DIV16_10_l1:
  411. adiw X,1 ; увеличили счётчик
  412. sbiw JobL,10 ; уменьшили исходное число
  413. brsh DIV16_10_l1 ; если остаток > 0 -- ещё на круг
  414. ; inc JobL ; если нужен остаток
  415. ret