Kogna debug suggestions

Moderators: TomKerekes, dynomotion

SJHardy
Posts: 46
Joined: Thu Oct 03, 2019 12:36 am

Re: Kogna debug suggestions

Post by SJHardy » Wed Apr 03, 2024 5:29 pm

While I can't cite chapter and verse of the C standard, I'm pretty sure it should not be making any assumptions about what functions do. If the CL6X compiler is really assuming the value is unchanging through the loop, that's definitely a compiler bug. I seem to recall reading that the compiler must assume that a function can do anything, especially if the source is not visible to the compiler at that point e.g. inline. So it should *not* be requiring volatile declarations. But as you imply, it's wise not to depend on the compiler being perfect.
It isn't clear if you are testing with optimization turned off or not.
Currently, I've turned off all optimization and have -g. Also, with or without function entry+exit hooks it behaves the same.
When you said Thread #1 "failed" without the NOWAIT define what did you mean? Does it hang in Thread #1's Delay_sec()? Crash? Shut off interrupts?
Sorry about being unclear. I meant that the general "lock up with interrupts disabled" phenomenon occurs. As far as I have tested, my homing routine works perfectly with NOWAIT, and locks up after homing Z then X and in the process of Y. (I've temporarily set up sequential axis homing to simplify debugging, but whether sequential or parallel it behaves in the same manner).
It might be usefult to know what INIT_SUPE and supe->ref_axes() actually do. Could you post the assembly code for that simple Thread #1 code?
There is a static var for each thread called "supe" which points to the global block at the end of the gather buffer. INIT_SUPE is boilerplate at the start of each thread to set it up:

Code: Select all

#define SUPE_BLOCK_SIZE     0x8000
#define SUPERVISOR_ADDR     ((supervisor_t *)((char *)gather_buffer + MAX_GATHER_DATA*8 - SUPE_BLOCK_SIZE))
#define INIT_SUPE supe = SUPERVISOR_ADDR
ref_axes is set up as a function pointer pointing to the following:

Code: Select all

static int ref_axes_main(void)
{
    // Stub invoker for homing thread.  (Same as home.c, except no wait for completion)
    int f;
    if (f = TestAndSet((int *)&supe->thd_function, THD_FUNC_REF_AXES)) {
        printf("ref_axes: function %d already running.\n", f);
        return -1;
    }
    StartThread(2);
    return 0;
}
The TestAndSet is used since thread 2 is loaded once and stays in memory, is then launched for various tasks, where it looks at supe->thd_function to determine its next task. Here is the top-level code for thread 2:

Code: Select all

#include <DM6-SCL-common.c>

#ifndef CL6X
    #error "This code needs to be compiled with CL6X"
#endif

static char msg[256];   // General message box message area


// Include all function implementation in-line.
#include <DM6-SCL-ref-axes.c>

#include <DM6-SCL-settings.c>

#include <DM6-SCL-custom-thd2.c>


/*
    Main entry point for thread 2, which is reserved for mutually exclusive functions which need
    to run in parallel with the supervisor (i.e. are too awkward to break into a state machine
    which can be run in the supervisor itself).
    
    Currently, functions are:
    - axis reffing
    - M118 (machine settings)
    
    Soon we should have M6 and M119.
    
    Since parameters cannot be directly passed to a thread at startup, the PC program should not
    invoke thread 2 directly.  Rather, a startup stub should be run in thread 1 which sets the
    required parameters (in supe) then issues StartThread(2).
*/
void main(void)
{
    INIT_SUPE;
    
    switch (supe->thd_function) {
    case THD_FUNC_NONE:
        break;
    case THD_FUNC_REF_AXES:
        supe->thd_result = ref_axes_main();
        break;
    case THD_FUNC_SETTINGS: // M118
        supe->thd_result = settings_main();
        break;
    #include <DM6-SCL-thd2.c>   // Hook for custom actions
    default:
        printf("main_thd2: unknown function code %d\n", supe->thd_function);
        break;
    }
    supe->thd_function = THD_FUNC_NONE;
}
To get the asm code, I'll have to screenshot CCS on the other machine. Is there a better way e.g. get the compiler to output an asm listing? That would be better then I'd have a record in my build directory.

As I mentioned before, this is all a bit Byzantine, but is the result of a process of evolution, so like the recurrent laryngeal nerve, it could do with a bit of post-hoc rework :-)

User avatar
TomKerekes
Posts: 2676
Joined: Mon Dec 04, 2017 1:49 am

Re: Kogna debug suggestions

Post by TomKerekes » Thu Apr 04, 2024 1:47 am

Hi Steve,

One thing that occurred to me is is that Starting a Thread while it is already running may well cause a crash. StartThread sets up the Stack Pointer and some values in the stack for the Thread. If this was in the process of being setup and a context switch causing the Thread to execute things could go bad.

Also when a thread exits there may be a period of time before the Thread is actually terminated and will no longer be scheduled to execute. Basically one Time Slice period.

Do you have a mechanism of determining a Thread is not still executing before starting it?

ThreadActive should indicate which Threads are currently active to execute.

To get the asm code, I'll have to screenshot CCS on the other machine. Is there a better way e.g. get the compiler to output an asm listing? That would be better then I'd have a record in my build directory.
The -k Compiler option should keep the assembly listing after the assembly file is assembled.
Regards,

Tom Kerekes
Dynomotion, Inc.

Post Reply