Monday, August 24, 2009

Puzzler #1


unsigned char x = 0x80;

main (void) {
char y;

y = 0x80;
if (x != y) {
printf("This should not happen\n");
}
}


Why does the string "This should not happen" appear on the console? It does on VS2005 for x86, but may not on a 8051 processor.

Answer: The problem is that 'char' and 'unsigned char' are different when it comes to comparisons, and that compilers like to optimize the comparison using machine register sizes. C casts the operands to machine sizes: unsigned char 0x80 gets cast to 0x00000080, and signed char 0x80 gets cast to 0xFFFFFF80. Then when you compare them, they don't equate! ARGH....

Thursday, August 20, 2009

Using Bits in 8051 assembly

warning: this is a placeholder written from memory. I need to update it



Useful commands: The JB (Jump if Bit set) will jump if a bit is set. The encoding of the field is the bit offset from data memory address 0x20. If you forget this, and try encoding the bit directly, then you will actually get bit 0x20.0 + 0x20 = 0x24.0 (ie 32 bits down the line).

To declare the bit in ASM:


BSEG 0 ; offset 0 in the 0x20.0 to 2F.7 range.
BIT mybit ; declare mybit at 0x20.0
...

; useful 8-byte entry in the vector table (ie at offset 0x0003 in code space for an ISR)

CSEG AT 0x0003

JB mybit, passhop ; 3 bytes encoding
AJMP fail ; 2 bytes encoding
passhop: LJMP pass ; 3 bytes encoding = 8 bytes total



In C, you would declare the bit as:

extern bit myBit at 0x20;

How to read high resolution system time in Win32


// example of how to read the system clock.
SYSTEMTIME st;
::GetSystemTime(&st);
FILETIME ft;
::SystemTimeToFileTime(&st,&ft);
DWORD diff = ft.dwLowDateTime - lasttime;
double rate;
rate = DEF_BUF_SIZE * 1000.0 / (diff * 1e-7) ;
std::cout << " rate:" << rate << std::endl;
lasttime = ft.dwLowDateTime;

Wednesday, April 29, 2009

Memory Barriers in multi-threaded applications

Sometimes, the compiler can get in the way and break your code because it makes single-thread assumptions about your code. In addition, the microprocessors can break your code because it makes single-core assumptions. The way to fix this is use a memory barrier.

Here is a very good description of the problem of multi-threading.


Here is how to do it on a PowerPC, using the lwsync instruction.

volatile unsigned variable1 = 0;

#define barrier() __asm__ volatile (”lwsync”)

#define ITERATIONS 50000000

void *writer(volatile unsigned *variable2) {
utilBindThreadToCPU(0);
for (;;) {
variable1 = variable1 + 1;
barrier();
*variable2 = *variable2 + 1;
}
return NULL;
}

How to predeclare typedefs for self-referential typedefs

Sometimes you need to have a typedef that refers to itself through a struct member, or there is a circular reference. Here is how to predeclare the typedef so you can use it before it is fully defined. It's basically 3 parts. First declare the struct, then declare the typedef, then define the struct using the typedef.


struct fileinfo;
struct cached_block;

typedef struct fileinfo FILEINFO;
typedef struct cached_block CACHED_BLOCK;

struct fileinfo {
FILEINFO *fi_next; /* list of all files */
CACHED_BLOCK *fi_blks; /* cached blocks for this file */
/* ... */
};

struct cached_block {
int cb_lbn; /* logical block number */
CACHED_BLOCK *cb_next; /* next cached block for this file */
FILEINFO *cb_file; /* file containing this block */
/* ... */
};

Thursday, February 12, 2009

Disassembling a binary using GNU tools on a weird architecture


objdump -D Release/tinyloader.bin --target=binary --architecture=xscale




The -D option is key. You can't use -d, since you are starting with a binary file that has no sections. The -D option ignores sections and disassembled everything.

Monday, January 26, 2009

How to install a bootloader on a STR912 without CAPS or Raisonance

ST recommends CAPS (their GUI) to install the STR912. However, that requires a Raisonance JTAG adapter. You can do it with just IAR EWARM and Segger tools.

  1. Download the JLINK software from Segger.com
  2. Run "J-LINK STR9 Commander" tool (it's under Segger-> JLink ARM 3.95a -> Processor Specific Utilities).
  3. Type "?" to get a list of commands
  4. Type "erase all" to fully erase the chip.
  5. Type "setb 1" to set the boot bit to bank 1.
  6. Type "q" to quit.
  7. Now you can use the flash loader of EWARM to install the code.
You can also use the "secure" command to secure the JTAG port, but that makes debugging via JTAG impossible. :)

Adding an external file to a perl module

Let's say you want a perl module to scream "argh" on failure. You find a argh.wav file and want to bundle it with the perl pm file. The problem is loading the wav file without knowing the full path. Perl's current working directory can be any where, and the location of the wav file or module file may not be in the same location as the starting pl file. To find the starting pl file, you can use the FindBin::Bin module, but this doesn't work for modules. If you want to know the location of the module (pm) file instead, you can use the %INC hash to get it. This hash value gets set when you "use" the pm file. Once you know where the pm file is, you can use the dirname() function to get the directory name, then add the name of the wav file.

Here is an example (in a perl module called "Scream.pm"):


use File::Basename;
use Win32::Sound;

my $wavfile = dirname($INC{"Scream.pm"})."/argh.wav";
Win32::Sound::Play($wavfile);

Thursday, January 15, 2009

Tools for mocking-up C++ classes

I haven't played with this yet, but it seems to have its heart in the right place.

http://code.google.com/p/googlemock/wiki/ForDummies

Neat source of icons


I stumbled upon this cache of free icons if you follow the LGPL.


http://commons.wikimedia.org/wiki/Crystal_Clear

Don't use a virtual function in a constructor

Virtual functions should be used until an object is fully constructed. That is because the constructor builds the virtual function table in pieces. When it is constructing the base class, the derived class virtual function table is not yet constructed. So if you call a virtual function, you are calling the virtual function of the base class not the derived class. This is worse if the base class is a pure interface, ie the virtual functions are declared as pure (ie " =0;"), because you can't call a pure function -- the pointer points to NULL and your program crashes.