1

Currently I have a C code that looks like this:

set_idt_entry(idt, 0, code_segment, &handle_interrupt0, 0, 0xE);
set_idt_entry(idt, 1, code_segment, &handle_interrupt1, 0, 0xE);
set_idt_entry(idt, 2, code_segment, &handle_interrupt2, 0, 0xE);
set_idt_entry(idt, 3, code_segment, &handle_interrupt3, 0, 0xE);
set_idt_entry(idt, 4, code_segment, &handle_interrupt4, 0, 0xE);
set_idt_entry(idt, 5, code_segment, &handle_interrupt5, 0, 0xE);
set_idt_entry(idt, 6, code_segment, &handle_interrupt6, 0, 0xE);
                                .
                                .
                                .

Repeated calls are taking about 256 lines and are looking ugly. I'm stuck trying to come up with a macro that could take care of this in a loop somehow. Is possible to do or leaving 256 lines of code is the best I can do?

jason
  • 45
  • 1
  • 7
  • 1
    I guess you would enter a world of preprocessor pain, see https://stackoverflow.com/questions/319328/how-to-write-a-while-loop-with-the-c-preprocessor. Might be better to stick to manual editing or a code generator as long as you don't have many of those cases in your code. – grek40 Jan 12 '22 at 07:43
  • 1
    Why not have a `for (int i = 0; i < 256; i++)` loop in the first place and a table containing `handle_interrupt0` to `handle_interrupt255`? But then you'd have a table with 256 entries, but it's still better IMO. – Jabberwocky Jan 12 '22 at 07:43
  • @grek40 Wow that's even uglier :). Thank you for showing me this though, I know what I'm dealing with now. If this is the only solution I will stick to current approach. – jason Jan 12 '22 at 07:47
  • @Jabberwocky As you mentioned it's still the same problem. Not really what I'm looking for – jason Jan 12 '22 at 07:49
  • 2
    The problem is that you made 256 unique identifiers to begin with, instead of an array. Where do these `handle_interrupt0` names come from? How are they declared? – Lundin Jan 12 '22 at 07:51
  • 2
    Why do you need to set 256 interrupt handlers in the first place? Set ones you actually use and give them proper names and they will already be more clearer and cleaner. –  Jan 12 '22 at 07:52
  • @Lundin They come from assembler macro – jason Jan 12 '22 at 07:53
  • Indeed. The average interrupt vector table has some default interrupt that you point at for those not used (typically the reset vector). – Lundin Jan 12 '22 at 07:54
  • (Btw if this happens to be a Cortex M there's a very neat solution to the default interrupt problem since it got reset vector at address zero.) – Lundin Jan 12 '22 at 07:56
  • Let's not get into interrupts. I want to know if this is possible to do with a macro in C language or not. If everyone agrees it is not possible the problem is solved and this question could be closed. – jason Jan 12 '22 at 07:58
  • Hang on... I'm writing an answer, though it could be made far less hacky-looking on a Cortex M. – Lundin Jan 12 '22 at 08:04
  • 1
    The macro capabilities of the C preprocessor are quite limited and don't offer loops per se. If you don't want a hacky solution, but a readable one, use your explicit code. Otherwise use another preprocessor, there are some, you don't need to write your own. – the busybee Jan 12 '22 at 08:16
  • 2
    Using external scripts for code generation, which you launch from the IDE before compiling, is often a sensible solution indeed. Just make sure that the auto-generated code goes into a file of its own. – Lundin Jan 12 '22 at 08:21

1 Answers1

4

You should place those variables in an array. Assuming these are ISR function pointers, then it would look something like:

void (*handle_interrupt[256])(void) = { ... };

Or better yet use a typedef:

typedef void isr_t (void);
isr_t* handle_interrupt [256] = { ... };

And even better, assuming embedded system, ensure this table ends up in flash:

static isr_t* const handle_interrupt [256] = { ... };

Now to avoid code repetition in this initializer list, come up with a default interrupt vector for those ISRs that aren't used. Like for example:

#define handle_default reset_interrupt

You can then create a default initializer list like this:

#define def1 handle_default, // note the comma here
#define def2 def1 def1
#define def5 def2 def2 def1
#define def10 def5 def5
... // you get the idea
#define def256 def100 def100 def50 def5 def1

static isr_t* const handle_interrupt [256] = { def256 };

Now I'm assuming that some of these won't be default vector. In that case we can do a trick by adding extra designated initializer at the end of the list. The order of evaluation of sub-expressions in an initializer list is unspecified, but the actual order of initialization is left-to-right (the order the initializers appear, C17 6.7.9/19). Like this:

static isr_t* const handle_interrupt [256] = 
{ 
  def256,
  [ 5] = handle_adc,   // #5 used for custom ADC interrupt
  [10] = handle_spi,   // #10 used for custom SPI interrupt
};

And now run-time code using this array will be trivial:

for(size_t i=0; i<256; i++)
  set_idt_entry(idt, 0, code_segment, &handle_interrupt[i], 0, 0xE);
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • A lot of assumptions of my code and not really what I'm looking for but I guess it answers my question - it's not possible to do it with a macro. – jason Jan 12 '22 at 08:23
  • @jason If you posted sufficient details in your question, then we wouldn't have to gaze into crystal balls to make those assumptions... The _actual_ problem you are trying to solve is _not_ "is there a macro which enumerates identifiers" but "is there a sensible way to write this interrupt handler initialization code without code repetition". – Lundin Jan 12 '22 at 08:27
  • Not really. I explicitly asked for macro because I wanted to know capabilities of C preprocessor and if it can solve this kind of problems. I was not that interested in this particular scenario that you dived into. It just so happend that I came into this problem while writing interrupts handlers. – jason Jan 12 '22 at 08:35
  • Only the order in which the initialization list expressions are evaluated is unspecified (C18 6.7.9/23), and initialization list expressions for subobjects that are overridden later might not be evaluated at all (note 151), but the order in which initialization list expressions are mapped to subobjects is well defined (6.7.9/19, also see note 152). So your neat trick is perfectly C standard compliant! – Ian Abbott Jan 12 '22 at 10:24
  • @IanAbbott Yeah my guts told me that apart from evaluation, they would behave as the comma operator, left-to-right. I can edit out that part of the answer. – Lundin Jan 12 '22 at 10:42