I noticed this very smart coding trick Chip used in checking for a hex character (0..9, A..F, a..f).
Code and table must be in cog.
I also found a shorter way to convert it to a binary nibble.
hexchrs long %00000000_00000000_00000000_00000000
long %00000011_11111111_00000000_00000000 '"0".."9"
long %00000000_00000000_00000000_01111110 '"A".."F"
long %00000000_00000000_00000000_01111110 '"a".."f"
long %00000000_00000000_00000000_00000000
long %00000000_00000000_00000000_00000000
long %00000000_00000000_00000000_00000000
long %00000000_00000000_00000000_00000000
.check altb x,#hexchrs 'check for hex
testb 0,x wc
if_nc ret 'if not hex, c=0
testbn x,#6 wz 'hex, "0".."9"?
if_nz add x,#9 '..make low nibble $A..$F
_ret_ and x,#$F 'extract low nibble, return c=1
The add x,#9 converts "A..F" to "J..O" and "a..f" to "j..o". "J" is ascii $4A and "j" is ascii $6A.
Then we strip off the upper nibble from both the "0..9" and "J..O"/"j..o" leaving $00..$0F"
While it's shorter code to first check for ASCII $80 and above, rather than using the 8 long table we could use a 4 long table. This would save 2 longs.
However, Chip is looking for the fastest code.
Custom pin config bits when issuing smartpin mode setting:
%PPPPPPPPPPPPP: low-level pin control (engineering sample die)
common labelling of pin config bits
%C = clocked I/O (extra clock for IN and OUT)
%I = invert IN output
%O = invert OUT input
%HHH/LLL = digital out drive strength
000: Fast
001: 1k5R
010: 15kR
011: 150kR
100: 1mA
101: 100uA
110: 10uA
111: Float
PinA is specified pin number
PinB is PinA's odd/even pair
%0_VVV_CIOHHHLLL = Digital mode (default = %0000000000000)
DIR enables PinA digital output
%VVV = Digital config
000: IN = PinA logic, PinA output from OUT
001: IN = PinA logic, PinA output from IN
010: IN = PinB logic, PinA output from IN
011: IN = PinA schmitt, PinA output from OUT
100: IN = PinA schmitt, PinA output from IN
101: IN = PinB schmitt, PinA output from IN
110: IN = PinA > PinB comparator, PinA output from OUT
111: IN = PinA > PinB comparator, PinA output from IN
%100_VVV_OHHHLLL = ADC_MODE, first order sigma-delta
IN has bitstream, sysclock bitrate, for smartpin mode %01111 (Y=0)
OUT is PinA digital output, clocked
DIR enables PinA digital output
%VVV = ADC config
000: GIO, 1x (~5 volt range, centred on VIO/2)
001: VIO, 1x "
010: PinB, 1x "
011: PinA, 1x "
100: PinA, 3.16x (~1.58 volt range, centred on VIO/2)
101: PinA, 10x (~0.5 volt range, centred on VIO/2)
110: PinA, 31.6x (~0.158 volt range, centred on VIO/2)
111: PinA, 100x (~0.05 volt range, centred on VIO/2)
%101_VV_DDDDDDDD = DAC_MODE (%TT = 00 and %MMMMM = 00000), 8-bit flash
OUT enables PinA ADC (config %011), sysclocked bitstream on IN
DIR enables PinA DAC output
%VV = PinA DAC config
00: 990 ohm, 3.3 volt range
01: 600 ohm, 2.0 volt range
10: 123.75 ohm, 3.3 volt range
11: 75 ohm, 2.0 volt range
%DDDDDDDD = DAC level
for %TT = %01 and %MMMMM = %00000, %101_VV_xxxxSSSS = COG_DAC mode
%SSSS = Cog/streamer select: sets DAC level (registered?)
for %00000 < %MMMMM < %00100 = SMART_DAC mode
DIR/IN are usual smartpin ctrl
%DDDDDDDD ignored, smartpin sets DAC level (registered?)
for %MMMMM >= %00100 or (%TT = %1x and %MMMMM = %00000) = BIT_DAC mode
OUT sets DAC level (clocked?, ADC disabled?, IN = ?)
0: 0 = GIO level
1: %DDDDDDDD
%11_VV_CDDDDDDDD = COMP_DAC comparator mode
DIR enables PinA digital output
%VV = Comparator config
00: IN = PinA > D, PinA driven by 1k5R from OUT
01: IN = PinA > D, PinA driven by 1k5R from !IN
10: IN = PinB > D, PinA driven by 1k5R from IN
11: IN = PinB > D, PinA driven by 1k5R from !IN
%DDDDDDDD = DAC level for internal analogue compare
Updated 20-11-2018 to correct smartpin mode number for capturing ADC bitstream.
25-11-2018: Reverse the update. Doh!
26-12-2018: Typo, R -> % in BIT_DAC mode line. And stated for engineering sample.
"There's no huge amount of massive material
hidden in the rings that we can't see,
the rings are almost pure ice."
A trap. Pnut has buggy code generation for PC-relative encoding of LOC instruction. Recommendation, for the moment anyway, is to always use #\ or #\@ .
NOTE: When specifying a numerical immediate in place of the label, it is treated as an absolute address and the same rules apply, ie: it will be encoded as PC-relative if possible, as per above. However, "@" produces an error with Pnut but not with p2asm. p2asm will perform a left shift by 2.
"There's no huge amount of massive material
hidden in the rings that we can't see,
the rings are almost pure ice."
Beware the instructions TESTB & TESTBN seems to me to give the wrong results for the Z flags on P2-ES silicon
mov lmm_x,#0
testb lmm_x,#0 wz ' nz <<<<<
testbn lmm_x,#0 wz ' z <<<<<
testb lmm_x,#0 wc ' nc
testbn lmm_x,#0 wc ' c
and lmm_x,#1 wz ' z
mov lmm_x,#1
testb lmm_x,#0 wz ' z <<<<<
testbn lmm_x,#0 wz ' nz <<<<<
testb lmm_x,#0 wc ' c
testbn lmm_x,#0 wc ' nc
and lmm_x,#1 wz ' nz
For anyone new reading, all register-level instructions affect the Z flag as you would expect, where it gets set if the result was zero.
For the bit-level instructions, on the other hand, C and Z are both read and written directly, without semantic consideration for what Z usually means.
There's a couple of undocumented traps with the REP instruction. One was known and easy to avoid, the other was unknown until recently and should be corrected in the next revision.
The known one is the last instruction within the REP block cannot be a branching instruction. If a branching instruction is used then the branch distance will have the block length subtracted from it. It won't be remedied, so just don't do it.
Any intentionally cancelling branches must be at least one instruction back from the end of the REP block.
The until recently unknown one is with the Jxxx branch-on-event instructions. Using any of these instructions anywhere within the REP block will intermittently fail to branch upon event. When the failure occurs, execution will continue out the end of the REP block and even fail to take the first following branch.
New tidbit discovered: WRPIN input %AAAABBBB config still apply to IN when smartpin is off. Which presumably means %FFF config also works with smartpin off.
"There's no huge amount of massive material
hidden in the rings that we can't see,
the rings are almost pure ice."
Code to convert a nibble to an ASCII character "0".."9" "A".."F" using just the C flag...
' convert nibble to ASCII hex char
getnib x,value,#7 '\ either instruction extracts only the lower nibble
and x,#$0F '/
or x,#"0"
cmp x,#";" wc ' : -> A etc
if_nc add x,#7
There's a hardware flaw with shared lutRAM. A simultaneous read and write will glitch the read data. The glitch patterns change slightly with each run but the alignment doesn't. Same for different sys clock rates.
This isn't strictly a P2 trap, but the presence of the stack based RET instruction and relative branches makes this
much harder to spot and can lead you (well me) running around in circles trying to track down very strange behaviours
that seem to defy logic:
cognew (@entry, ...)
DAT
ORG
rogue long 0
entry ' your code
Of course the ORG should be after the random long data, otherwise all the addressing is thrown, but
the effect is to omit the leading instructions in call'ed routines (jmps are relative and tend to work),
which can have subtle and bizarre consequences.
On the P1 all branches get affected and things tend to fall over completely rather than limp along misbehaving
It would be nice to get an assembler warning if the first entry after ORG 0 is not an instruction.
There are times where the first instruction is a long that has no effect when executed.
P2 will be a little different to P1 in that you can start the cog at other than address COG $0, and also because we don't really have a NOP opcode.
Comments
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
In P1...
LOCKSET D WC returns C=previous lock setting ie C=1=previously set
In P2
LOCKTRY D WC returns C=1=obtained lock Note the reversed result
This is opposite to P1, and also differs from
LOCKNEW D WC returns C=1=no lock available
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Here is the definitive example from Chip
https://forums.parallax.com/discussion/comment/1438380/#Comment_1438380
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Here is a solution to skipping instructions without using condition codes... Acknowledgement to PeterJ
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
I noticed this very smart coding trick Chip used in checking for a hex character (0..9, A..F, a..f).
Code and table must be in cog.
I also found a shorter way to convert it to a binary nibble. The add x,#9 converts "A..F" to "J..O" and "a..f" to "j..o". "J" is ascii $4A and "j" is ascii $6A.
Then we strip off the upper nibble from both the "0..9" and "J..O"/"j..o" leaving $00..$0F"
While it's shorter code to first check for ASCII $80 and above, rather than using the 8 long table we could use a 4 long table. This would save 2 longs.
However, Chip is looking for the fastest code.
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
The P1 ignores lowest hub address bit(s) for non-aligned hub reads and writes.
The P2 correctly accesses non-aligned word and long reads and writes.
In the P1, there were tricks associated with the lower hub address bit(s) being ignored. This code will fail on P2.
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
In P1 we did this...
In P2 we do this...
And here is the trap: Our P1 code incorrectly converted to P2 Note we need to include the addct1 instruction into the loop because waitctn no longer adds to the count
WAITX D/#
An alternative to just wait n+2 clocks is the WAITX instruction.
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
This should work. Just fill in the values and the values will be calculated for you... Oops. Fixed this _SETFREQ = 1<<24 +.. was 1<<25
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
25-11-2018: Reverse the update. Doh!
26-12-2018: Typo, R -> % in BIT_DAC mode line. And stated for engineering sample.
hidden in the rings that we can't see,
the rings are almost pure ice."
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
BMASK D,#11 'D = $FFF
BMASK D,#15 'D = $FFFF
BMASK D,#30 'D = $7FFF_FFFF
So here is another way of expressing this... adjusted per Chip's following suggestion
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
Here is a section of code to record 'sample_length' of P0-P31 or P32-P63 using the streamer into HUB RAM at 'samples'...
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
NOTE: When specifying a numerical immediate in place of the label, it is treated as an absolute address and the same rules apply, ie: it will be encoded as PC-relative if possible, as per above. However, "@" produces an error with Pnut but not with p2asm. p2asm will perform a left shift by 2.
hidden in the rings that we can't see,
the rings are almost pure ice."
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
For anyone new reading, all register-level instructions affect the Z flag as you would expect, where it gets set if the result was zero.
For the bit-level instructions, on the other hand, C and Z are both read and written directly, without semantic consideration for what Z usually means.
The known one is the last instruction within the REP block cannot be a branching instruction. If a branching instruction is used then the branch distance will have the block length subtracted from it. It won't be remedied, so just don't do it.
Any intentionally cancelling branches must be at least one instruction back from the end of the REP block.
The until recently unknown one is with the Jxxx branch-on-event instructions. Using any of these instructions anywhere within the REP block will intermittently fail to branch upon event. When the failure occurs, execution will continue out the end of the REP block and even fail to take the first following branch.
This one is expected to be fixed. Example code of accommodating, and alternative below - https://forums.parallax.com/discussion/comment/1458393/#Comment_1458393
Some extra detail - https://forums.parallax.com/discussion/comment/1461458/#Comment_1461458
and https://forums.parallax.com/discussion/169438/rep-blocks-and-branching-issue/p1
hidden in the rings that we can't see,
the rings are almost pure ice."
hidden in the rings that we can't see,
the rings are almost pure ice."
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)
v32i FPGA image on P123 board @ 20 MHz
RevA P2ES board @ 20 MHz
EDIT: Updated with extra tests. Thanks Brian.
hidden in the rings that we can't see,
the rings are almost pure ice."
You've managed to add a forth comment now!
hidden in the rings that we can't see,
the rings are almost pure ice."
Seem the forum software does not actually allow that, so I've done the next best thing..... ♪
much harder to spot and can lead you (well me) running around in circles trying to track down very strange behaviours
that seem to defy logic:
Of course the ORG should be after the random long data, otherwise all the addressing is thrown, but
the effect is to omit the leading instructions in call'ed routines (jmps are relative and tend to work),
which can have subtle and bizarre consequences.
On the P1 all branches get affected and things tend to fall over completely rather than limp along misbehaving
It would be nice to get an assembler warning if the first entry after ORG 0 is not an instruction.
P2 will be a little different to P1 in that you can start the cog at other than address COG $0, and also because we don't really have a NOP opcode.
Prop OS (also see Sphinx, PropDos, PropCmd, Spinix)
Website: www.clusos.com
Prop Tools (Index) , Emulators (Index) , ZiCog (Z80)