News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_tulinmola

Sharing constants between C and ASM with SDCC

Started by tulinmola, 11:08, 08 August 18

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

tulinmola

Hi there! I have a simple question – I guess.


Let me illustrate this with an example. Suppose we have these files:



// renderer.h
...
#define RENDERER_WIDTH nn
...
extern void renderer_drawSprite(...);
...




// renderer_drawSprite.h
.equ RENDERER_WIDTH, nn
...



As you can see the RENDERER_WIDTH constant appears twice. And that's not good... At least I don't like it very much. So, my question is, how do you share constants between C and ASM code? Is there any "best practice" here?


Thanks in advance!
Tulo

freemac

#1
#define does not create variable (/constant), it's just a "rename this into that" done even before compiling C (#, it's preprocessing instructions)

When you compile the .c, you can see the .asm build after.

Using global variable (outside of function) is good practice in SDCC Z80, you can also use struct.

.equ does not create variable (/constant), also, you can find them in some Targhan .asm for compiling music routine with or else without sound effect routine, building then a smaller or larger .bin file at result. So once again, here it's just a "rename this into that" done even before assembling ASM.

You can more dynamically write ASM from C using __asm__() function :
__asm__("NOP\nNOP\nNOP\nNOP\nNOP\n NOP\nNOP\nNOP\nNOP\nNOP\n NOP\nNOP\nNOP\n");

ronaldo

#2
Quote from: tulinmola on 11:08, 08 August 18
As you can see the RENDERER_WIDTH constant appears twice. And that's not good... At least I don't like it very much. So, my question is, how do you share constants between C and ASM code? Is there any "best practice" here?
To make you feel better (or not), I stumbled upon this problem two years ago and have not found a proper solution yet. Depending on the context, you may design your own workarounds. For instance, you may create a macro that generates both a #define and a piece of assembly. Something like this (warning: untested)

#define DEFINECONSTANT(C,VAL) \
  #define C VAL \
  void dummyfunction_##C##_VAL() __naked { \
   __asm { \
      .equ C, VAL \
   }__endasm; \
  }

It is the best I can think of by now.

cpcitor

Hi everyone. Old post, but interesting, and new information!

Quote from: tulinmola on 11:08, 08 August 18
As you can see the RENDERER_WIDTH constant appears twice. And that's not good... At least I don't like it very much. So, my question is, how do you share constants between C and ASM code? Is there any "best practice" here?

Good question tulinmola, thanks for asking!
I am also very sensitive to the DRY principle (don't repeat yourself), SSOF (sigle source of truth) etc.

I see two uses for this:

* sharing memory addresses between asm and C, used to pass data. This is already well taken care of by Assembler and linker (declare extern on one side, declare global with value on the other). But it's not memory addresses that we want: we want constants.
* constants that can be used both sides to generate compact fast code, no indirections.

There are extra questions, like: ASM only knows integer values, but C can use #define (basically text) but also typed values (signed/unsigned integers, pointer), etc. Could we share values and get them typed on the C side?

Quote from: ronaldo on 12:56, 08 August 18
To make you feel better (or not), I stumbled upon this problem two years ago and have not found a proper solution yet. Depending on the context, you may design your own workarounds. For instance, you may create a macro that generates both a #define and a piece of assembly. Something like this (warning: untested)

#define DEFINECONSTANT(C,VAL) \
  #define C VAL \
  void dummyfunction_##C##_VAL() __naked { \
   __asm { \
      .equ C, VAL \
   }__endasm; \
  }

It is the best I can think of by now.

Unfortunatey, by design preprocessor macros cannot generate #define directives. This is similar to question https://stackoverflow.com/questions/860273/macro-producing-macros-in-c , answer there is negative.

Yet there is hope!

I've been facing the problem in a small project I'm doing (small path towards a greater goal) and think I may have found a solution that looks neat. It should allow to:
(1) define named constants,
(2) use them as compile-time constants in ASM as well as in C,
(3) allow to define some in reference to others if needed,
(4) allow to use them as parameters to macro calls (both assembly macros and C macros)
(5) if at all useful, also be available as typed (well, only one type, unsigned 16bit, but thats what they are anyway). -- I suspect the compiler will always to a better optimization with good old #defined values than with typed values anyway.

I'll tell how it goes.
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

cpcitor

#4
Quote from: cpcitor on 05:18, 06 December 19
I've been facing the problem in a small project I'm doing (small path towards a greater goal) and think I may have found a solution that looks neat. It should allow to:
(1) define named constants,
(2) use them as compile-time constants in ASM as well as in C,
(3) allow to define some in reference to others if needed,
(4) allow to use them as parameters to macro calls (both assembly macros and C macros)
(5) if at all useful, also be available as typed (well, only one type, unsigned 16bit, but thats what they are anyway). -- I suspect the compiler will always to a better optimization with good old #defined values than with typed values anyway.

I'll tell how it goes.

Okay, it's mostly working but not really ready.
It works very well to propagate "simple" integer constants globally, à la #define.

Propagating typed values naively is not good because SDCC generates code and allocates memory to store the value. Perhaps this is so that the user can always take a pointer to that value.
Anyway this leads to inefficient Z80 code for typed values.
Code is very good for values propagates ad #define.

I'm continuing to think through this. I believe there can be a simple and natural way to get typed values. Something that allows to never repeat oneself yet share variables easily, with types if needed. Will find it.
Had a CPC since 1985, currently software dev professional, including embedded systems.

I made in 2013 the first CPC cross-dev environment that auto-installs C compiler and tools: cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC, later forked into CPCTelera.

reidrac

#5
The #defines are processed by the cpp (C pre processor), so they only exist in C land. You can use them in ASM if you embed the ASM code.

For example:

#define CONSTANT 5

void fn()
{
  __asm;
    ld bc, #CONSTANT
  __endasm;


But I don't think you can have an include file that can be used in both C and ASM files, basically because the cpp won't process those ASM files.

I use __asm and __endasm sometimes when I'm converting from C to ASM, or because they are small pieces of ASM in an otherwise C code module. If I'm writing an ASM file, those tend to be independent and I try to avoid sharing constants (although sharing variables is OK, I tend to avoid that because it usually means a worse design).

My two cents.

EDIT: I'm not sure if I understand completely your problem. Just in case, you can do this...


// main.c
extern unsigned char shared;

unsigned char is_shared_zero();

void main()
{
   shared = 1;
   is_shared_zero(); // this is false
}



// module.z80
.globl _shared ; this will export _shared in asm and shared (no leading underscore) in C
.globl _is_shared_zero

_is_shared_zero::
  ld l, #0
  ld a, (_shared)
  or a
  ret nz
  ld l, #1
  ret
Released The Return of Traxtor, Golden Tail, Magica, The Dawn of Kernel, Kitsune`s Curse, Brick Rick and Hyperdrive for the CPC.

If you like my games and want to show some appreciation, you can always buy me a coffee.

Powered by SMFPacks Menu Editor Mod