summaryrefslogtreecommitdiff
path: root/gp2x/test/load_imm_test.c
blob: b850d560ac5d31889e29fb69a9ac5581f12f5955 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <stdio.h>

typedef unsigned int u32;

u32 arm_imm_find_nonzero(u32 imm, u32 start_bit)
{
  u32 i;

  for(i = start_bit; i < 32; i += 2)
  {
    if((imm >> i) & 0x03)
      break;
  }

  return i;
}

u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations)
{
  u32 store_count = 0;
  u32 left_shift = 0;

  // Otherwise it'll return 0 things to store because it'll never
  // find anything.
  if(imm == 0)
  {
    rotations[0] = 0;
    stores[0] = 0;
    return 1;
  }

  // Find chunks of non-zero data at 2 bit alignments.
  while(1)
  {
    left_shift = arm_imm_find_nonzero(imm, left_shift);

    if(left_shift == 32)
    {
      // We've hit the end of the useful data.
      return store_count;
    }

    // Hit the end, it might wrap back around to the beginning.
    if(left_shift >= 24)
    {
      // Make a mask for the residual bits. IE, if we have
      // 5 bits of data at the end we can wrap around to 3
      // bits of data in the beginning. Thus the first
      // thing, after being shifted left, has to be less
      // than 111b, 0x7, or (1 << 3) - 1.
      u32 top_bits = 32 - left_shift;
      u32 residual_bits = 8 - top_bits;
      u32 residual_mask = (1 << residual_bits) - 1;

      if((store_count > 1) && (left_shift > 24) &&
       ((stores[0] << (32 - rotations[0])) < residual_mask))
      {
        // Then we can throw out the last bit and tack it on
        // to the first bit.
        u32 initial_bits = rotations[0];
        stores[0] = (stores[0] << (top_bits + (32 - rotations[0]))) |
         ((imm >> left_shift) & 0xFF);
        rotations[0] = top_bits;

        return store_count;
      }
      else
      {
        // There's nothing to wrap over to in the beginning
        stores[store_count] = (imm >> left_shift) & 0xFF;
        rotations[store_count] = (32 - left_shift) & 0x1F;
        return store_count + 1;
      }
      break;
    }

    stores[store_count] = (imm >> left_shift) & 0xFF;
    rotations[store_count] = (32 - left_shift) & 0x1F;

    store_count++;
    left_shift += 8;
  }
}

#define ror(value, shift)                                                     \
  ((value) >> shift) | ((value) << (32 - shift))                              \

u32 arm_assemble_imm_32bit(u32 *stores, u32 *rotations, u32 store_count)
{
  u32 n = ror(stores[0], rotations[0]);
  u32 i;
  printf("%x : %x\n", stores[0], rotations[0]);

  for(i = 1; i < store_count; i++)
  {
    printf("%x : %x\n", stores[i], rotations[i]);
    n |= ror(stores[i], rotations[i]);
  }

  return n;
}


int main(int argc, char *argv[])
{
  u32 n = 0;
  u32 stores[4];
  u32 rotations[4];
  u32 store_count;
  u32 n2;

  if(argc != 1)
  {
    n = strtoul(argv[1], NULL, 16);
    store_count = arm_disect_imm_32bit(n, stores, rotations);
    n2 = arm_assemble_imm_32bit(stores, rotations, store_count);
    printf("%08x -> %08x (%d stores)\n", n, n2, store_count);
    return 0;
  }

  do
  {
    store_count = arm_disect_imm_32bit(n, stores, rotations);
    n2 = arm_assemble_imm_32bit(stores, rotations, store_count);
    if(n != n2)
    {
      printf("Failure: %08x -/-> %08x\n", n, n2);
      return -1;
    }
    n++;
  } while(n != 0);

  printf("Done!\n");
  return 0;
}