Indirect Addressing Question

DCom

Member
Join Date
May 2016
Location
Conroe
Posts
20
Guys, I currently have an RSLogix 5000 program that uses indirect addressing for timing points for pressrolls. I am trying to understand how it functions. It is an XIC instruction with the address being, CON_BSR[seqCONPR1.FADN/32].[seqCONPR1.FADN MOD 32]. I have researched quite a bit, but have not found a straight forward answer on how that expression really works. Any help will be greatly appreciated. Thanks.
 
Bernie, the value for seqCONPR1.FADN is 23. So 23/32 will leave me with the decimal 0.71875, which should be rounded to [1]. After that, I am assuming the second curly brackets will divide (MOD) the decimal by 32 and round to give me the point? I think that's what I am understanding.
 
Bernie, I think I remember reading somewhere that in Logix5k, when math is done inside indirection this way, that the result is treated like integer math in C++, i.e. it is truncated to an integer value, rather than rounded. I can't for the life of me remember where I saw that though. I'll try and test later, because I am curious now.
If DCom's program has been working, then this must be the way it actually works.

Dcom, what Bernie is saying is that if you divide your seqCONPR1.FADN/32 in a DIV instruction and store in an integer, your answer would be 1. 23 MOD 32 = 23. So if evaluated that way, you would be looking at CON_BSR[1].[23] after indirection. That is what Bernie is concerned about. This type of Word/Point indirect addressing is often used to cycle through bits of alarm word arrays to find the active alarm(s). I've never seen it done quite that way. I've always broken out the math to make it more clear what is being done. Technicians hate you a little less when you do it that way! I take a pointer that is limited from 0 - ((2^Array_Length)-1). Advance that each time you want to check another alarm bit. Then:

Code:
Word_Ptr := TRN(Pointer/32)
Bit_Ptr := Pointer MOD 32
IF Alarm[Word_Ptr].[Bit_Ptr] THEN
   Active_Alarm_Value := Pointer
END_IF;

The above is more along the lines of how I've always done it and seen it done.

So in your case, the seqCONPR1.FADN is a pointer that is advancing through the CON_BSR array. The BSR in the tag name makes me wonder if it is a product-tracking array (Bit-Shift Right?) or perhaps is a recipe array of timing setpoints, like you mentioned. What happens after the XIC instruction? I'm guessing there is a MOV instruction that also uses indirect addressing.
 
You would want a value of 0-31 to end up pointing to the first word [0]. But it won't. Try it individually with those values.

Obviously 32-63 should point to word [1].

It's even worse. The Control/Compact Logix line uses "banker's rounding". This means that a fraction of exactly .50000 will round to the "nearest even". Try dividing by 32 with 16 then 48 then 80 etc.

I don't have RSLogix5000 on my computers at home so I can't see if there is a proper solution. I'm pretty sure there is. Maybe others will help out.

Edit - thanks dcooper23 for the expansion on the problem.
 
Last edited:
Did a bit of testing and found some interesting results.

See below:
attachment.php


Notice that the DIV test_ptr 32 yields 0 when test_ptr = 31.
And the MOV instruction using the test_word_ptr in indirection works exactly as the one with the test_ptr/32 used in the indirection.
So it appers that Studio5000 now truncates all integer divide results???
I know that hasn't always been the case. This project is in version 28, on a 1756-L71s. I know that in v20 and earlier firmware, the logix PLC's used the "banker's round" method.

Studio5000v28_IntegerMath.jpg
 
Yes. It is a bit tracking array of where a certain product is on the Conveyor and energizes a roll to lower down. It does have a Move instruction that has the current speed of the CONPR1 and moves it to the current set timing point. It also jumps to another routine that moves other points. I was just curious which exact bit was making the XIC instruction true. I'm still searching through the program to decipher it.
 
No need to search through the program. The value that determines which bit is evaluated by the XIC instruction is the seqCONPR1.FADN value. If in your example, the FADN value is 23 then 23/32 =0 (round down) and 23 mod 32 is 23. So the XIC is CON_BSR[0].23
I would be curious what changes the value of the FADN pointer. My guess is it would be an encoder roll over, or proxy flag event, or something of the like.
 
I believe it only uses rounding when casting from a float to an int. I have certainly used the div mod trick for addressing across bit boundaries.

I remember trying all sorts of complicated stuff trying to avoid the rounding problem when a co-worker just did the obvious and had it work fine.

If you do want to use rounding then use a cpt and cast the calculation as a float by multiplying by 1.0 first.
 
Thanks everyone. You all were tremendous help. I just verified what you said, dcooper33, and tested to see if when I changed the value of CON_BSR [0].23 from 0 to 1 and the XIC was energized. Again, I thank you all for clarifying this. Thanks
 
The issue about rounding "differences" in Logix5000 will only come into effect if the math has been performed to float precision, rounding only ever occurs if a float value has to be stored in an integer destination. Integer math does not suffer from the (some people think strange) rounding method....

Let me explain....

If ALL of the operands of a math instruction (and that includes calculations within square brackets for indirection) are of an integer data-type, then the processor will use the fast integer math internal routines to determine the result, which will ALWAYS return a truncated result. Integer math has no concept of fractional results - hence 5/2 = 2, 10/6 = 1

If ANY ONE OR MORE of the operands, source or destination, of a math instruction (and that includes calculations within square brackets for indirection) are of REAL data-type, then all of the operands are internally converted to REAL, and the slower float math internal routines are used. The result will be a float value. Then the instruction that invoked the math will determine what to do with the float result, and if it needs to be converted back to an integer, to be stored in an integer type tag or to be used as an indirect address, then the processor will invoke its "banker's" or "round-to-even" algorithm. The following shows the effects of this rounding method

Code:
DIV, 7, 2 = 3.5  ; destination is a REAL
DIV, 7, 2 = 3    ; destination is an xINT
DIV, 7.0, 2 = 4  ; destination is an xINT

DIV, 9, 2 = 4.5  ; destination is a REAL
DIV, 9, 2 = 4    ; destination is an xINT
DIV, 9.0, 2 = 4  ; destination is an xINT
 
The issue about rounding "differences" in Logix5000 will only come into effect if the math has been performed to float precision, rounding only ever occurs if a float value has to be stored in an integer destination. Integer math does not suffer from the (some people think strange) rounding method....

Let me explain....

If ALL of the operands of a math instruction (and that includes calculations within square brackets for indirection) are of an integer data-type, then the processor will use the fast integer math internal routines to determine the result, which will ALWAYS return a truncated result. Integer math has no concept of fractional results - hence 5/2 = 2, 10/6 = 1

If ANY ONE OR MORE of the operands, source or destination, of a math instruction (and that includes calculations within square brackets for indirection) are of REAL data-type, then all of the operands are internally converted to REAL, and the slower float math internal routines are used. The result will be a float value. Then the instruction that invoked the math will determine what to do with the float result, and if it needs to be converted back to an integer, to be stored in an integer type tag or to be used as an indirect address, then the processor will invoke its "banker's" or "round-to-even" algorithm. The following shows the effects of this rounding method

Code:
DIV, 7, 2 = 3.5  ; destination is a REAL
DIV, 7, 2 = 3    ; destination is an xINT
DIV, 7.0, 2 = 4  ; destination is an xINT

DIV, 9, 2 = 4.5  ; destination is a REAL
DIV, 9, 2 = 4    ; destination is an xINT
DIV, 9.0, 2 = 4  ; destination is an xINT

Thank you for the explanation, daba. Have Logix-class PLC's always handled integer division by truncating the result?
 
....Have Logix-class PLC's always handled integer division by truncating the result?

Yes, integer math has always truncated results in Logix-class PLC's.

It is important to realise that there are two "calculators" built into the processor....

one that deals with integers only, and it produces truncated results.

and another that is invoked only when any of the input or output operands are of a REAL data-type.

but rounding issues will only occur if one or more sources are REAL (meaning a fractional result will occur), AND the destination is an integer (SINT INT or DINT), that is when the processor invokes "rounding".
 
Last edited:

Similar Topics

when your pointer gets indexed, if your previous reference is true, and your current reference is true before getting indexed, will the...
Replies
13
Views
5,416
Good day all, I would like to know if it is possible to use a counter' accumulator value as an indirect address. So it would look something like...
Replies
8
Views
4,170
Hi, I have an indirect addressing question that I just can't understand. L #DB_Conn T #iDB OPN DB [ #iDB] L...
Replies
6
Views
3,547
Yes, I did search for information first. Yes I looked through the limited help files that came with my Step 7. No I do not have any other books...
Replies
77
Views
20,951
I've got a rung that uses the first pass bit to initiate a For argument. In the Routine named 'Alarm' I have something like this...
Replies
15
Views
9,883
Back
Top Bottom