Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
I'm working on a project that would benefit from having a good function call trace system, after reading up on stuff around the internet it seems like this is a format that can do the job:

code:
#define TRACE(...) do { printf(...); } while(0);
It basically lets you plop in a printf() wherever you need it while debugging, then comment it out to

code:
#define TRACE(...) // do { printf(...); } while(0);
and it compiles to nothing if you don't need it. Nice! But why is the printf() call wrapped inside of the do-while loop?

Adbot
ADBOT LOVES YOU

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.


Thanks much for the excellent and detailed explanation! :tipshat:

You wrap your code in do{}while(0) so that it works syntactically as you want with semicolons, but since that structure doesn't do anything useful it gets optimized out to nothing in the actual output. Other constructs like if statements don't work the same way with semicolons so it has to be do-while.

pseudorandom name posted:

Well, you screwed up your examples, it should be do { } while (0)

True, I was typing it out from memory and auto-included the semicolon by force of habit. I didn't understand the importance of it not being there so it didn't jump out at me. I get why you don't want it there now.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
Weird question: does the first function called in a C++ program absolutely have to be called main, or can we rename it to something else?

The reason I ask is because I just started some work on an embedded microcontroller with an asymmetric dual core, one is a (relatively) beefy Cortex M7 and the other is a weaker Cortex M4 on the same silicon. When kickstarting the chip from power on and doing all of the stuff to init the processors before handing off fully to the software side I end up with two functions, both called main(), when a more natural naming might be main_m7() and main_m4(). My IDE absolutely rejects me naming them that, but having two different things with the same name is mildly confusing in the code.

I suppose I can just make each main() call a pass-thru function to main_m7 and main_m4, but it's just an interesting thought experiment to consider naming them something else natively.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
Thanks everyone who commented, I appreciate the info and advice!

Foxfire_ posted:

Do you have an operating system with concepts like 'programs', or are you just using the chip directly?

Nope, this is bare metal register-flippy stuff. The power comes on and the hardware knows the first four bytes are the starting value of the stack pointer, then the next four bytes are the reset vector aka the starting value of the program counter. Those get loaded and then you pop into the reset vector code where I do all the setup stuff you described, then call main.

So yeah, I didn't think the name main was going to be special in that context, it's just a thing I call once the chip is ready to go. But I think the IDE is throwing a fit because, as Dijkstracula pointed out, the name main is standardized as special in most cases.

Anyway I think I hit on a solution that meets my needs without getting into doing anything too strange. The function name main may be special but the file name that main is located in is not. So I should be able to call one file main_m4.cpp and the other main_m7.cpp, put each of the respective main() calls in each one which keeps the compiler happy, but now I'm also happy because I don't have two tabs open in the IDE labeled main.cpp but containing different contents causing me to swear under my breath as I open the wrong one for the hundredth time that day.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.

StumblyWumbly posted:

How are you building this? I'd think you'd need 2 separate projects and linkers, but it sounds like your IDE is putting it all into one? Or is it mainly that you don't like having 2 similar projects open at once?

This is in Visual Studio with the VisualGDB extension for working on embedded microcontrollers. I'm in the learning phase of how to do dual core processors but as I understand it now you make one VS solution with two projects inside it, one for each processor. Then each project gets its own linker/startup/chip header/code that can be compiled and downloaded to the target independently.

The two project thing is what leads to having two main.cpp files which gets slightly confusing since both can be open in the IDE at once. I think I can resolve that by naming the files main_m7.cpp and main_m4.cpp, and let each contain a main() call without doing anything super weird.

Next up on the list is figuring out how to assign different hardware peripherals to each processor and how to run a hardware debugger with two processors since apparently you can set it up so that a breakpoint in one stops only that processor or both.

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
Is there any way to tell a linker script to put a data structure at a specific location in memory?

My situation is that I'm working on an embedded microcontroller with two processors and I want to set up some FIFO queues to pass messages between them. Each processor has its own project with its own linker script, but they need to agree exactly on where the FIFOs are located so they can take turns reading/writing data.

What I am doing now, which works but feels sub-optimal, is manually declaring a variable in each linker script that contains the base address of a section of memory that both processors can access. Then there is a code file that is common to both processors that reads that address variable and assigns it to a struct pointer that defines my FIFOs. That makes both processors access the FIFO structs at the same memory location which basically works. But there is nothing stopping some other code from also declaring a variable in that location which would lead to a real fun bug.

Is there a better way to do this?

Adbot
ADBOT LOVES YOU

PDP-1
Oct 12, 2004

It's a beautiful day in the neighborhood.
Thanks for the replys!

rjmccall posted:

Casting an integer to a pointer to your struct is by far the easiest and most portable way.

Qwertycoatl posted:

I agree with this.

Also, if at all possible, the integer should come from a header file supplied with your platform instead of being copied into your source code from a pdf

OK, that sounds pretty much like what I was doing, just with the extra step of getting the value out of the linker script because I was thinking that that is the place memory architecture should be described. I like the idea of getting the memory address out of the chip header file though, I'll take a look and see if it's defined in there.

Jabor posted:

Your linker scripts should define two separate memory segments:

- One for memory that's private to that processor, which should accept all sections that aren't explicitly targeted elsewhere
- One for memory shared with the other processor

For the definitions of locations within the shared memory segment, include the exact same file from both linker scripts. This file should declare your FIFO section and tell the linker to place it in the shared memory segment. Enforce (through code review or tooling) that nobody explicitly targets the shared memory segment from outside the common file.

That's kind of the setup I started with, but then had the paranoid thought that if future-me ever forgot about the details and allocated another bit of memory in this shared bank to be used by only one processor, that' processors linker might stack things in memory from the base address as (new item, FIFOs) while the second processor's linker would just have (FIFOs) and they wouldn't agree on the FIFOs address.

This makes me think that maybe it would be a good idea to comment out references to the shared memory entirely from the linker scripts while adding a note stating why I did that. Then future me can't would not be able to put anything else there by just giving it an attribute, I'd have to open up the linker script and (hopefully) run across my old warning comments.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply