In this months issue of the Massmind newsletter:
These items will appear on the site in a month or so, but you get them first with a subscription to the newsletter!
While laying out the registers for an application, I needed a counter for shifting out bits (count from 8 to zero) and so I allocated a byte in the global register space and dismissed the missgiving I had about wasting the top 5 bit of the byte. I really needed a lot of speed for the routine that was shifting out the bits so I didn't want to mask off the top x bits to test for zero.
As it turned out, I didn't run out of registers, I ran out of code space.
Reviewing the code, I realized that I was spending a lot of code bank switching between buffer head and tail pointers that I hadn't quite been able to squeeze into global space and the bank where the buffer was actually stored. Finding some more global memory would help reduce the code size.
I had one byte of global space allocated to flags, and only 5 bits used. I re-checked the bits and found that I could move one to a bank without any additional code so that left 4 bits to find a home for. I though of that short counter, but reviewing the VP code convinced me that I just could not afford to check for zero with any extra instructions. The original analysis of the job was based on how fast we could shift out those bits and I specified an SX at 75MHz and had written the bit shifting code in my head at the time.
I started thinking about how to tell if a part of a byte has reached zero and eventually realized that when the lower 3 bits were decremented from 0, the 4th bit would be cleared and that could be used to test for zero!
... and so on until
And I realized that I could reload the counter simply by setting the 4th bit! No need to load a literal value. I moved the remaining 4 flag bits into the top of the "Half counter" byte and rewrote the bit code (which now had less of a delay between bytes for a small increase in the overall bitrate).
Since then, I've seen a number of cases where this trick has been of great value. I've used it to dispatch VP's when one needed to be executed once for every 4 interrupts (for example) by checking the second bit. Well, on that one you do have to check the bottom bit as well... Another use was when I needed to check for the occurance of 2 different things, but I didn't care what order they came in. I decremented once when I found one type, twice when I found another. I could do a single bit check to see which had arrived (so as to not accept two of the same thing) but still just do a single bit test to check for the arrival of both signals.
One of these days, I'll write a macro to automatically compile the best code for any FOR start TO end type loop.
When you need a jump table (not a lookup table; iread is better for that) for 4 or fewer routines, bit testing is actually more efficient than adding an offset to the PC and then jumping from there.
Since I am (as Peter said) a "macro freak" I wrote the following macros for SASM to automatically compile bit tests and jumps for up to 8 addreses (based on the value of the bottom 3 bits of a register). It is almost as good as a jump table at that size, and better below that. The macros start with binjmp2 which only accepts two different labels and one bit. For example:
binjmp2 status.c, carry, nocarry
and will generate:
jnb flag, first jmp second
It assumes that an equate called pageaddr is set to the current page and if one of the destinations is outside this page, it generates "long" jumps with the @ before the label instead.
binjmp2 MACRO index, one, two ;assumes that pageaddr is set to current value of page bits on entry. noexpand pageaddr = $>>9 ifdef one if (pageaddr == one >> 9) expand jnb index.0,one noexpand else pageaddr = $ >> 9 expand jnb index.0,@one noexpand endif else pageaddr = $ >> 9 expand jnb index.0,@one noexpand endif ifdef two if (pageaddr == two >> 9) expand jmp two noexpand else pageaddr = $ >> 9 expand jmp @two noexpand endif else pageaddr = $ >> 9 expand jmp @two noexpand endif endm
With this routine under our belt, we can build binjmp4 which calls it twice for 4 addresses or once for 3 or 1 and takes care of the other address itself. There is some tricky page bit testing here based on the routine knowing that the next set of bit tests can't be more than a certain distance away. It works, trust me (he says)
binjmp4 MACRO index, one, two, three, four local :1set ;assumes that pageaddr is set to current value of page bits on entry. if (pageaddr == ($+9)>>9) ;:1set can't be more than 9 words away. expand jb index.1, :1set noexpand else expand sb index.1 page :1set jmp :1set noexpand endif binjmp2 index, one, two expand :1set noexpand pageaddr = $ >> 9 ;can't get here except by jump and so must be paged binjmp2 index, three, four endm
Now! we can get crazy and build one that handles any number of jumps by calling
binjmp4 or binjmp2 and takeing care of the odd lable itself. This also sets
the page and the pageaddr value so we don't have to think about anything!
To use it, just enter
BinJump <reg>, <Address> [, <Address>]
where <reg> is the first parameter of the register to tbe tested and the following parameters are a list of addresses to jump to based on the value of the register.
binjump MACRO local :2Set, :1Set, parms, index parms = \0 - 1 index = \1 ;Call with the first parameter of the register to tbe tested and ;the following parameters a list of addresses to jump to based on ;the value of the register. ;More effecient than a long jump table for 4 or fewer addresses expand page $ noexpand pageaddr = $ >> 9 if parms > 4 if parms == 5 expand jb \1.2, @\6 ;=4 noexpand binjmp4 \1,\2,\3,\4,\5 else ;6 or more if (pageaddr == ($+19)>>9) expand jb \1.2, :2Set ;>4 ;@$+16 noexpand else expand sb \1.2 page :2set jmp :2set ;>4 ;@$+16 noexpand endif binjmp4 \1,\2,\3,\4,\5 expand :2Set noexpand pageaddr = $ >> 9 ;can't get here except by jump and so must be paged if parms > 6 if parms > 7 binjmp4 \1,\6,\7,\8,\9 else ;7 expand jb \1.2, @\8 ;=2 or 6 noexpand binjmp4 \1,\2,\3,\6,\7 endif else ;6 binjmp2 \1,\6,\7 endif endif else ;4 or less if parms > 2 if parms == 3 expand jb \1.1, @\4 ;=2 or 6 noexpand binjmp2 \1,\2,\3 else ;4 binjmp4 \1,\2,\3,\4,\5 endif else ;2 binjmp2 \1, \2, \3 endif endif endm
There is also a GotoW macro at
http://www.sxlist.com/techref/ubicom/sasmcond.src that compiles either a binjmp or a regular jump table based on the number of addresses and does some tricky testing for pageing.
sxlist.com member BCI-hotmail-K96 added some code for the PIC16F84a to interface to the graphic LCD module LPH 7366-1 used in the Nokia 5110 cell Phone. These are very nice little LCD modules available for about $25 on ebay and all over the web.. This is a High-resolution, illuminated, graphical display; Up to 5 lines for text, numbers, graphics; Dynamic display for large/small font. It uses a PCD8544 48 x 84 pixels matrix LCD controller/driver. Beats the hell of of the other "serial LCD units" available. All the info is at http://sandiding.tripod.com/lcd.html including the wireing, power supply, etc...
Running the through the Code converter from MPASM to SASM at:
http://www.sxlist.com/cgi-bin/mpasm2sasm2.exe gives us the following which should be ready to go with only a few tweaks. If anyone tries it, please let me know.
;=======LCD_Nokia nse1,nse3,nsm1 / Version 10====================$21/$12/$02== ; cod LPH7366-$1 / driver PCD8544 ; rb6,rb7 sclock,sdata ; ra0,ra1,ra2,ra3 d/C,Reset,Vccmd,SCE ; internal clock ; standard crystal 4000 MHz XT - 1us pe instructiune/pe aproape ; Program realizat de Ing. Bergthaller Iulian-Alexandru ;------------------------------------------------------------ list p=$16f84A;f=inhx8m _CP_OFF equ $3FFF ;code protect off _PWRTE_ON equ $3FFF ;Power on timer on _WDT_OFF equ $3FFB ;watch dog timer off _XT_OSC equ $3FFD ;crystal oscillator __CONFIG _CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC ;------------------------------------------------------------ ; cpu init porta equ $05 portb equ $06 count1 equ $0C count2 equ $0D count3 equ $0E afisaj equ $0F ;LPH7366 pinout: ; pin1 V+ ; pin2 Sclk ; pin3 Sda ; pin4 DorC ; pin5 Cs ; pin6 Osc (32768Hz external clock) ; pin7 Gnd ; pin8 Vout(DC/DC voltage converter) ; pin9 Reset #DEFINE sclk portb,$6 #DEFINE sdta portb,$7 #DEFINE dorc porta,$0 #DEFINE rset porta,$1 #DEFINE tens porta,$2 #DEFINE enab porta,$3 ;------------------------------------------------------------ ; bit init w equ $0 ;------------------------------------------------------------ org $0 ; ;------------------------------------------------------------ init mov W, #$0 ;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction. ; tris portb ; set portb as output ; set portb as output mov Rb, W ; all ouput low mov W, #$0 ;*** WARNING: TRIS expanded in two instructions. Check if previous instruction is a skip instruction. ; tris porta ; set portb as output ; set portb as output mov Ra, W ; all ouput low start call pause setb dorc setb enab setb tens ;activare tensiune call lcres ;resetare cca. 250ms mov W, #21H ;set extins mov afisaj, W call lccmd mov W, #197 ;Vop mov afisaj, W call lccmd mov W, #13H ;bias mov afisaj, W call lccmd mov W, #20H ;afisare orizontala mov afisaj, W call lccmd mov W, #09H ;mod control all on mov afisaj, W call cbild ;resetare DDRAM call lccmd call pause mov W, #08H ;mod control blank mov afisaj, W call lccmd call pause mov W, #0CH ;mod control normal mov afisaj, W call lccmd mov W, #40H ;x ini mov afisaj, W call lccmd mov W, #80H ;y ini mov afisaj, W call lccmd adata mov W, #1FH ;date mov afisaj, W call lcdta mov W, #05H ;date mov afisaj, W call lcdta mov W, #07H ;date mov afisaj, W call lcdta jmp adata lcdta setb dorc clrb enab ;activare chip si start date call varsa setb enab retw $00 lccmd clrb dorc clrb enab ;activare chip si start date call varsa setb enab retw $00 lcres clrb rset ;resetare call pause setb rset ;dezactivare reset retw $00 varsa clrb sclk snb afisaj.$7 ;bit0(MSB) setb sdta sb afisaj.$7 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$6 ;bit1 setb sdta sb afisaj.$6 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$5 ;bit2 setb sdta sb afisaj.$5 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$4 ;bit3 setb sdta sb afisaj.$4 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$3 ;bit4 setb sdta sb afisaj.$3 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$2 ;bit5 setb sdta sb afisaj.$2 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$1 ;bit6 setb sdta sb afisaj.$1 clrb sdta call halta setb sclk call halta clrb sclk snb afisaj.$0 ;bit7(LSB) setb sdta sb afisaj.$0 clrb sdta call halta setb sclk call halta clrb sclk retw $00 cbild clrb sdta mov W, #6 mov count3, W c3 mov W, #84 mov count1, W c1 mov W, #8 mov count2, W setb dorc clrb enab c2 clrb sclk nop nop setb sclk decsz count2 jmp c2 setb enab decsz count1 jmp c1 decsz count3 jmp c3 retw $00 pause mov W, #7 mov count3, W d3 mov W, #50 mov count1, W d1 mov W, #250 mov count2, W d2 decsz count2 jmp d2 decsz count1 jmp d1 decsz count3 jmp d3 retw $00 halta mov W, #20H mov count1, W g1 mov W, #40H mov count2, W g2 decsz count2 jmp g2 decsz count1 jmp g1 retw $00 ;------------------------------------------------------------ end ;============================================================
By the way did you know how Nokia got that name? Its the sound made by the siamese twin elephants (joined at the trunk) whenever they tried to trumpet.
Can you find a faster way to convert a bit number into a mask for that bit? Hint: it can be done faster with tables. I like this routine because it doesn't need a table and so avoids pageing issues.
;build mask from fsr.1-3 (8 words, 8 cycles) mov w,#1 ;mask = (fsr && 2) ? 4 : 1 sb fsr.1 mov w,#4 mov mask,w sb fsr.2 ;if (fsr && 4) mask = mask << 4 swap mask sb fsr.0 ;if (fsr && 1) mask = mask << 1 rl mask
Why is each higher baud rate twice as fast until 14.4K which is only 1.5 times faster than 9600?
115,200 57,600 28,800 14,400 ? 9,600 4,800 2,400 1,200 600 300
Please do comment on any errors, improvments, confusions or ideas that are found in this letter.
--- James Newton, Host of SXList.com firstname.lastname@example.org 1-619-652-0593 fax:1-208-279-8767 SX FAQ / Code / Tutorials / Documentation: http://www.sxlist.com Pick faster!
|file: /Techref/new/letter/news0201.htm, 15KB, , updated: 2008/1/22 09:35, local time: 2018/1/22 00:08,
|©2018 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?|
<A HREF="http://www.piclist.com/techref/new/letter/news0201.htm"> Massmind news letter, January 2003</A>
|Did you find what you needed?|
PICList 2018 contributors:
o List host: MIT, Site host massmind.org, Top posters @20180122 David C Brown, Isaac M. Bavaresco, Manu Abraham, RussellMc, Van Horn, David, Dwayne Reid, Harold Hallikainen, James Cameron, Sean Breheny, John Gardner,
* Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.
Welcome to www.piclist.com!