Tool/software:
Consider a function like the following in debug
where a counter is incremented over a set of enums. The assembly code is more or less what you can expect, after the call the variable is incremented and tested.
(I took screenshots with CCS 20.0.2, but the issue is the same with CCS 12.8.1, in a different and more realistic project)
In fact, after the first run, I find
and that's fine (my enum started at 0, next is 1).
When the loop wraps up I get the surprise
1. variable in memory is 1
2. a MOV has loaded it in AL
3. however, AL is 0 - and this is confirmed running the code
If I continue running the loop it never evaluates to something different, and the called function sees its parameter always at zero.
Note that a few collateral things are making it happen, and it's been a bit hard to replicate it in a short example (I had to add some weird code).
The lines in the example marked with comments //** are the triggers: if you remove/change them, the results are different. As an example, moving line 148 after line 156, the problem disappears, and all runs as expected.
I didn't check it on a different site (PC, programmer, board, etc.). Then I'd like to know if someone can replicate it first, or if it's just something unusual happening to me.
The comment on line 151 is confusing. The scope of the static variable test_item is limited to the function main_core_tests. It cannot be accessed during the function STA_CoreTest.
I think you mean say the function STA_CoreTest never returns the value STA_TEST_PASS, but there are circumstances where it should. To comment on that, I need to know more about the function STA_CoreTest.
Thanks and regards,
-George
I tried to describe the issue quickly, but clearly, I failed to describe it at all.
The following is the same code above, in the compiler listing, which still retains all the name references that are lost in the disassembly view of the debugger:
This excerpt is around the loop in the function main_core_tests()
, around the call to STA_CoreTest()
- the latter isn't directly involved in the issue, it just receives a wrong parameter, as I describe below.
Note: The fact that test_item
is static isn't needed by the code, is just functional for bug exploitation (could be global, with the same effect). Much of the code is there for things to happen as described here.
a. The variable test_item is set to 0 before entering the loop (in the lines above this screenshot). The fetch at offset +0x1c loads 0 in AL, and so it is passed on to STA_CoreTest
as a parameter
b. Then it is incremented on each run at offset +0x23
c. At offset +0x26 the loop returns to label $C$L1. On the first run, the value of test_item in memory is correctly 1
d. When loading again AL at offset +0x1c I would expect it to be 1, but to my surprise, it still yields 0, and so it does for every repetition in the loop
I don't know whether there's a pipeline contention with instruction at offset +0x1b, which uses ACC.
The lines from +0x14 to +0x1b are produced from C source by macro DEBUG_MARK2_TOGGLE(): if I move/remove that line, the problem disappears.
Let me insist on this: I wouldn't believe this claim myself, if I didn't see it happening all the time, with the debugger running on two different projects.
Here's why I asked for someone else to test the code (the whole test project is attached to the original message).
If I understand correctly, you are saying that for these instructions near the end of the key loop ...
INC @||test_item$1|| MOV AL,@||test_item$1||
The increment of the memory location test_item$1 occurs as expected. But the value loaded into AL is always 0. Is that right?
Thanks and regards,
-George
Er.. that's almost right.
Behaves like the instruction MOV AL,@||test_item$1||
at the beginning of the loop is always skipped. The one at the end, offset +0x24 is interpreted correctly, but when the loop returns to the top, the same instruction at offset +0x1c keeps leaving 0 in AL.
As I wrote, sounds illogical until you see it running.
I slightly modified code, declaring test_item
as global, so that it can easily be shown in a memory window. The resulting compiled code is exactly the same.
I then recorded a short debug session from my screen, going from first run of the loop, increment and jump back to top. It's a 4 MiB video, you can download it from here
www.swisstransfer.com/.../2e360ce7-7581-4bdc-88d4-1c8235376bed
Thanks for making the video. Unfortunately, I cannot view it. Something about it sets off the avoid malware systems used by TI.
I will bring this thread to the attention of C2000 hardware experts. They are much likely to be helpful than me.
Thanks and regards,
-George
Hi Luca,
I am going to take over helping with this issue. Please allow me some time to go through it and try to replicate on my setup.
Best Regards,
Delaney
Thanks for helping.
In the while has been released C2000-CGT version 22.6.2.LTS, then I installed it.
Recompiling the whole project on CCS 20.0.2 targeting this latest compiler, I can confirm that on my side the behavior is still the same - as well, generated code around the problematic lines looks to be the same, anyway.
Hi Luca,
I apologize for the delay. Can you provide a screenshot of the code in the function definition for STA_CoreTest()? I think this would help me rule out any problems in the C code first, before diving into the assembly.
Best Regards,
Delaney
Hi Delaney,
you can find in attachment to the original message a ZIP of the whole project sources, "Universal Project.zip" - even including some source files that are pretty useless, but that I left to not alter too much the very repeatable behavior.
Hi Luca,
I ran your code and I'm not sure if I am understanding the issue fully. Let's try to look at this from a C perspective rather than diving into the assembly right away. Are you expecting the test_item variable to loop through all the enums then break out of the loop when it reaches STA_TEST_MAX? Can you explain what the expected program execution is vs. what you are seeing so I can understand which one I see on my setup?
Best Regards,
Delaney
Hi Delaney,
the code is as simple as it looks, and it mostly works as intended.
Note first that everything in this example is tailored for the execution issue to show up.
The loop iterates over the enumeration values, from STA_TEST_START
ending when reaching STA_TEST_MAX
.
That happens exactly as expected if you monitor the iterator test_item
in memory, with the loop ending successfully.
In the loop body the iterator is then passed as an argument to STA_CoreTest()
, and here is where the problem arises. When passed as an argument it is retrieved from memory.
The surprise, executing the code, is that whatever the value in test_item
, on every call to STA_CoreTest()
its argument has always a value of zero.
From the assembly code perspective, the data page pointer register DP
is loaded to access test_item
data page, and the variable value is loaded in the register AL
.
Still, everything looks fine here, up to a point: in between there's another instruction, using a precedent value in the accumulator (MOVL *+XAR4[6],ACC
), sure from code optimization. What I suspect is that the instruction in between creates a pipeline contention on ACC
and AL
access, with a failing load into AL
.
Register AL
is right the lower 16 bits of ACC
, and in that phase those bits are always zero.
Note that the instruction in between is produced by the macro DEBUG_MARK2_TOGGLE()
: its presence is the culprit.
The C code is legal, and the assembly code is legal (apparently), but the execution result is not what is expected.
As a side note, I tested it again with recently released CCS 20.1, which also brings a new firmware for my XDS110 debug probe.
The issue is still there, but it seems to be dependent also on the debugging environment: with some different breakpoints and/or execution steps it has new different and unexpected results - still around those few loop body lines.
The precedent behavior is more or less obtained with a breakpoint at the beginning of the loop, and stepping with "Assembly Step Over", but I also see AL tainted with DP lower 16 bits. Yikes!
[EDIT]
I tested it on a second (brand-new) board, just to be certain it isn't due to MCU, and still behaves the same. I start thinking that my issue is around XDS110 firmware.
How can I downgrade XDS110 firmware? Done with xdsdfu and a firmware from CCS 12.8.1 (version 3.0.0.32) - unfortunately, now I can no longer debug with CCS 20
[EDIT]
I resolved the issue with XDS110 firmware downgrading.
However, I don't mark it as resolved: the current and supported CCS 20 has XDS110 firmware(s) showing the issue, the only workaround is to use the now deprecated and unsupported CCS 12.8.1
What's completely wrong in my original assumption is that this is not a compiler issue, but an XDS110 firmware issue.
Hi Luca,
Delaney is currently out of office and will get back to you as soon as possible when she returns next week.
Best Regards,
Allison
Hi Luca,
I tested the code on CCS 12.8.1 so I suppose that's why I didn't see any issues. Can you try one thing on CCS 20 to confirm that it is an emulation issue:
If you see that the item variable passed into the function is 0 when stepping through the code but the COM port sends the actual value correctly, it is a JTAG/CCS related issue. If the SCI transmitted data is showing 0 as well, the issue is in the actual code on the device.
Also, as a note, when stepping through the code, make sure you have "Continuous Refresh" toggled on in the Register View to make sure the registers are constantly updating on the screen. This could be why you were seeing the value 0 written to the AL register.
Best Regards,
Delaney