Assembly Code Examples for the Beginner - Page 3 — Parallax Forums

# Assembly Code Examples for the Beginner

• Posts: 1,981
edited 2008-10-07 01:10
Untested, 18x4 ...

```      ' lhs == 18-bit value
' rhs == 4-bit value
' acc := lhs * rhs

mov acc,#0
shr rhs,#1   WC
shl lhs,#1
shr rhs,#1   WC
shl lhs,#1
shr rhs,#1   WC
shl lhs,#1
shr rhs,#1   WC

```
• Posts: 34
edited 2008-10-08 16:59
Ok now for some non proccesor calculation.

Is it true that when I want to play an audio 16[url=mailto:16bit@22.05khz]bit@22.05khz[/url]·signal, I only have (20000000/(16*22050))=56.56clock cycles thus I only may use about 14 instructions(most instructions cost 4 cycles)?

The thing that I want to make a synthesizer and·would love to use 16bit 44.1khz to playback my calculations.
But that would really limit me in assembly instructions.

Edit:
I seem to have made a mistake about the calc.
It would have been 20000000/22050=907cycles about 226cycles which would be enough I gess, and then shift the 16bits in the audio dac.
maybe even at 44.1khz...

But for now...
I want to use one cog for wave generation and then put it trought a filter algoritm.
I then have to see if I could sync the 2 cogs.
first cog will generate the first 16bit of the wave, the second will have to wait till the first cog calculated the waveform.
I thought of writing·a bit in the hub mem, "0" would be wait for waveform calc to finish which will be '1" if finished, second cog will make it '0' once it is read.
The first cog sees a '0' and know it has to calc·the next 16bit value of the wave form.

Is this a good approach or not?

Post Edited (darkxceed) : 10/8/2008 5:24:40 PM GMT
• Posts: 1,981
edited 2008-10-08 17:27
For t=1/f, 44.1kHz equates to just over 22675ns, so that's how many nanoseconds you have between each update of the output value. At 80MHz, cycle time is 12.5nS, instruction time 50nS, so 22675/50 = 453 instructions between updates.

PS : It's much better if you start a new topic for questions not related to an existing thread.
• Posts: 34
edited 2008-10-08 17:50
OK you are right about topic.

But isn't it true that a cog operates at 20Mhz and not 80Mhz?

your calculations is almost the same as me btw 80000000/44100/4=453, so it take one cycle of the 20Mhz clock to execute 1 instruction.

Post Edited (darkxceed) : 10/8/2008 5:57:52 PM GMT
• Posts: 3,019
edited 2008-10-08 18:03
darkxceed, the cog operates at 20mips with 80Mhz ( 5Mhz clock * 16PLL ) which is 80Million / 4 clocks per instruction ( with some exceptions hub-ops etc.) = 20Mips [noparse]:)[/noparse]

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

·
• Posts: 34
edited 2008-10-08 18:23
I·feel like a fool, you are right, 20mips and not Mhz.

Well this adds up all well!

thanx
• Posts: 23
edited 2008-10-10 20:42
How do you access the pins in assembly.· I want to continuosly read in pin p2, until it's low. Then I want to read pins 16 to 23.
• Posts: 23,101
edited 2008-10-10 21:32
INA is a register / memory location just like any other. You need to use INA as a source field. Typically, you'd have a bit mask in some location which corresponds to the pin(s) you want, then use a test instruction to set one of the conditional flags (zero or carry) or you'd copy INA to a location and shift and mask the bits you want there. For example:
```
test   bit2mask,INA   wc   ' At this point, the carry flag is set to the state of pin 2

bit2mask   long   |< 2

mov  temp,INA
shr    temp,#16               ' Shift bit 16 to the position of bit 0
and   temp,#\$FF              ' Mask off least significant 8 bits

temp         long  0
```
• Posts: 3,019
edited 2008-10-10 21:32
yllawwally, making sure you haven't got the bits set in DIRA as output, ie leave them 0's
.
.
.
waitpne PIN2,PIN2 'waits for INA anded with PIN2 to not equal PIN2 ( assuming only one bit is set in PIN2 otherwise a low on any of the input pins in PIN2 would pass this check )
mov datain,INA ' get the data from the port.
shr datain,#16 ' I'm assuming you want the byte, so shift the bits right 16 times
and datain,#255
.
.
.
PIN2 long 1<<2

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

·
• Posts: 28
edited 2008-11-09 17:53
Hello , i would like to ask if someone changed the code in the library Synth.Spin (which is in Spin language) , to propeller assembly language .
Is it possible or it's very complicated ?
Thank you in advance
• Posts: 48
edited 2013-01-20 14:24
I was looking through:
Assembly Code Examples for the Beginner: SPI Engine Demo
and I have a really simple question.
```DAT           org'
' SPI Engine - main loop
'
loop          rdlong  t1,par          wz                'wait for command
if_z  jmp     #loop
movd    :arg,#arg0                        'get 5 arguments ; arg0 to arg4
mov     t2,t1                             '    &#9474;
mov     t3,#5                             '&#61626;&#9472;&#9472;&#9472;&#9496;
:arg          rdlong  arg0,t2
djnz    t3,#:arg
mov     address,t1                        'preserve address location for passing
'variables back to Spin language.
wrlong  zero,par                          'zero command to signify command received
ror     t1,#16+2                          'lookup command address
movs    :table,t1
rol     t1,#2
shl     t1,#3
:table        mov     t2,0
shr     t2,t1
and     t2,#\$FF
jumps         byte    0                                 '0
byte    SHIFTOUT_                         '1
byte    SHIFTIN_                          '2
byte    NotUsed_                          '3
NotUsed_      jmp     #loop
```

what is the "movd" command doing?
I read the command explanation out of the manual, and I understand movd copies the value in the source location to the destination field (bits [17..9]) of the destination location; but I don't understand what it's doing here. Can you fill the destination field of PASM instructions with a movd operation? and if that is what it's being used for here, why wouldn't you just use arg0, why would you use movd and #arg0?

Also, I understand when you use the # symbol in front of a value, you are indicating that rather than a memory location, you are using a 9 bit literal. But what does it mean when there is a # symbol in front of a memory address?

I've spent a good while trying to figure this out myself, and I don't think I'm going to.
So I really would appreciate an explanation. Thanks.
• Posts: 3,623
edited 2013-01-20 20:12
Copper wrote: »
```DAT           org'
' SPI Engine - main loop
'
[COLOR="#FFA500"]loop[/COLOR]          rdlong  t1,par          wz                'wait for command
if_z  jmp     #loop
[COLOR="blue"]movd    :arg,#arg0[/COLOR]                        'get 5 arguments ; arg0 to arg4
mov     t2,t1                             '    &#9474;
mov     t3,#5                             '&#61626;&#9472;&#9472;&#9472;&#9496;
:arg          rdlong  arg0,t2
djnz    t3,#:arg
mov     address,t1                        'preserve address location for passing
```
I read the command explanation out of the manual, and I understand movd copies the value in the source location to the destination field (bits [17..9]) of the destination location; but I don't understand what it's doing here. Can you fill the destination field of PASM instructions with a movd operation? and if that is what it's being used for here, why wouldn't you just use arg0, why would you use movd and #arg0?
In the example above the insn at :arg is modified from two different places and the whole parameter fetch sequence happens to be repeated (new/next command). Hope that's enough to get you down the right path here ...
Copper wrote: »
Also, I understand when you use the # symbol in front of a value, you are indicating that rather than a memory location, you are using a 9 bit literal. But what does it mean when there is a # symbol in front of a memory address?
What are the values ending up in a and b? Then think about what the effect would be on an insn when used with movd in the context of parameter setup.
```DAT             org     0

entry           mov     a, location             ' \$000, a = ?
mov     b, #location            ' \$001, b = ?

waitpeq \$, #0                   ' \$002

location        long    42                      ' \$003
a               res     1                       ' \$004
b               res     1                       ' \$005
```
• Posts: 48
edited 2013-01-21 15:26

I had a discussion with a friend that I think cleared some of this up for me.
The short answers to my short questions:

Q: Can you modify a later instruction using the "movd" command?
A: Yes. It makes sense, but the only applications for the "movd" command described in the manual are both configuring special registers (either the video or counter modules), and I was having a hard time testing the theory.

Q: What does it mean when you put a literal symbol in front of a label rather than a value?
A: If you put a # symbol in front of a a label for either an initialized or un-initialized variable, you are telling the propeller to use the memory location that label refers to, as a value; rather than the value contained there-in. In other words, if you have a label "Number" at memory location 4, and the value in "Number" is 18, then "#Number" equals 4, rather than 18.

If any of that is wrong please show no mercy.

So to test my understanding I wrote a small block of assembly code, but am not getting the results I expected.
```CON

_clkmode=     xtal1+pll16x
_xinfreq=     5_000_000

PUB main

cognew(@start, 4)

DAT

ORG 0
start         mov       n1,     #0              wz 'set Z to 1
:read         rdlong    n1,     par                'read par into n1

n1Lights      muxz     dira,   n1                  'set bits in dira corresponding with the high bits in n1 to Z
muxz     outa,   n1                  'set bits in outa corresponding with the high bits in n1 to Z

Ldelay        mov       time, cnt                   'time:=cnt
add       time, Ldelay                'add delay into time
waitcnt   time, #0                    'wait for count to equal time

_Ldelay  long  500_000

n1      res 1

time    res 1
```

I was hoping to see P3 light up (using P0-P31 as a binary display for the value in n1).

I'm using the Gear: Parallax Propeller Emulator (which can be found here) and it's built in dir display,
and this is what I'm getting:
(shows both dira and dirb with dira on top)
which I'm pretty sure reads P0, P1, P2, P3, P5, P6, P9, P10, P11, P13, P20 as high, and everything else as low.

So what am I missing here?
Thanks for your help.
• Posts: 3,623
edited 2013-01-21 16:13
Copper wrote: »
I was hoping to see P3 light up (using P0-P31 as a binary display for the value in n1).
At least dira looks correct (\$00102E6F). Why is that? You set par to 4. In the PASM section you do a rdlong from said address (loading a long from hub RAM address #4) which gives you - among other things - the clkmode (\$6F) and the binary checksum (\$2E). Where did you think you'd get the mask from which would light up P3 (%1000)?

Edit: Just realised that you mentioned dira/dirb rather than dira/outa (still too early here).

For non-special-register movd usage check [post=1108886]this example[/post].
• Posts: 48
edited 2013-01-23 14:13
I'm still confused about literals.

In the propeller manual, it clearly says you can use nine bit literal values in place of a memory location.

Here's an example from the manual:
```add  X, #25           'Add 25 to X
add  X, Y             'Add Y to X
X  long  50
Y  long  10
```
and the description:
"the result of the first ADD instruction is 75 (i.e.: X + 25 → 50 + 25 = 75) and that value, 75, is stored back in the X register. Similarly, the result of the second ADD instruction is 85
(i.e.: X + Y → 75 + 10 = 85) and so X is set to 85. "

So to answer Kuroneko, I thought I was adding 4+4=8, ie 000000_00000000_00000000_00001000

Really I'm just trying to understand what's going on in this block of code (from Beau Schwabe's SPI engine)
```loop          rdlong  t1,par          wz                'wait for command        if_z  jmp     #loop
movd    :arg,#arg0                        'get 5 arguments ; arg0 to arg4
mov     t2,t1                             '    &#9474;
mov     t3,#5                             '&#61626;&#9472;&#9472;&#9472;&#9496;
:arg          rdlong  arg0,t2
djnz    t3,#:arg
```
• Posts: 3,623
edited 2013-01-23 16:25
Copper wrote: »
So to answer Kuroneko, I thought I was adding 4+4=8, ie 000000_00000000_00000000_00001000
I assume you mean this bit of code:
```start         mov       n1,     #0              wz 'set Z to 1
:read         [COLOR="#FFA500"]rdlong[/COLOR]    n1,     par                'read par into n1
```
What happens is that - after setting the Z flag - you read from hub RAM location #4 (par == 4) which gives you \$00102E6F in n1 (basically the wrong insn here). After that you increase the content of :read by 4 (not n1 or par). Location :read contains an insn (rdlong n1, par) which is encoded as \$08BC13F0. Adding 4 to it results in \$08BC13F4 (rdlong n1, outa). One way of arriving at 8 would have been:
```start         mov       n1,     #0              wz 'set Z to 1
:read         mov       n1,     par                'move par into n1
add       n1,     #4                 'add the literal decimal value 4 into n1
```

Copper wrote: »
Really I'm just trying to understand what's going on in this block of code (from Beau Schwabe's SPI engine)
The objective here is to read 5 parameters from hub RAM. Unrolled it would look like this:
```rdlong  arg0, t2
rdlong  arg1, t2
rdlong  arg2, t2
rdlong  arg3, t2
rdlong  arg4, t2
```
Doing it like this is OK for a small number of parameters (or [thread=135075]if you want it fast[/thread]). To keep the code size down it's sometimes done in a loop.
```{1}     loop          rdlong  t1,par wz         'wait for command
{2}             if_z  jmp     #loop

{3}                   movd    :arg,#arg0        'get 5 arguments ; arg0 to arg4
{4}                   mov     t2,t1             '    &#9474;
{5}                   mov     t3,#5             '&#61626;&#9472;&#9472;&#9472;&#9496;

{6}     :arg          rdlong  arg0,t2
{9}                   djnz    t3,#:arg
```
1. read the command (par is the hub address of the command)
2. if said command is zero try again (until non-zero)
3. reset parameter fetch insn to rdlong arg0, t2
4. take copy of command (hub address in lower bits)
5. initialise loop counter (5 arguments)
6. read first argument into arg0
7. modify parameter fetch insn to point to next cog address (arg1)
9. read next argument (insn at :arg has now been modified/updated)
A note re: point 7, what happens here is that the destination field (insn[17..9]) is incremented by one, IOW starting with rdlong arg0, t2 you'll effectively end up with rdlong arg0+1, t2 which is the same as rdlong arg1, t2 in our case. After 5 loop cycles said insn has been incremented by 5*d0. Because of this we need point 3 which resets the insn's destination field to point to arg0 when the next command is handled.
• Posts: 48
edited 2013-01-24 13:35
Thank you very much for your excellent response. I'm going to have to study it as soon as I get some time.
Glancing through it, I basically didn't understand how to do a single thing correctly there. PASM is weird.
I need to re-examine how "values" are passed to PASM sub-routines.
At any rate, again thanks for the response. I've got some work to do.
• Posts: 38
edited 2013-02-09 08:07
I thought I'd add to this thread rather than start a new one...

I'm still grappling with some fundamental concepts of ASM. I'm trying to imagine the framework of an ASM routine that shares data with a Spin routine. Here's what I don't get:

I have two bytes and 12 words in hub memory that need to be manipulated by a cog running ASM. How do I get the addresses of said bytes and words into the ASM routine with just one long parameter variable? Or tell Spin where they are if they have to be defined and put in the hub with ASM?

Help me, Obi Wans...
• Posts: 8,805
edited 2013-02-09 08:41
You can only pass one address via par so what most of us do is pass the starting address of a block of longs; within this block you can store the addresses (use @ to populate) of your byte and word arrays.

Note: It is not a good idea to count on placement of variables in a list when you want multiple addresses -- better to manually stuff and pass the addresses as part of a parameters list.

Here's a partial listing:
```var

long  cog

long  param1
long  param2

word  warray[12]
byte  barray[2]

pub start

stop

param1 := @warray                                             ' get hub address of arrays
param2 := @barray

cog := cognew(@entry, @param1) + 1

return cog

pub stop

if (cog)
cogstop(cog - 1)
cog := 0

dat

org     0

entry                   mov     t1, par                         ' get address of params
rdlong  wpntr, t1                       ' get hub addr of w's
add     t1, #4                          ' next long
rdlong  bpntr, t1                       ' get hub addr of b's
```

This sets the cog variables wpntr and bpntr to the addresses of the respective arrays. You can use these values (updated with an index) with wrxxxx and rdxxxx to access the arrays.

Here's how you might create cog subroutines to read/write those arrays:
```readw                   mov     t1, wpntr                       ' point to w array
shl     idx, #1                         ' x2 for words
rdlong  wval, t1                        ' read warray[idx] into wval

writew                  mov     t1, wpntr                       ' point to w array
shl     idx, #1                         ' x2 for words
wrlong  wval, t1                        ' write wval to warray[idx]
writew_ret              ret

readb                   mov     t1, bpntr                       ' point to b array
rdlong  bval, t1                        ' read barray[idx] into bval

writeb                  mov     t1, bpntr                       ' point to b array
wrlong  bval, t1                        ' write bval to barray[idx]
writeb_ret              ret
```

Remember that the cog sees the hub as a giant array of bytes. What this means, then, is that when you're reading/writing a word, you must multiply the index value by 2 (2 bytes per long word). This is added into the base address of the array which gives you the correct hub address for the word you want to access.
• Posts: 38
edited 2013-02-09 09:12
Aha! Thanks!
• Posts: 48
edited 2013-02-09 13:38
So I'm trying to write a PASM Prime Number Generator to generate the 1000th prime number.

First I wrote one in SPIN, (01_SPIN_PrimeNumberGenerator.spin)
It takes 4 minutes and 44 seconds to run.

Now I'm trying to replicate the process in PASM.
This is what I have so far:
```{PASM 1000th prime number generator   ***Time to execute:???}CON

_clkmode=     xtal1+pll16x
_xinfreq=     5_000_000

OBJ

pst: "Parallax Serial Terminal"

VAR

long _Prime

PUB main

pst.Start(57600)
waitcnt(clkfreq*2+cnt)

cognew(@start, @_Prime)

repeat while _Prime==0
pst.str(string(16, "Calculating..."))

pst.str(string(13, "1000th Prime Number == "))
pst.dec(_Prime)

DAT
org 0
start         add   candidate, #2                             'generate "next" candidate (all odd numbers)
mov   divisor,  candidate                       'copy candidate to divisor
dd            sub   divisor,  #2                              'generate "next" divisor (all odd numbers < candidate)
sub   divisor,  #1      nr, wz                  'check if divisor has reached one
if_z  jmp   #prime                                    'if divisor==1 (Z==1) then jump to #prime
divide        mov   checked,  check   wz                      'check if (candidate//divisor)==0
if_z  jmp   #start                                    'if check==0 (Z==1) then move on to next candidate
jmp   #dd                                       'if check<>0 (Z==0) then move on to next divisor
prime         add   prime_cnt, #1                             'count candidate as prime
sub   prime_cnt, grand nr, wz                   'check if prime_cnt==1000
if_z  jmp   #end                                      'if prime_cnt==1000 (Z==1) then jump to #end
jmp   #start                                    'if prime_cnt<>1000 (Z==0) then move on to next candidate
end           wrlong candidate, PAR                           'write candidate (1000th prime number) to address at PAR (_Prime)

'************************************************************

candidate      long      7
prime_cnt     long      4
check         long      (candidate//divisor)
grand         long      1000

divisor       res       1
quotient      res       1
checked       res       1
```

Unfortunately, instead of the expected 7919, It returns 1999.

My first suspicion is that I don't quite understand how to use the flags properly.

Also, I'm not certain I can have a variable ("check") equal an operation between
two other variables (candidate//divisor) without doing more than just putting candidate//divisor in the value field.

As always I would appreciate any advice.
Thanks.
• Posts: 1,981
edited 2013-02-09 14:00
JonnyMac wrote: »
Remember that the cog sees the hub as a giant array of bytes. What this means, then, is that when you're reading/writing a word, you must multiply the index value by 2 (2 bytes per long).

Little slip there - 2 bytes per word is what was meant! And for longs the factor is 4 (or a shift-left of 2 bits).
• Posts: 1,981
edited 2013-02-09 14:03
Copper wrote: »
So I'm trying to write a PASM Prime Number Generator to generate the 1000th prime number.

First I wrote one in SPIN, (01_SPIN_PrimeNumberGenerator.spin)
It takes 4 minutes and 44 seconds to run.

Now I'm trying to replicate the process in PASM.

Unfortunately, instead of the expected 7919, It returns 1999.

My first suspicion is that I don't quite understand how to use the flags properly.

You haven't implemented the divisibility test so every odd number is believed to succeed, so you stop on the 1000'th odd number.
• Posts: 48
edited 2013-02-10 10:33
I guess I'm confused as to how to do that.
In my code I have one variable named check initialized to (candidate//divisor)
and at instruction "divide" I copy the value from check into checked and "wz"
where Z==1 would mean I had evenly divided divisor into candidate, thus candidate is not prime.
• Posts: 3,623
edited 2013-02-10 15:32
Copper wrote: »
In my code I have one variable named check initialized to (candidate//divisor)
This is a compile time value which is calculated as the remainder from dividing the cog address of candidate (\$00D) by the cog address of divisor (\$011). IOW it will stay \$00D for the duration of your run and you will always get a result of 7+(1000-4)*2 = 1999.

Division & Co have to be done the hard way in PASM if you want runtime results. Check appendix B of the manual. You should also terminate your program properly after the wrlong (with an endless loop/wait or cogstop). Otherwise the cog continues to execute what's there.
• Posts: 48
edited 2013-02-10 17:47
Bummer. I thought the value was determined when the value was read (not that I can think of how that would happen).
Thanks for the help.

Update:

Integrated the division code from appendix b of the manual (thanks Kuroneko) and it works.
16.5ish seconds to execute; and that's with a 2 second handshake period for the serial terminal. So 14.5ish seconds to generate the prime number.

Update2:

So now I'm trying to pass the starting address of an array of longs like JonnyMac described earlier in the thread.
I think I understand the general goal: to set a variable equal to the starting address of an array of "longs" and then in assembly, read each long into it's own variable by starting with the address in PAR then adding an Index value to that address such that you arrive at the next long (which I think is idx:=4). I have had a hell of a time wrapping my head around the idea of memory addresses, but I feel like I'm close.
```{PASM 1000th prime number generator   ***Time to execute:???}CON

_clkmode=     xtal1+pll16x
_xinfreq=     5_000_000

OBJ

pst: "Parallax Serial Terminal"

VAR

long array_start
long _PASM_PARS[2]

PUB main

pst.Start(57600)
waitcnt(clkfreq*2+cnt)

array_start:=@_PASM_PARS
_PASM_PARS[1]:=(cognew(@Pre, @array_start)+1)
pst.str(string(16, "Calculating..."))

repeat while _PASM_PARS[0]==0
waitcnt(clkfreq/100+cnt)

pst.str(string(13, "1000th Prime Number == "))
pst.dec(_PASM_PARS[0])

DAT
org 0
Pre             mov     Larray,PAR                                'get address of array_start
mov     idx,#1                                    'set index to 1
shl     idx,#2                                    'set index to 4
add     array_addr,idx                            'add index to array start to get address of next location in array
'*************************************************************************************************************************************
start           add     candidate,#2                              'generate "next" candidate (all odd numbers)
mov     divisor,candidate                         'copy candidate to divisor
dd              sub     divisor,#2                                'generate "next" divisor (all odd numbers < candidate)
sub     divisor,#1                nr,wz           'check if divisor has reached one
if_z    jmp     #prime                                    'if divisor==1 (Z==1) then jump to #prime
check           jmp     #divide                                   'jmp to #divide
checked         mov     dend,rem                  nr,wz           'flag z if rem==0
if_z    jmp     #start                                    'if check==0 (Z==1) then move on to next candidate
jmp     #dd                                       'if check<>0 (Z==0) then move on to next divisor
prime           add     prime_cnt,#1                              'count candidate as prime
sub     prime_cnt,grand           nr, wz          'check if prime_cnt==1000
if_z    jmp     #end                                      'if prime_cnt==1000 (Z==1) then jump to #end
jmp     #start                                    'if prime_cnt<>1000 (Z==0) then move on to next candidate
end             wrlong  candidate,Larray                          'write candidate (1000th prime number) to address at PAR (_Prime)
'cogstop cog_id                                   'stop cog(cog_id)
'*************************************************************************************************************************************

divide          mov     dor, divisor                              'copy divisor into dor
mov     dend, candidate                           'copy den into candidate
shl     dor,#15                                   'get dor into dor[30..15]

cmpsub  dend,dor       wc                         'dend =< dor? Subtract it, quotient bit in c
rcl     dend,#1                                   'rotate c into quotient, shift dividend
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   'repeat x16
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
cmpsub  dend,dor       wc                         '
rcl     dend,#1                                   '
'quotient in dend[15..0], remainder in dend[31..16]
mov     rem,dend                                  'copy dend to rem
shr     rem,#15                                   'shift out quotient

'*************************************************************************************************************************************

candidate     long      7
prime_cnt     long      4
grand         long      1000

divisor       res       1
dor           res       1
dend          res       1
rem           res       1
Larray        res       1
idx           res       1
cog_id        res       1
```
Other than adding the Pre routine, all I changed was the wrlong from "wrlong candidate,PAR" to "wrlong candidate,Larray" where "Larray" theoretically == @_PASM_PARS[0]
The other variable in the array is the cog_id of the PASM cog so I can use a cogstop command at end; rather than an endless loop. But I'm not using it right now.
My point being I'm probably missing something in the Pre routine.

Thanks for your help.
• Posts: 6
edited 2013-10-05 08:17
in reference to Beau's post #8, why are the mux commands preferred and not the less obscure "or" command?

for example: