| CODE |
| NOLIST ; This file is part of picide, ATA(PI) interface to PIC18 family MCUs. ; Copyright (C) 2004-5 Toby Thain, toby@telegraphics.com.au ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA LIST TITLE picide SUBTITLE "Utility routines" ;; Version history ;; 21-Oct-2004: 0.1 - started by Toby ;; 23-Feb-2005: 1.0 - public release under GPL ; contents of this module: global udiv8_8 ; unsigned divide 8 bits by 8 bits global udiv16_8 ; unsigned divide 16 bits by 8 bits global udiv16_16; unsigned divide 16 bits by 16 bits global udiv32_16; unsigned divide 32 bits by 16 bits global divd,divs; dividend & divisor, inputs to above routines global hexdigit ; print W reg as ASCII hex digit global puthex ; print W as two hex digits global putdec ; print W as decimal digits global putdec16 ; print 16 bit value in dec16 as decimal global dec16 ; input to above routine global decstr ; scratch space for above routine global dumpsec ; print sector buffer in hex/ASCII, # lines in W global dumpstuff; dump memory from FSR1 in hex/ASCII, # lines in W global rnd8 ; quick and dirty LFSR (semi-random numbers) global LFSRVALUEL; LFSR state #define UTIL_ASM #include "defs.inc" #define DUMPCOLS 16 ; controls format of hex dump routines extern putch udata_acs divd res 4; dividend: 32 bits divs res 2; divisor: 16 bits dtemp res 2 divcnt res 1 temp res 1 rnd res 1 rndcnt res 1 decstr res 8 dec16 res 2; value used by putdec16 digcnt res 1 rowcnt res 1; used by dumpsec colcnt res 2 dumpad res 2 ascii res DUMPCOLS+1 LFSRVALUEL res 1; used by rnd8 psltemp res 1; used by putstrbits,putstrlist code putdec: movwf divd lfsr 0,decstr+7 clrf digcnt decdig: movlw 10 rcall udiv8_8 movff divd+1,POSTDEC0; remainder - store digits backwards incf digcnt tstfsz divd; quotient bra decdig ; no more digits ; output digits forwards pdig: movf PREINC0,w addlw '0' call putch decfsz digcnt bra pdig return putdec16: lfsr 0,decstr+7 ; set divisor movlw 10 movwf divs clrf divs+1 ; set initial dividend movff dec16,divd movff dec16+1,divd+1 clrf digcnt decdigb: rcall udiv16_16 movff divd+2,POSTDEC0; remainder - store digits backwards incf digcnt ; quotient becomes next dividend tstfsz divd bra decdigb tstfsz divd+1 bra decdigb ; output digits forwards pdigb: movf PREINC0,w addlw '0' call putch decfsz digcnt bra pdig return puthex: movwf temp swapf temp,w rcall hexdigit movf temp,w hexdigit: andlw 0x0f addlw -10 bn isdec addlw 'A'-'0'-10 isdec: addlw '0'+10 goto putch ; print a hex/ASCII dump of the sector buffer dumpsec:; # lines is in Wreg lfsr 1,secbuf; set up read pointer dumpstuff:; alternative entry with FSR1 pointing at data movwf rowcnt clrf dumpad; zero offset clrf dumpad+1 dorow:; print hex offset at start of each line movf dumpad+1,w rcall puthex movf dumpad,w rcall puthex _putchar ':' lfsr 2, ascii; set up write pointer movlw DUMPCOLS; # columns (bytes per line) movwf colcnt addwf dumpad; bump offset by bytes per line bnc docol incf dumpad+1 docol: movlw 0x7e cpfsgt INDF1 bra sevenb; it's 7-bit, and not DEL nonprint: movlw '.' movwf POSTINC2 bra dohex sevenb: movlw 0x1f cpfsgt INDF1 bra nonprint; it's a control char movff INDF1,POSTINC2; it's ASCII, copy it over dohex: movf POSTINC1,w rcall puthex decfsz colcnt bra docol _putchar ' ' ; print ASCII row clrf INDF2; add terminating NUL _putstrd ascii _crlf decfsz rowcnt bra dorow return ; helper routines used by macros in defs.inc global putstrtail,putstrlist,putstrbits,psbit,putstrpc,psltemp ; print NUL-terminated string at TBLPTR putstrtail: putit: tblrd *+ movf TABLAT,w bz donestr call putch bra putit donestr:return ; print NUL-terminated string at PC putstrpc: movff TOSU,TBLPTRU movff TOSH,TBLPTRH movff TOSL,TBLPTRL putstr2:rcall putstrtail ; adjust return address to after end of string fixuppc:btfsc TBLPTRL,0; is ptr odd? tblrd *+; yes, bump it by one movf TBLPTRU,w; copy to return PC movwf TOSU; ** cannot use movff ** movf TBLPTRH,w movwf TOSH movf TBLPTRL,w movwf TOSL return ; macro helper ; find indexed string in NUL-terminated list (at PC), print it putstrlist: movff TOSU,TBLPTRU movff TOSH,TBLPTRH movff TOSL,TBLPTRL addlw 0; set flags on W bz putstr2 skip: tblrd *+ movf TABLAT,f bnz skip decfsz WREG bra skip print: bra putstr2; print the string pointed at IF 0; old version putstrlist: movf psltemp,w isthis: bz print skip: tblrd *+ movf TABLAT,f bnz skip addlw -1 bra isthis print: bra putstrtail; print the string pointed at ENDIF ; macro helper ; print strings corresponding to bit vector, msb first putstrbits: movwf psltemp movff TOSU,TBLPTRU movff TOSH,TBLPTRH movff TOSL,TBLPTRL call psbit bra fixuppc psbit: bcf STATUS,C rlcf psltemp,f bc printit; high bit was set btfsc STATUS,Z; nothing left? return ; skip to next string skipbit: tblrd *+ movf TABLAT,f bnz skipbit bra psbit printit: rcall putstrtail bra psbit IF 0; old version putstrbits: movf psltemp,w nextbit:bcf STATUS,C rlcf psltemp bc printit; high bit was set btfsc STATUS,Z; nothing left to print return ; skip to next string skipbit: tblrd *+ movf TABLAT,f bnz skipbit bra nextbit printit:rcall putstrtail bra nextbit ENDIF ; Galois LFSR ; from: http://www.piclist.com/techref/microchip/rand8bit.htm ; more info: http://www.shmoo.com/crypto/Cracking_DES/CH10/main.html ; seed LFSRVALUEL with a non zero value rnd8: BCF STATUS,C RRCF LFSRVALUEL,W BTFSC STATUS,C XORLW 0xB4; nice trick, sets the incoming MSB according to carry MOVWF LFSRVALUEL return ; integer division ; based on code in Nova Programmer's Reference, p E-4 ; on entry: divisor in W ; dividend in divdhi,divdlo (16 bits) ; on exit: quotient in divdlo, remainder in divdhi ; carry set if overflow udiv8_8: clrf divd+1; dividend is 8 bits only udiv16_8: movwf divs subwf divd+1,w; dividend hi < divisor? bc oflow; no - result won't fit in 8 bits movlw 8 ; width of divisor movwf divcnt ; carry is clear here rlcf divd dloop: rlcf divd+1 movf divs,w subwf divd+1,w ; carry is set if result zero or positive bnc next movwf divd+1; store subtracted result next: rlcf divd decfsz divcnt bra dloop oflow: return udiv16_16:; 16 bit dividend only clrf divd+2 clrf divd+3 ; divide 32 bit value by 16 bit value ; 16 bit quotient in divd1,0 ; 16 bit remainder in divd2,3 udiv32_16:; OVERFLOW IS NOT CHECKED movlw 16; width of divisor movwf divcnt bcf STATUS,C; clear carry here rlcf divd rlcf divd+1 loopb: rlcf divd+2 rlcf divd+3 ; trial subtraction - divisor from high word of dividend movff divd+2,dtemp movf divs,w subwf dtemp movff divd+3,dtemp+1 movf divs+1,w subwfb dtemp+1 ; carry is set if result zero or positive bnc nextb movff dtemp,divd+2; store subtracted result movff dtemp+1,divd+3 nextb: rlcf divd rlcf divd+1 decfsz divcnt bra loopb return end |