XC8: .asm to C ( i.e. Lowering One's Expectations)

nsaspook

Joined Aug 27, 2009
13,262
Nothing better than "goto" to efficiently navigate the multi-laned, interleaved highway of life:

C:
        if (hold_timer) goto kkhold;
        if (rep_timer) goto kkrep;
        if (key_change.bytev)
        {
            hold_timer = HOLD_TIMER_INIT;
            goto kexitr;
        }
        else goto kexit;
   
    kkhold:
        if (!key_down.bytev) goto kkpr;
        if (--hold_timer) goto kexit;
        key_ph.bytev = key_down.bytev;
        goto kkrep1;
   
    kkrep:
        if (!key_down.bytev) goto kexitr;
        if (--rep_timer) goto kexit;
   
    kkrep1:
        key_rpt.bytev = key_down.bytev;
        rep_timer = REP_TIMER_INIT;
        goto kexit;

    kkpr:
        key_pr.bytev = key_last.bytev;
           
    kexitpr:
        hold_timer = 0;
   
    kexitr:
        rep_timer  = 0;
   
    kexit:
        key_rel.bytev = ~key_down.bytev & key_last.bytev;
        key_last.bytev = key_down.bytev;
Nothing wrong with GOTO if used properly.

but if you use GOTO, you might be attacked by a dinosaur.
1669674926935.png
 

nsaspook

Joined Aug 27, 2009
13,262

Thread Starter

joeyd999

Joined Jun 6, 2011
5,283
Here is the entirety of the C version of the .asm keypad driver I generally use.

It supports multiplexed keypads, is fully debounced, and encodes flags on each pass indicating keys that have been pressed, held, released, pressed-and-released within a short delay, pressed-and-held with a short delay, and press-and-repeat. Of course, entirely non-blocking.

@MMcLaren, you may recognize the vertical counters. Your cluing me into these years ago is the gift that keeps on giving. Thanks.

In this case, there are only three active push buttons. One is from a rotary encoder on RB1. The other two are multiplexed on RB3. It's a strange layout -- but there are underlying reasons for this in this application.

Constructive comments and criticisms welcome.

keypad.h:
/*
 * File:   keypad.h
 * Author: Joeyd999
 *
 * Created on November 17, 2022, 4:13 PM
 */

#ifndef KEYPAD_H
#define    KEYPAD_H

#ifdef    __cplusplus
extern "C" {
#endif
    
//                                      Port A
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Bit      |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Device   |CHARGER| SOUND |    KEYPAD     |ANALOG |BATTERY|    ANALOG     |
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Function |CHGSTAT| SPKR  | KROW1 | KROW0 | VBAT  |VBCTL  | VBIAS | VTEMP |
//         +-------+-------+-------+-------+-------+-------+-------+-------+

//                                      Port B
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Bit      |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Device   | ISCP  |T SENSE| ANASW |  LCD  |    ENCODER    |KEYPAD |ENCODER|
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Function |  PGD  |PGC/TCS| ASW2  | LCDBL | ENCSW | ENCA  | KCOL3 | ENCB  |
//         +-------+-------+-------+-------+-------+-------+-------+-------+

//Key Map
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Bit      |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
//         +-------+-------+-------+-------+-------+-------+-------+-------+
//Key      |       |       |       |       | ENCSW |       | KEY1  |  KEY0 |
//         +-------+-------+-------+-------+-------+-------+-------+-------+

    
    
#include <xc.h>
#include "custom_types.h"
#include "system_timer_definitions.h"

#define KEY_ROW0 TRISA4
#define KEY_ROW1 TRISA5
    
#define key0_down    key_down.bitv.b0
#define key1_down    key_down.bitv.b1
#define encsw_down   key_down.bitv.b3

#define key0_change  key_change.bitv.b0
#define key1_change  key_change.bitv.b1
#define encsw_change key_change.bitv.b3

#define key0_pr      key_pr.bitv.b0
#define key1_pr      key_pr.bitv.b1
#define encsw_pr     key_pr.bitv.b3
    
#define key0_ph      key_ph.bitv.b0
#define key1_ph      key_ph.bitv.b1
#define encsw_ph     key_ph.bitv.b3
    
#define key0_rpt     key_rpt.bitv.b0
#define key1_rpt     key_rpt.bitv.b1
#define encsw_rpt    key_rpt.bitv.b3
    
#define key0_rel     key_rel.bitv.b0
#define key1_rel     key_rel.bitv.b1
#define encsw_rel    key_rel.bitv.b3
    
#define HOLD_TIMER_INIT clctim(512,T8ms);   
#define REP_TIMER_INIT  clctim(128,T8ms);   
    
extern ct_bitmap8 key_down;   
extern ct_bitmap8 key_change;
extern ct_bitmap8 key_pr;
extern ct_bitmap8 key_ph;
extern ct_bitmap8 key_rpt;
extern ct_bitmap8 key_rel;


void key_poll(void);

#ifdef    __cplusplus
}
#endif

#endif    /* KEYPAD_H */
keypad.c:
/*
 * File:   keypad.c
 * Author: Joeyd999
 *
 * Created on November 17, 2022, 4:13 PM
 */

#include "keypad.h"
#include "system_timer_definitions.h"

uint_fast8_t key_last   = 0;
ct_bitmap8   key_down   = {0};
ct_bitmap8   key_change = {0};
ct_bitmap8   key_pr     = {0};
ct_bitmap8   key_ph     = {0};
ct_bitmap8   key_rpt    = {0};
ct_bitmap8   key_rel    = {0};


void key_poll(void)
{
    static uint_fast8_t key_capture;
    static uint_fast8_t vcntr0 = 0xff, vcntr1 = 0xff;
    static uint_fast8_t hold_timer = 0;
    static uint_fast8_t rep_timer = 0;

    //clear single pass flags for this loop
    
    key_pr.bytev      = 0;      //clear pressed and released
    key_ph.bytev      = 0;      //clear press and hold
    key_rpt.bytev     = 0;      //clear repeat
    key_rel.bytev     = 0;      //clear released
    
    if (!TC4ms) return;         //two rows to process once each 4ms

    //scan appropriate key row
    
    if (!KEY_ROW0)
    {
       key_capture = (~PORTB >> 1) & 0b0001;    //Capture KEY0 (on row 0)
       KEY_ROW0 = 1;                            //switch to row 1
       KEY_ROW1 = 0;                            //  for 2nd pass
       return;
    }
 
    key_capture |= (~PORTB & 0b1010);           //Capture KEY1 (on row 1) and Encoder Switch
    KEY_ROW0 = 0;                               //switch back to row 0
    KEY_ROW1 = 1;                               //  for next scan
        
    //process vertical counters (4 steps, total 32ms debounce time)
    
    key_capture ^= key_last;                      //compute changes since last pass
    
    vcntr0 = ~(vcntr0 & key_capture);                   //process vertical counters
    vcntr1 = (vcntr1 & key_capture) ^ vcntr0;

    key_capture &= vcntr0 & vcntr1;                     //get changes and check for overflow
    
    key_down.bytev ^=key_capture;                       //compute new keys down
    key_change.bytev = key_capture & key_down.bytev;    //compute new keys changed
    
    //process timed key functions
    
        if (hold_timer) goto kkhold;
        if (rep_timer) goto kkrep;
        if (!key_change.bytev) goto kexit;
        hold_timer = HOLD_TIMER_INIT;
        goto kexitr;
    
    kkhold:
        if (!key_down.bytev) goto kkpr;
        if (--hold_timer) goto kexit;
        key_ph.bytev = key_down.bytev;
        goto kkrep1;
    
    kkrep:
        if (!key_down.bytev) goto kexitr;
        if (--rep_timer) goto kexit;
    
    kkrep1:
        key_rpt.bytev = key_down.bytev;
        rep_timer = REP_TIMER_INIT;
        goto kexit;

    kkpr:
        key_pr.bytev = key_last;
            
    kexitpr:
        hold_timer = 0;
    
    kexitr:
        rep_timer  = 0;
    
    kexit:
        key_rel.bytev = ~key_down.bytev & key_last;
        key_last = key_down.bytev;
}
 

Thread Starter

joeyd999

Joined Jun 6, 2011
5,283
I continue to struggle to find ways to force C to minimize code size and execution speed. When doing math in .asm, I'm always availed the opportunity to access values at the bit, byte, or word levels and perform operations at the level that results in the most concise code.

For example, let's say I've got a 32 bit signed accumulator, the final important result is always an unsigned 16 bit integer that consists of the middle two bytes of the accumulator. Why would I want to do this? Imagine the low order of the four bytes is to manage the precision of the input data being accumulated, and the high order byte to handle overflows.

In .asm, this is easy: I do 32 bit math on the 4 constituent bytes, and use the middle two bytes as the result, completely ignoring the first and last byte (or adding 0x80 to the last byte to process rounding).

In C, this is not so easy (so it seems) without continually recasting data types and lots of unnecessary bit shifting over multiple bytes.

I've managed to get around this by creating complex data structure such as:

Example Structure:
typedef union
{
    int_fast32_t dwordv;
    struct
    {
        uint_fast8_t byte0;
        uint_fast8_t byte1;
        uint_fast8_t byte2;
        uint_fast8_t byte3;
    } bytev;
    struct
    {
        uint_fast8_t byte0;
        uint_fast16_t umwordv;
        uint_fast8_t byte3;
    } umixvm;
    struct
    {
        uint_fast8_t byte0;
        int_fast16_t mwordv;
        uint_fast8_t byte3;
    } mixvm;
    
} ct_bytemap32;
Unfortunately, I'm having to write multiple such structures which is killing the readability of the code.

Am I missing something? Is there an easier way to achieve the same result?
 

nsaspook

Joined Aug 27, 2009
13,262
That's pretty much the standard way to provide memory manipulation addresses in C for blocks of data memory. It can get redundant so I sometimes just use shifts instead. The readability of the code is more of a descriptive naming/formatting style. If the middle two bytes are for a section of the accumulator then name it something like that as a high level abstraction structure of the total memory block of bytes, words.
C:
/*
* File:   imu.h
* Author: root
*
* Created on September 19, 2022, 8:50 AM
*/

#ifndef IMU_H
#define IMU_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include <math.h>
#include "definitions.h"                // SYS function prototypes
#include "imupic32mcj.h"

#define IMU_DRIVER "V1.500"
#define IMU_ALIAS "IMU"

#define IMU_ID_DELAY 400
    /*
     * what IMU chip are we using
     */
    //#define BMA490L
#define SCA3300 // this includes the SCL3300 device

#define IMU_DATA_RAW_LEN  30
#define IMU_DATA_BUFFER_INDEX  1

    typedef struct _sSensorData_t {
        const uint16_t id;
        double x; /**< X-axis sensor data */
        double y; /**< Y-axis sensor data */
        double z; /**< Z-axis sensor data */
        float xa; /**< X-angle sensor data */
        float ya; /**< Y-angle sensor data */
        float za; /**< Z-angle sensor data */
        float xerr;
        float yerr;
        float zerr;
        uint32_t sensortime; /**< sensor time */
        float sensortemp;
        uint8_t buffer[64]; // can-fd frame buffer space
    } sSensorData_t;

    /*
     * function pointer templates structure
     * for the device I/O routines and data
     */
    typedef const struct _op_t {
        void (*info_ptr)(void);
        void (*imu_set_spimode)(void *);
        bool (*imu_getid)(void *);
        bool (*imu_getdata)(void *);
    } op_t;

    enum device_type {
        IMU_BMA490L = 0, // IMU chip model
        IMU_SCA3300,
        IMU_SCL3300,
        IMU_NONE,
        IMU_LAST,
    };

    /*
     * IMU data structure for driver
     */
    typedef struct _imu_cmd_t {
        const uint16_t id;
        uint32_t board_serial_id;
        enum device_type device;
        const uint8_t cs, spi_bytes, acc_range_scl;
        uint8_t acc_range;
        uint32_t log_timeout, rs, ss;
        volatile bool online, run, update, features, crc_error, angles;
        uint64_t host_serial_id;
        uint8_t rbuf[64], tbuf[64];
        uint32_t rbuf32[2], tbuf32[2];
        uint16_t serial1, serial2;
        op_t op;
    } imu_cmd_t;

    struct sca3300_data {
        const uint16_t id;

        struct {
            int16_t channels[9];
            uint16_t ret_status;
            uint32_t ts;
        } scan;
        uint8_t rs;
        uint8_t ss;
    };

    enum accel_g {
        range_2g = 0,
        range_4g,
        range_8g,
        range_16g,
        range_scale,
        range_15g,
        range_3g,
        range_6g,
        range_15gl,
        range_12g,
        range_24g,
        range_inc1,
        range_inc2,
    };

    enum sca3300_scan_indexes {
        SCA3300_ACC_X = 0,
        SCA3300_ACC_Y,
        SCA3300_ACC_Z,
        SCA3300_TEMP,
        SCA3300_TIMESTAMP,
        SCL3300_ANG_X,
        SCL3300_ANG_Y,
        SCL3300_ANG_Z,
    };

    /*! Earth's gravity in m/s^2 */
#define GRAVITY_EARTH   (9.80665)
    /*
     * device earth gravity range calibration scalars
     */
#define BMA490_ACCEL_MG_LSB_2G  0.000061035 ///< Macro for mg per LSB at +/- 2g sensitivity (1 LSB = 0.000061035mg) */
#define BMA490_ACCEL_MG_LSB_4G  0.000122070 ///< Macro for mg per LSB at +/- 4g sensitivity (1 LSB = 0.000122070mg) */
#define BMA490_ACCEL_MG_LSB_8G  0.000244141 ///< Macro for mg per LSB at +/- 8g sensitivity (1 LSB = 0.000244141mg) */
#define BMA490_ACCEL_MG_LSB_16G  0.000488281 ///< Macro for mg per LSB at +/- 16g sensitivity (1 LSB = 0.000488281mg) */
#define IMU_ACCEL_MG_SCALE  1.000000000
#define SCA3300_ACCEL_MG_LSB_15G 0.000207000 ///< Macro for mg per LSB at +/- 1.5g sensitivity    LSB/g 5400
#define SCA3300_ACCEL_MG_LSB_3G  0.000395000 ///< Macro for mg per LSB at +/- 3g sensitivity        LSB/g 2700
#define SCA3300_ACCEL_MG_LSB_6G  0.000765000 ///< Macro for mg per LSB at +/- 6g sensitivity        LSB/g 1350
#define SCL3300_ACCEL_MG_LSB_12G 0.000167400 ///< Macro for mg per LSB at +/- 1.2g sensitivity    LSB/g 6000
#define SCL3300_ACCEL_MG_LSB_24G 0.000333800 ///< Macro for mg per LSB at +/- 2.4g sensitivity    LSB/g 3000
#define SCL3300_INC1   0.000083700
#define SCL3300_INC2   0.000083700

#define ANGLE_RES1  16384.0
#define ANGLE_RES2  90.0
#define TEMPERATURE_RES  18.9
#define TEMPERATURE_OFFSET -273.0

    typedef struct sFFTData_t {
        uint16_t id;
        uint8_t buffer[64]; // can-fd frame buffer space
    } sFFTData_t;

    double get_imu_scale(imu_cmd_t *);
    void getAllData(sSensorData_t *, imu_cmd_t *);
    const uint8_t * imu_string(imu_cmd_t *);

#ifdef __cplusplus
}
#endif

#endif /* IMU_H */
C:
#include "imu.h"

const double imu_table[] = {
    BMA490_ACCEL_MG_LSB_2G,
    BMA490_ACCEL_MG_LSB_4G,
    BMA490_ACCEL_MG_LSB_8G,
    BMA490_ACCEL_MG_LSB_16G,
    IMU_ACCEL_MG_SCALE,
    SCA3300_ACCEL_MG_LSB_15G,
    SCA3300_ACCEL_MG_LSB_3G,
    SCA3300_ACCEL_MG_LSB_6G,
    SCL3300_ACCEL_MG_LSB_12G,
    SCL3300_ACCEL_MG_LSB_24G,
    SCL3300_INC1,
    SCL3300_INC2,
};

static const uint8_t imu_name [][8] = {
    "BMA490L",
    "SCA3300",
    "SCL3300",
    "NO IMU ",
};

static uint32_t sensortime;

static void move_bma490_transfer_data(uint8_t *, imu_cmd_t *);

extern struct sca3300_data sdata;

double get_imu_scale(imu_cmd_t * imu)
{
    double accelRange = IMU_ACCEL_MG_SCALE;

    if (imu) { // null pointer check
        /*
         * load the proper scaling constants
         */
        switch (imu->acc_range) {
        case range_16g:
            accelRange = BMA490_ACCEL_MG_LSB_16G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_8g:
            accelRange = BMA490_ACCEL_MG_LSB_8G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_4g:
            accelRange = BMA490_ACCEL_MG_LSB_4G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_15g:
        case range_15gl:
            accelRange = SCA3300_ACCEL_MG_LSB_15G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_3g:
            accelRange = SCA3300_ACCEL_MG_LSB_3G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_6g:
            accelRange = SCA3300_ACCEL_MG_LSB_6G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_12g:
            accelRange = SCL3300_ACCEL_MG_LSB_12G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_24g:
            accelRange = SCL3300_ACCEL_MG_LSB_24G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_inc1:
            accelRange = SCL3300_INC1 * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_inc2:
            accelRange = SCL3300_INC2 * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        case range_2g:
            accelRange = BMA490_ACCEL_MG_LSB_2G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
            break;
        default:
            if (imu->device == IMU_BMA490L) {
                accelRange = BMA490_ACCEL_MG_LSB_2G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
                imu->acc_range = range_2g; // update imu data structure
            } else {
                if (imu->device == IMU_SCA3300) {
                    accelRange = SCA3300_ACCEL_MG_LSB_15G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
                    imu->acc_range = range_15g; // update imu data structure
                } else {
                    accelRange = SCL3300_ACCEL_MG_LSB_12G * GRAVITY_EARTH * IMU_ACCEL_MG_SCALE;
                    imu->acc_range = range_12g; // update imu data structure
                }
            }
            break;
        }
    }

    return accelRange;
}

void getAllData(sSensorData_t *accel, imu_cmd_t * imu)
{
    uint8_t data[IMU_DATA_RAW_LEN + 2] = {0}; // add space for dummy data
    int16_t x = 0, y = 0, z = 0;
#ifdef SCA3300
    int16_t xa = 0, ya = 0, za = 0;
#endif
    double accelRange;

    accelRange = get_imu_scale(imu);

    // munge data to proper format for logging
    if (imu) { // null pointer check
        if (accel) { // null pointer check
            if (imu->device == IMU_BMA490L) {
                move_bma490_transfer_data(data, imu);
                sensortime = (data[9] << 16) | (data[8] << 8) | data[7]; // 24-bit sensor time
                sdata.scan.ts = sensortime;
                x = (int16_t) (((uint16_t) data[2] << 8) | data[1]); // 16-bit xyz data
                sdata.scan.channels[SCA3300_ACC_X] = x;
                y = (int16_t) (((uint16_t) data[4] << 8) | data[3]);
                sdata.scan.channels[SCA3300_ACC_Y] = y;
                z = (int16_t) (((uint16_t) data[6] << 8) | data[5]);
                sdata.scan.channels[SCA3300_ACC_Z] = z;
                accel->sensortime = sensortime; // time log each accel measurement from IMU
            }
#ifdef SCA3300
            x = sdata.scan.channels[SCA3300_ACC_X];
            y = sdata.scan.channels[SCA3300_ACC_Y];
            z = sdata.scan.channels[SCA3300_ACC_Z];
            accel->sensortime = sdata.scan.ts; // time log each accel measurement from TIMER
            accel->sensortemp = TEMPERATURE_OFFSET + (sdata.scan.channels[SCA3300_TEMP] / TEMPERATURE_RES);
            if (imu->device == IMU_SCL3300) {
                xa = sdata.scan.channels[SCL3300_ANG_X];
                ya = sdata.scan.channels[SCL3300_ANG_Y];
                za = sdata.scan.channels[SCL3300_ANG_Z];
                accel->xa = xa / ANGLE_RES1 * ANGLE_RES2; // scale angle data
                accel->ya = ya / ANGLE_RES1 * ANGLE_RES2;
                accel->za = za / ANGLE_RES1 * ANGLE_RES2;
            }
#endif
            accel->x = x * accelRange; // scale to the correct units
            accel->y = y * accelRange;
            accel->z = z * accelRange;
        }
    }
}

/*
* load raw SPI sensor data from IMU and transfer to the logging processing buffer
*/
void move_bma490_transfer_data(uint8_t *pBuf, imu_cmd_t * imu)
{
    if (pBuf && imu) { // null pointer checks
        for (uint32_t i = IMU_DATA_BUFFER_INDEX; i < IMU_DATA_RAW_LEN; i++) {
            pBuf[i - IMU_DATA_BUFFER_INDEX] = imu->rbuf[i];
        }
    }
}

const uint8_t * imu_string(imu_cmd_t * imu)
{
    const uint8_t * str_ptr = imu_name[IMU_NONE];

    if (imu) { // null pointer check
        if (imu->device < IMU_LAST) {
            str_ptr = imu_name[imu->device];
        }
    }
    return str_ptr; // return none string

}
 
Last edited:

BobaMosfet

Joined Jul 1, 2009
2,113
Hey, @nsaspook, I'm working on a PIC project in C. I feel icky all over.

In any case, I've got this code to declare and initialize an array of strings:

C:
const char * messages[] =   {
                            "Line 1 Init msg",    //m_init1
                            "Line 2 Init msg ",   //m_init2
                            "                "    //m_blank
};
The code compiles and runs as expected, but I get this compiler warning:



What the heck does this mean?
What is messages.h Your file? Did you extern the definition in it? Did you leave the .h version empty?
 

BobaMosfet

Joined Jul 1, 2009
2,113
I continue to struggle to find ways to force C to minimize code size and execution speed. When doing math in .asm, I'm always availed the opportunity to access values at the bit, byte, or word levels and perform operations at the level that results in the most concise code.

For example, let's say I've got a 32 bit signed accumulator, the final important result is always an unsigned 16 bit integer that consists of the middle two bytes of the accumulator. Why would I want to do this? Imagine the low order of the four bytes is to manage the precision of the input data being accumulated, and the high order byte to handle overflows.

In .asm, this is easy: I do 32 bit math on the 4 constituent bytes, and use the middle two bytes as the result, completely ignoring the first and last byte (or adding 0x80 to the last byte to process rounding).

In C, this is not so easy (so it seems) without continually recasting data types and lots of unnecessary bit shifting over multiple bytes.

I've managed to get around this by creating complex data structure such as:

Example Structure:
typedef union
{
    int_fast32_t dwordv;
    struct
    {
        uint_fast8_t byte0;
        uint_fast8_t byte1;
        uint_fast8_t byte2;
        uint_fast8_t byte3;
    } bytev;
    struct
    {
        uint_fast8_t byte0;
        uint_fast16_t umwordv;
        uint_fast8_t byte3;
    } umixvm;
    struct
    {
        uint_fast8_t byte0;
        int_fast16_t mwordv;
        uint_fast8_t byte3;
    } mixvm;

} ct_bytemap32;
Unfortunately, I'm having to write multiple such structures which is killing the readability of the code.

Am I missing something? Is there an easier way to achieve the same result?
And why aren't you doing inline assembly, then? That's why inline assembly exists. And if inline isn't an option, you do realize you can create your assembly code, copy the hex, put that in an array in C, get an address to it, and jump to it, right? Stop thinking of C as limiting you and understand the power it gives you do ANYTHING. You can craft C using these methods almost as tight as assembly language- I know, I did that for years in 6DoF environments.
 

MrSalts

Joined Apr 2, 2020
2,767
C is what it is. ASM is what it is but very specific to each processor.
C is more convenient and portable (skills wise and code wise.

In Joey's case, the fact that he has developed his specific applications for years and years who found all the little optimization tricks in ASM and now has to come from a cold start on C.
 

nsaspook

Joined Aug 27, 2009
13,262
No. C is limiting. Severely.
The C abstract machine is limiting when run on 8-bit small resource hardware because it's an efficiency kludge to make it run hardware it wasn't designed for. We keep using C because most other languages are an even bigger kludge on 8-bit systems.

Most of us have accepted that fact with higher spec'd base 8-bit hardware for designs and/or moved to at least 16-bit hardware.
PIC18f57K42 system.
https://forum.allaboutcircuits.com/...c-controlled-battery-array.32879/post-1448225
https://forum.allaboutcircuits.com/...c-controlled-battery-array.32879/post-1463914
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
5,283
The C abstract machine is limiting when run on 8-bit small resource hardware because it's an efficiency kludge to make it run hardware it wasn't designed for. We keep using C because most other languages are an even bigger kludge on 8-bit systems.

Most of us have accepted that fact with higher spec'd base 8-bit hardware for designs and/or moved to at least 16-bit hardware.
PIC18f57K42 system.
https://forum.allaboutcircuits.com/...c-controlled-battery-array.32879/post-1448225
https://forum.allaboutcircuits.com/...c-controlled-battery-array.32879/post-1463914
Call me frugal. I hate buying hardware capabilities I don't need.

Just give me support for picasm under MPLabX and I'll be happy for the remainder of my life.
 

nsaspook

Joined Aug 27, 2009
13,262
Call me frugal. I hate buying hardware capabilities I don't need.

Just give me support for picasm under MPLabX and I'll be happy for the remainder of my life.
Sadly:

Those hardware capabilities are there of provide efficiency solutions to 8-bit C CPU limitations. Expand your horizons, be creative.;)
 
Last edited:

ApacheKid

Joined Jan 12, 2015
1,609
No. C is limiting. Severely.
This is a meaningless statement. The environment you are working in is too limited for C to be a big help to you. Assembler might be the only language suitable for your needs in that environment.

A C programmer working in your situation would say "These 8 bit PIC things are limiting, severely".

Let me ask, what would you have C do differently, what changes could be made that would reduce the "limiting" nature of things for you?

Is the language's expressiveness not a good fit? or the code generated?

If these devices are unusual, so untypical then perhaps a language should be designed that is specific to them, exploits them in the way you like to...
 

Thread Starter

joeyd999

Joined Jun 6, 2011
5,283
This is a meaningless statement. The environment you are working in is too limited for C to be a big help to you. Assembler might be the only language suitable for your needs in that environment.

A C programmer working in your situation would say "These 8 bit PIC things are limiting, severely".

Let me ask, what would you have C do differently, what changes could be made that would reduce the "limiting" nature of things for you?
Haven't I made myself clear, repeatedly? Let me shout it:

I DO NOT WANT TO WRITE C CODE FOR 8 BIT CPUS! I WANT TO WRITE ASM. BUT I CANNOT, BECAUSE MY CPU VENDOR WILL NO LONGER SUPPORT A DECENT ASSEMBLER FOR THEIR PARTS.

Comprende?
 

nsaspook

Joined Aug 27, 2009
13,262
This is a meaningless statement. The environment you are working in is too limited for C to be a big help to you. Assembler might be the only language suitable for your needs in that environment.

A C programmer working in your situation would say "These 8 bit PIC things are limiting, severely".

Let me ask, what would you have C do differently, what changes could be made that would reduce the "limiting" nature of things for you?

Is the language's expressiveness not a good fit? or the code generated?

If these devices are unusual, so untypical then perhaps a language should be designed that is specific to them, exploits them in the way you like to...
The constraints are real, on real devices, in real products. It take a while to learn the C tricks used in the 8-bit domain.

I've had to push pretty hard to make added functionally fit in a deployed device designed for a pretty simplistic operation.

1674247314616.png
 

djsfantasi

Joined Apr 11, 2010
9,160
Haven't I made myself clear, repeatedly? Let me shout it:

I DO NOT WANT TO WRITE C CODE FOR 8 BIT CPUS! I WANT TO WRITE ASM. BUT I CANNOT, BECAUSE MY CPU VENDOR WILL NO LONGER SUPPORT A DECENT ASSEMBLER FOR THEIR PARTS.

Comprende?
So practically speaking, it is not C that is limiting. It is either your selected part or your inability to write what you want in C.
 

nsaspook

Joined Aug 27, 2009
13,262
So practically speaking, it is not C that is limiting. It is either your selected part or your inability to write what you want in C.
IMO C on 8-bit limiting (on code size and speed) because it can't completely and simply mesh with all requirements of the needed C minimal abstract machine without some level of software mapping abstraction for things like, pointers for sram and flash, integer promotion with 8-bit words, etc ... A lot of the optimization in a good 8-bit C compiler is reconstruction of the code into a efficient 8-bit model.
 
Top