Strange behavior with offset / masking

advertisements

Backstory: I'm working on a toy compiler that takes some simplified assembly-like text and converts it into 32-bit instructions.

The conversion into 32-bit instructions is working correctly, but when I try to output the results, I run into some issues. Specifically, the macros I wrote to pull out the various segments seem to be mangling values in ways I can't explain.

The following loop is where I run into issues (bit manipulations are stored in macros, but I expanded them out for simpler debugging):

while(pc < num_insts)
{
   printf("full: %x | op: %x | rs: %x | rt: %x | rd: %x | imm: %x\n",
      inst_mem[pc],
      ((inst_mem[pc] >> 26) & 0x0000003F),
      ((inst_mem[pc] >> 21) & 0x0000003F),
      ((inst_mem[pc] >> 16) & 0x0000003F),
      ((inst_mem[pc] >> 11) & 0x0000F800),
      (inst_mem[pc++] & 0x0000FFFF));
}

Which prints out the following:

full: 20450008 | op: 8 | rs: 2 | rt: 5 | rd: 0 | imm: 10
full: 0 | op: 0 | rs: 0 | rt: 0 | rd: 0 | imm: 8

The correct values for those lines would be:

full: 20450008 | op: 8 | rs: 1 | rt: 4 | rd: 0 | imm: 16
full: 20240010 | op: 8 | rs: 2 | rt: 5 | rd: 0 | imm: 8

If I replace that with the simpler

while(pc < num_insts)
{
   printf("full: %x", inst_mem[pc++]);
}

then each full address is output as I would expect. This implies to me that the parsing is all working as it should, and that my macros to pull values out of the address after parsing and jacking with something they shouldn't be. I'm just not sure what that something would be.

Since inst_mem[] contains int32_t values and all shifts are less than 32, it shouldn't be an issue of undocumented shift behavior.

If anyone can provide a nudge in the right directions, I would be more than grateful. I'm running out of ideas.


The order of evalutation of function arguments doesn't have to be "first argument first". Therefore, it is very dangerous to have increments like pc++ when other function arguments use pc. Change pc++ to pc and increment pc afterwards:

while(pc < num_insts)
{
   printf("full: %x | op: %x | rs: %x | rt: %x | rd: %x | imm: %x\n",
      inst_mem[pc],
      ((inst_mem[pc] >> 26) & 0x0000003F),
      ((inst_mem[pc] >> 21) & 0x0000003F),
      ((inst_mem[pc] >> 16) & 0x0000003F),
      ((inst_mem[pc] >> 11) & 0x0000F800),
      (inst_mem[pc] & 0x0000FFFF));
   pc++;
}