First, this issue is late and is devoded to my father, James C. Newton, who passed away this month. He was the best of fathers and the worst of fathers (as we all are) and I will miss him dearly. If you have any good code you don't mind shareing, for goodness sake, send it to me so I can catch up and avoid thinking about it. <GRIN>
This months focus is on more flexible versions of the standard routines that we all need at one time or another. Checking a value against a min and max that may change rather than bounds that are hard coded. Setting a bit in a byte specified by an index register (aka bit array). Converting any number of bytes to any number of digits of packed BCD.
To start things off, here is a list of the different methods of doing a select (or table lookup) that shows which is best for a given range and type of input value. Note that the IREAD method is basically unlimited.
Here is a quick (and I hope thought provokeing ) list of possible ranges and types of input values and the method that will produce the most "efficient" (smallest and fastest) way of jumping to an address indexed by that value. i.e. "select case" or "switch" statement. Do you get the title now? <GRIN> This is a sort of a switch for the type of code to use for your select.
Which brings us to "what is an xor list"?
mov W, rcreg xor W, #'A' snz ; same as btfsc zero jmp conversionA xor W, #'A'^'B' ;undo the xor a, then xor b snz jmp conversionB xor W, #'B'^'C' ;undo the xor b, then xor c snz jmp conversionC This works because: (X xor A) xor (A xor B) is the same as: X xor (A xor A) xor B which is the same as X xor 0 xor B which is the same as X xor B.
If anyone is interested, I bet I could get this into a macro that you could call with any number of constant values and an index register.
select reg case "A" case "B" case "C" endselect
Harold Hallikainen (who, by the way, provides the FCC rules on the web at his site http://www.hallikainen.org/FCC/FccRules/, and makes a darn fine line of lighting controllers (DMX etc..) at http://www.dovesystems.com/) posted this nice little range check sample. It is good because it works with min and max in ram rather than hard coded... Can you write a macro to build the shortest possible range check with constant min and max?
WindowTest macro value, min, max ; call as WindowTest value ; and cleared if not (wtfail). ; The key to this is the mov w,fr-w instruction. ; Carry =1 if the result is greater than 0 (carry=1 is positive result). So, ; carry=1 if f=>w ; carry=0 if f<w or w>f local wtexit ; local labels in macro ; For min, we want value=>min, ; so we'll put value in f and min in w mov W, min ; Get minimum mov W, value-w ; w=value-min. Result positive (carry set) if value=>min jnc wtexit ; If no carry, we're below min. Exit with fail (carry clear) ; For max, we want max=>value, ; so we'll put max in f, value in w mov W, value ; Get current value in w mov W, max-w ; w = max-value. Result positive (carry set) ; if max=>value. Exit with carry set wtexit endm
The answer to last months code challange is, of course, at:
http://www.sxlist.com/techref/ubicom/lib/math/bit/mask_sx.htm
This is pretty hot code! Seems to work just fine, but I haven't tested it extensivly. It's slower than some other versions, but when it comes to getting digits up for a human to look at, who cares?
; by FredMaher Madrid 10 Nov 02, Rewritten for SX by James Newton Feb 03. ; Using an extension of the >4 add 3 algorithm device sx18 reset start: BCDdigits = 5 ;change as you like BINdigits = 3 ;change as you like org 16 bcd DS BCDdigits bin DS BINdigits IFNDEF count count DS 1 ENDIF IFNDEF temp temp DS 1 ENDIF ; org 0 Start: ;----------------------------------------------------------------- ;Hex(Binary) to BCD routine ;----------------------------------------------------------------- Main: mov temp, #BCDdigits mov w, #bcd mov fsr, w BCDclear: clr indf inc fsr djnz temp, BCDclear: Testvals: mov W, #0FFh mov bin, W mov W, #0FFh mov bin+1, W mov W, #0Fh mov bin+2, W call bin2bcd: Convend: ; remove when in main prg jmp Convend: ; remove when in main prg ;----------------------------------------------------------- ; End main Bin Bcd ;------------------------------------------------------------ bin2bcd: mov count, #BINdigits * 8 ; count max value Shifting: test count snb Z ret ; bin number is now converted 2 bcd dec count ;---------------------------- ; Now left shift all registers clrb C mov temp, #BINdigits mov fsr, #bin BINrlLoop: rl indf inc fsr djnz temp, BINrlLoop: mov temp, #BCDdigits mov fsr, #bcd BCDrlLoop: rl indf inc fsr djnz temp, BCDrlLoop: ; next step check those which are >4 and add 3 test count snb Z ; finish without testing >4 ret Nibtests: ;Test BCD, high and low nibbles. If greater than 4 ( or 40) add 3 (or 30) mov temp, #BCDdigits mov fsr, #bcd BCDadjLoop: mov W, #0Bh ;(16-5) add W, indf ;DC set if carry from bit 3 to 4 mov W, #03h ; >4 add3 snb DC add indf, W mov W, #0B0h ; is high nibble more than 5? add W, indf mov W, #30h ; add 3 to high nibble snb C add indf, W inc fsr djnz temp, BCDadjLoop: jmp Shifting:
I got the attached exe (in a zip to keep it from picking up a virus on the way) from a guy who didn't want to be identified, who says it was written by another guy who didn't want to be identified.... it passed norton on my machine and it seems to work great. Dont open it without anti-virus software... I won't take any responsibility. If anyone has the time to figure out how the exe works and write me some pseudo code, I'll try to make an online version.
There is something like this specifically designed to look for good values
to match baud rate (or other) standard frequencies at
http://www.sxlist.com/techref/scenix/isrcalc.asp
one of these days I'll expand on that so that it will also be able to generate
a program template from the values you select.
This amazing routine from Scott Dattalo can basically store a bit into any bit of any register. You give it a register value that counts off each bit in the register file (the top 5 bits of this index value tell us which register and the bottom 3 bits tell us which bit in that register) and a bit value to set that bit to. E.g. to clear the carry flag. Set the index (called "bit_position") to 0001 1000 (register 3 bit 0) and the "new_state" bit to 0. Bit arrays are useful for low resolution vision or pattern matching,
set_bit: ;Get a pointer to the byte containing the bit we want: mov W, >>bit_position ;bit_position holds the bit number to set or clear mov fsr, W rr fsr mov W, >>fsr and W, #BIT_ARRAY_MASK ;use this to exclude globals mov fsr, W mov W, #bit_array ;address of the start of the bit array add fsr, W ; find 1<<(bit_position&7) [note, this could be made 2-cycles ; shorter, can you see how?] mov W, #0101b snb bit_position.0 mov W, #1010b mov mask, W ;mask could be temp mov W, #0011b snb bit_position.1 mov W, #1100b and mask, W snb bit_position.2 swap mask ; now set or clear the bit mov W, mask or indf, W ; Assume we're setting. sb new_state ;new_state has the bit value to store xor W, indf ; assumption was wrong
One of the really cool features in the IP2K processor from Ubicom is the "serdes" or serializer deserializer. This bit of hardware recognized that most forms of IO consist of some combination of a set of standard operatons. I'm trying to find a way to do that in software for the SX chips. The advantage would be that one "general purpose" virtual peripheral could then be configured to handle just about every type of IO we ever need. And... it could be setup on the fly.
mode | .7 | .6 | .5 | .4 | .3 | .2 | .1 | .0 | Rate | Data | D:DataPresent, R:Rate C:Count | ||
async serial rx / tx | IO | 1 | 0 | 0 | 1 | P | S | D | SRRR | 1CCC | P:Parity(none, even) S:Speed (High: 115,200, 57,600, 28,800, 14,400 Low:9600, 4800, 2400, 1200) In low speed mode, the count is reloaded with 12 rather than R every other time. | ||
i2c data in / out | IO | 1 | 1 | 0 | M | D | PPPP | PPPP | 200 (230?) Hz ISR 115.2bps. The I2C spec says SCL min low is 4.7uS and
high is 4uS. That works out to 115Hz, but the spec also says SCL max is 100KHz.
P bits decide which pin is the I2C clock M:Mode (master, slave) |
||||
SPI in / out | IO | 1 | 1 | 0 | PPPP | PPPP | |||||||
Quadrature decoder / Stepper | IO | 0 | 1 | 1 | 1 | D | PPPP | PPPP | Position (up/dn count of encoder or step) | More than one pin on in the mask. Stepper can do any sort of pattern by recording the appropriate bit changes as a "wave" table in the FRAM buffer. | |||
a2d / d2a | IO | 0 | 0 | 1 | 1 | Single pin, sigma delta with Vin thru Rin to Cap then thru Rf to IO pin. | |||||||
pluse width measurement / PWM | IO | 0 | 0 | 1 | 1 | E | D | CCCC | CCCC | Duty cycle or measured pulse width | C:Count Input:Set to FF when pin E:Edge(set or cleared) and dec until pin changes then copied to Data. Output: C is copied from Data and pin set to E. Then C is dec to zero and pin set to not E. Finally C is then loaded with 255-Data and dec to zero again. | ||
freq count / generate | IO | 0 | 0 | 1 | 0 | R | D | CCCC | CCCC | ||||
bit pattern capture / generate (magic sine) | IO | 1 | 0 | 0 | 0 | D | 1RRR | 1CCC | |||||
wave capture / out | IO | 0 | 1 | 0 | D | PPPP | PPPP |
in_out equ .7 ;input or output serial equ .6 ;serial or parallel (do we shift in/out the data?) pinmask equ .5 ;serial sync or async (is there a clock pin?) ; Also decides if the Rate byte is a pin mask or a counter. width equ .4 ;is Rate counter 3 bits (reloaded from upper 3 bits) or 8 bits (loaded from/to data) ; if Rate is not zero, and data with Rate and then input or output. trigger equ .3 ;Do we wait for a trigger (e.g. stop bit, clock, encoder pulse, cap charge, or just keep running? ; ser_des_vp clr mask inc mask mov fsr, pincfg+0 :each_pin mov w, port and w, mask clc sz stc ;Pin state is in C :counter dec ind ;Reduce the counter jb ind.3, cnt_done ;Check for wrap inc ind ;Prep for next count xxxx0111 -> xxxx1000 ; So a preset can be or'd in. Also, .3 ; must remain set so that we know this is ; a timed pin. jb ind.serial ;If this is a serial pin :is_serial setb fsr.4 ;Point to data byte for this pin rl ind ;Store C in MSB and get C from LSB clrb fsr.4 ;back to pin config jmp cnt_done :not_serial :cnt_done jb ind.in_out ;if this is an output pin jc bit_set :bit_clear mov w, ~mask ;clear the pin if the data bit is zero and port, W jmp in_out :bit_set or port, W ;set the pin if the data bit is one. :in_out :pin_done :next_pin rl mask inc fsr
If you document everything you know and write expert systems (e.g. code generators, macros, languages, etc... ) that can duplicate most of what you are good at, will you live on forever?
Please do comment on any errors, improvments, confusions or ideas that are found in this letter.
Thanks!
--- James Newton, Host of SXList.com james@sxlist.com 1-619-652-0593 fax:1-208-279-8767 SX FAQ / Code / Tutorials / Documentation: http://www.sxlist.com Pick faster!
file: /Techref/new/letter/news0302.htm, 15KB, , updated: 2004/1/14 14:50, local time: 2024/11/25 23:02,
18.117.70.64:LOG IN
|
©2024 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://techref.massmind.org/Techref/new/letter/news0302.htm"> Massmind news letter, Feburary 2003</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to techref.massmind.org! |
.