Is there a way for a program to know if it's executed under the simulator and not on an actual CPU?
Alright, here's my solution for LPC2xxx chips, in case anyone is interested. It is based on the fact that most flash programming tools modify the program image in such a way that the sum of all interrupt vectors in the boot block will be 0, whereas under the simulator the program is executed "as is", without any modification.
#include <stdint.h> #include <stdbool.h> bool in_simulator(void) { uint32_t sum = 0; uint32_t * p; for (p = 0; p < (uint32_t *)0x20; p++) sum += *p; return sum != 0; }
I doubt that anyone cares, but any criticism and suggestions are welcome :)
It is based on the fact that most flash programming tools modify the program image in such a way that the sum of all interrupt vectors in the boot block will be 0,
But that reasoning, what you're describing isn't what you said you wanted to have. It's a way to detect flash programming tools' checksumming of the vector table, not one to detect the simulator.
And of course, nothing stops the person configuring the simulator from implementing the same kind of checksumming either to the program itself, or as part of the debugger startup script, thus completely fooling your "detection".
You did quote two questions.
But none of your own text did answer any of the two questions. We still don't know the answer to the "why"...
You mean why a program would need to know whether or not it's running under the simulator? I need that for debugging. I cannot use any of the debug adapters due to the specifics of our device, so I have to use the simulator extensively. And as the simulator doesn't support many of our peripherals, I have to turn off some program components when I want to debug some others. Basically, I have to implement two configurations for the program depending on where it's being executed.
Before posting here I did some googling and found nothing, not even a single mention of the problem!
You seem to have completely overlooked that the reason for nobody mentioning this problem might be that this is not a problem. That's a typical result of trying to hide the context of your request from the people you seek help from.
And as the simulator doesn't support many of our peripherals, I have to turn off some program components when I want to debug some others. Basically, I have to implement two configurations for the program depending on where it's being executed.
And if you had told us that right away, you would have got the solution to your actual problem much earlier, rather than not-quite-solutions to what you thought the problem was.
You do not need to do detect the simulator. You need to tell your program that it's running in the simulator. That's what multi-target projects and compiler switches are for. You just build a special version of the program tailored to working on the simulator, and that's that.
You just build a special version of the program tailored to working on the simulator, and that's that.
I have to agree with that. It's probably an error on his part and likely to be a one off.
This is inconvenient to me. I'm running the program on the device and when I see something go wrong I launch the program in the IDE - and it's the same program, I don't need to change 10+ switches and recompile it.
So I definitely knew what I was doing when I was asking how to detect the simulator and not how to use compiler switches :)
and it's the same program, You say that as if it were the solution to some problem. But it's not. It's actually a problem which you introduced into your program. Did you ever ask yourself what would happen if your simulator detection ever randomly failed on real hardware? Well, your "solution" will then turn off a whole series of important peripherals because it believes it's running in a simulator. Bad news. This is not code you want to have in your actual production executable.
I don't need to change 10+ switches and recompile it.
If you truly believe you need "10+ compiler switches" to achieve this, maybe you should get on-site help with this project of yours.
I was writing my last message late at night in local time and I didn't think very well... Of course you could get along with only one compiler switch, but you still have to remember to change that switch and recompile the program every time you want to run it on the simulator. Not a problem? Well maybe :) But this has been bugging be for the last few days as the program is being actively developed.
Did you ever ask yourself what would happen if your simulator detection ever randomly failed on real hardware?
Can you give a realistic scenario of how the code in the second post could fail on real hardware? :) But your point still makes sense. I'll probably have to condition it out of the production build, thanks for the tip-off!
still have to remember to change that switch and recompile the program every time you want to run it on the simulator. Not a problem?
Congratulations, you're now only half a step away from figuring out why my recommendation mentioned not just compiler switches, but also multiple targets in one IDE project. One of those could conveniently called, hmm, let's see, "Debug" and differ from the other one ("Release", maybe?) by a) the detailed configuration and initialization sequence for your debugger of choice: the simulator, and b) any and all other changes necessary to configure the program for debugging, e.g. compiler switches, or reduced optimization flags.
This approach does violate an important rule in safety conscious embedded development: you debug what you fly, and you fly exactly what you debugged. But if that's truly not an option, as you claimed, then there's nothing significant left to be lost by tailoring the debug build for optimal debugging capabilities.
I am using uVision V4.60.0.0 and I haven't noticed any "multiple targets" facility in it. It does support "Multi-Project Workspaces" though, which basically means that you can edit and compile two or more projects at the same time. Presumably I could create a parallel "Debug" project and compile it along with the "Release" one. But then I have to 1) keep the two projects in sync and 2) put up with the fact that compilation now takes two times as longer (or I still have to remember to recompile).
Well, I don't know... I still haven't seen any strong arguments as to why my method may fail and why having to maintain two projects instead of one is safer and facilitates debugging.
That being said, you've sowed a grain of doubt in me. I guess I have to think more about it. Anyway, thank you everyone for your input :)
I haven't noticed any "multiple targets" facility in it. Then maybe you haven't looked very thoroughly. Let me point your attention to the Project->Manage->Components,... dialog, and the fact it has a list of Project Targets for you to manage.
I still haven't seen any strong arguments as to why my method may fail
Actually you have. You even put the most important one right above your own description of your proposed solution. You wrote that most flash programming tools do that checksumming you intend to base your solution's design on. Someone replied that only tools for one particular brand of ARM micro controllers really do that.. So where exactly does your sudden confidence come from that this will always be the case? How do you plan on excluding the possibility that your program will, at some point, by somebody you've never spoken to, be flashed by a programming tool that doesn't follow that scheme?
Need to run "the same" program? You aren't if you are completely switching what code flow your program takes. If you run different code lines in the simulator that's the same logically as running a different program.
And changing 10 switches? Why? Too quick to just change one?
#define SIMULATION 1
And that can be supplied on the command line in the project file, so no need to even change that parameter - you just switch active target.
Save yourself lots of grief and continued nonsense responses. Invest in a ulink.
Then maybe you haven't looked very thoroughly. Let me point your attention to the Project->Manage->Components,... dialog, and the fact it has a list of Project Targets for you to manage.
Wow, that couldn't be hidden better!.. But again you have to remember to switch targets and recompile the program every time you want to launch it in the simulator... Multi-Project Workspaces is probably even more convenient as it allows you to compile all your targets at once.
Anyway, thanks for the hint, I was unaware of that feature :)
You wrote that most flash programming tools do that checksumming you intend to base your solution's design on. Someone replied that only tools for one particular brand of ARM micro controllers really do that..
I thought I was clear enough when I wrote "here's my solution for LPC2xxx chips" that this solution applies to one particular brand of ARM microcontrollers :) And, I admit, it was probably a mistake to write that "most" flash programming tools do that checksumming. In fact, all of them that work with that brand and use ISP should do it.
So where exactly does your sudden confidence come from that this will always be the case? How do you plan on excluding the possibility that your program will, at some point, by somebody you've never spoken to, be flashed by a programming tool that doesn't follow that scheme?
I'm afraid I'll have to explain the boot process on the LPC2xxx...
All LPC2xxx chips (OK, all that I know of) come with a boot loader. The boot loader does two things: 1) provides an interface with flash programming software ("In-System Programming") and 2) actually executes the user program. Before execution, the boot loader checks user code validity with the very procedure I wrote in the second post. If the code isn't valid, it doesn't get executed. And what makes the user code "valid" is the flash programming software that modifies the program's image appropriately before flashing it.
That means that a program with no correct checksum just can't be running on a real word LPC2xxx, but that happens on the simulator.
Once again, to make it absolutely clear, my method is valid if:
1) it's an LPC2xxx 2) it has a boot loader
I'm not sure if 2) necessarily follows from 1), but so far I'm fine with both :)
You dare to explain something to Hans-Bernhard Broeker?
If you run different code lines in the simulator that's the same logically as running a different program.
Not exactly. A program may take any branch of execution depending on its input, but it's still the same program :) A different program in my case has all its variables/functions at different addresses. This may happen if the same source is compiled with different switches, and it's important to debug the same program, because some hard-to-detect errors (like buffer/stack overflows etc) may manifest themselves with one memory layout and not with the other.
As I said, I wouldn't have to switch targets at all if I could debug using ulink or something, but since I can't, I have to do it too often and it buggers me. So it goes :)
-> if I could debug using ulink or something
I am quite sure that, many persons involved in this thread, are embedded experts, they are good at HW/SW and many other fields. And the most important, one of them is very familiar with NXP LPC23xx. So, if it is not confidential, it would be nice if you can provide Why/Why-Not.
So, if it is not confidential, it would be nice if you can provide Why/Why-Not.
Well, it was the choice of our hardware engineers :) I'm not sure, but it has something to do with the size of our device and their not being able to find room for the connectors on the boards :) As a matter of fact, we have two LPC chips on one board and more on others, and we can't even program them separately. We communicate with one of them via CAN and it in turn programs the others using ISP...
When there is lack of room for a connector, it's still often possible to just get a few test points on the board and then you manually solder wires to get a debugging interface. With good solder skills, the test points can be made very small and very close together.
So in the end, I find it very strange to not be able to make the boards capable of JTAG-debugging.
But there is another, very easy, option - solder a JTAG interface directly on the processor pins. Spend 30 minutes and you have a board with JTAG debugging. Way better than simulation and you can finally debug real code without strange code stubs that you wouldn't want in a final release version.
Alright. Just in case someone is still interested in the topic, I'd like to offer a working cross-platform example of how the simulator can be detected using a debug script. Kudos goes to Chad Clendening and Per Westermark for the idea.
This code works on both the ARM and the 8051 simulators, with slightly different debug scripts. I now don't have all the necessary hardware to test the code on it, but I hope it works on it just as good :) Anyway, I would appreciate it if someone would check that out :)
/* sim-detect.c */ #include <stdio.h> #include <string.h> #if defined(__arm__) /* This is here only to print a message over UART. In the IDE it will show up in a Serial Window. */ #include <lpc21xx.h> #define VPB_CLOCK 12000000 #define BAUD_RATE 9600 int sendchar(int ch) { while (!(U0LSR & 0x20)) ; return (U0THR = ch); } /* ------------------------------------------------------------------------- */ int getkey(void) { while (!(U0LSR & 0x01)) ; return U0RBR; } /* ------------------------------------------------------------------------- */ struct __FILE { int handle; }; /* ------------------------------------------------------------------------- */ int fputc(int ch, FILE *f) { return sendchar(ch); } /* ------------------------------------------------------------------------- */ void _sys_exit(int return_code) { for (;;) ; } /* ------------------------------------------------------------------------- */ #elif defined(__C51__) #include <reg51.h> #endif /* Attention! These memory address values were chosen for demonstration purposes only. They may be incompatible with your particular memory layout. */ #if defined(__arm__) #define SIM_DETECTOR_ATTR __attribute__((section(".ARM.__at_0x40000000"))) #elif defined(__C51__) #define SIM_DETECTOR_ATTR _at_ 0x30 #else #define SIM_DETECTOR_ATTR #endif volatile unsigned char sim_detector SIM_DETECTOR_ATTR; int main(void) { /* set up UART0 to see the detection message */ #if defined(__arm__) PINSEL0 = 0x00000005; U0LCR = 0x83; U0DLL = (VPB_CLOCK/16/BAUD_RATE) & 0xFF; U0DLM = ((VPB_CLOCK/16/BAUD_RATE) >> 8) & 0xFF; U0LCR = 0x03; #elif defined(__C51__) SCON = 0x50; TMOD |= 0x20; TH1 = 213; TR1 = 1; TI = 1; #endif sim_detector = 0x55; if (sim_detector == 0xAA) puts("SIMULATOR DETECTED"); else puts("SIMULATOR NOT DETECTED"); return 0; }
The debug script for the ARM:
/* debug-arm.ini */ signal void sim_detect(unsigned long adr) { unsigned char val; while (1) { /* wait for write access */ wwatch(adr); /* read value */ val = _RBYTE(adr); /* uncomment the line below if you want to see sim_detector values */ // printf("sim_detector = %X\n", val); /* change value */ val = ~val; /* write value back */ _WBYTE(adr, val); } } sim_detect(0x40000000);
The debug script for the 8051:
/* debug-c51.ini */ signal void sim_detect(unsigned long adr) { unsigned char val; while (1) { /* wait for write access */ wwatch(adr); /* read value */ val = _RBYTE(adr); /* uncomment the line below if you want to see sim_detector values */ // printf("val = %X\n", val); /* change value */ val = ~val; /* write value back */ _WBYTE(adr, val); } } sim_detect(D:0x30);
By the way - never let hardware engineers run the show all by themselves. Always make sure that there are one or more skilled sw guys involved, and that it is 100% clear that the total quality of the product depends on the ability to test both the hardware and the software. And that a JTAG interface isn't just an optional method of programming the processors but an excellent way to validate the prototype hardware by allowing the pins to be wiggled etc.
View all questions in Keil forum