|
| 1 | +#ifndef AFFINEDECODER_H |
| 2 | +#define AFFINEDECODER_H |
| 3 | + |
| 4 | +#include "gatorom.h" |
| 5 | +#include <array> |
| 6 | +/* This is a general purpose "affine decoder". It aims to |
| 7 | +make a template for a good variety of decoder bit patterns |
| 8 | +with only small code changes. There are 3 arrays used to construct it: |
| 9 | +- counts: each entry indicates how many times the stride should be repeated |
| 10 | +- col_strides: how much to increment col by each time this stride is taken |
| 11 | +- row_strides: how much to increment row by each time this stride is taken |
| 12 | +
|
| 13 | +The strides act like an affine map, the column increment and row increment are |
| 14 | +multiplied by an index vector to produce a row offset and column offset. |
| 15 | +The index vector increments based on the counts, incrementing idx_vec[0] |
| 16 | +until it reaches count[0], at which point it "carries" over to increment |
| 17 | +idx_vec[1]. As an example, suppose counts = [2, 3, 4]. The index vector would |
| 18 | +increment through: [0,0,0] [1,0,0] [0,1,0] [1,1,0] [0,2,0] [1,2,0] [0,0,1] |
| 19 | +
|
| 20 | +Combining this with the row and column strides, it's possible to represent many |
| 21 | +interleaved and non-interleaved bit-read patterns. |
| 22 | +
|
| 23 | +A simple layout: |
| 24 | +1234 |
| 25 | +5678 |
| 26 | +
|
| 27 | +would look like |
| 28 | +counts: [4, 2] |
| 29 | +col_strides: [1, 0] |
| 30 | +row_strides: [0, 1] |
| 31 | +
|
| 32 | +and would iterate as |
| 33 | +idx vector: col, row |
| 34 | +00: (0*1)+(0*0), (0*0)+(0*1) |
| 35 | +... |
| 36 | +30: (3*1)+(0*0), (3*0)+(0*1) |
| 37 | +01: (0*1)+(1*0), (0*0)+(1*1) |
| 38 | +... |
| 39 | +31: (3*1)+(1*0), (3*0)+(1*1) |
| 40 | +
|
| 41 | +
|
| 42 | +colsdownl can be represented with: |
| 43 | +initial col offset: numcols-numcols/wordsize |
| 44 | +initial row offset: 0 |
| 45 | +counts : [wordsize , numrows, numcols/wordsize] |
| 46 | +col_strides: [-numcols/wordsize, 0 , 1] |
| 47 | +row_strides: [0 , 1 , 0] |
| 48 | +
|
| 49 | +so for example with wordsize=2, numrows=4, numcols=4: |
| 50 | +1908 |
| 51 | +3b2a |
| 52 | +5d4c |
| 53 | +7f6e |
| 54 | +
|
| 55 | +so: |
| 56 | +counts: [2,4,2] |
| 57 | +col_strides: [-2,0,1] |
| 58 | +row_strides: [0,1,0] |
| 59 | +idx: col, row |
| 60 | +000: 2, 0 |
| 61 | +100: 2-2+0+0, 0+0+0 |
| 62 | +010: 2+0+0+0, 0+1+0 |
| 63 | +110: 2-2+0+0, 0+1+0 |
| 64 | +020: 2+0+0+0, 0+2+0 |
| 65 | +120: 0,2 |
| 66 | +030: 2,3 |
| 67 | +130: 0,3 |
| 68 | +001: 2+0+0+1, 0+0+0 |
| 69 | +101: 2-2+0+1, 0+0+0 |
| 70 | +... |
| 71 | +
|
| 72 | +*/ |
| 73 | +template <size_t N> class AffineDecoder : public GatoDecoder { |
| 74 | +private: |
| 75 | + std::array<unsigned int, N> counts; |
| 76 | + std::array<int, N> row_strides; |
| 77 | + std::array<int, N> col_strides; |
| 78 | + int row_start; |
| 79 | + int col_start; |
| 80 | + |
| 81 | +public: |
| 82 | + AffineDecoder(std::array<unsigned int, N> counts, |
| 83 | + std::array<int, N> row_strides, std::array<int, N> col_strides, |
| 84 | + int row_start, int col_start); |
| 85 | + void decode(GatoROM *gr); |
| 86 | + void inc_idx_counts(std::array<unsigned int, N> &idx_counts); |
| 87 | + int get_row_offset(std::array<unsigned int, N> &idx_counts); |
| 88 | + int get_col_offset(std::array<unsigned int, N> &idx_counts); |
| 89 | +}; |
| 90 | + |
| 91 | +template <size_t N> |
| 92 | +AffineDecoder<N>::AffineDecoder(std::array<unsigned int, N> counts, |
| 93 | + std::array<int, N> row_strides, |
| 94 | + std::array<int, N> col_strides, int row_start, |
| 95 | + int col_start) { |
| 96 | + |
| 97 | + this->row_start = row_start; |
| 98 | + this->col_start = col_start; |
| 99 | + this->name = "Raw Affine Decoder"; |
| 100 | + this->counts = counts; |
| 101 | + this->row_strides = row_strides; |
| 102 | + this->col_strides = col_strides; |
| 103 | +} |
| 104 | + |
| 105 | +template <size_t N> |
| 106 | +int AffineDecoder<N>::get_col_offset(std::array<unsigned int, N> &idx_counts) { |
| 107 | + int col_offset = this->col_start; |
| 108 | + for (size_t i = 0; i < N; i++) { |
| 109 | + col_offset += idx_counts[i] * this->col_strides[i]; |
| 110 | + } |
| 111 | + return col_offset; |
| 112 | +} |
| 113 | + |
| 114 | +template <size_t N> |
| 115 | +int AffineDecoder<N>::get_row_offset(std::array<unsigned int, N> &idx_counts) { |
| 116 | + int row_offset = this->row_start; |
| 117 | + for (size_t i = 0; i < N; i++) { |
| 118 | + row_offset += idx_counts[i] * this->row_strides[i]; |
| 119 | + } |
| 120 | + return row_offset; |
| 121 | +} |
| 122 | + |
| 123 | +template <size_t N> |
| 124 | +void AffineDecoder<N>::inc_idx_counts(std::array<unsigned int, N> &idx_counts) { |
| 125 | + size_t cur_idx = 0; |
| 126 | + idx_counts[cur_idx]++; |
| 127 | + cur_idx++; |
| 128 | + while (cur_idx < N && |
| 129 | + (idx_counts[cur_idx - 1] == this->counts[cur_idx - 1])) { |
| 130 | + idx_counts[cur_idx - 1] = 0; |
| 131 | + idx_counts[cur_idx]++; |
| 132 | + cur_idx++; |
| 133 | + } |
| 134 | +}; |
| 135 | + |
| 136 | +template <size_t N> void AffineDecoder<N>::decode(GatoROM *gr) { |
| 137 | + |
| 138 | + uint32_t adr = 0; |
| 139 | + QByteArray ba, bad; // data and damage |
| 140 | + |
| 141 | + int wordsize = gr->wordsize; |
| 142 | + std::array<unsigned int, N> idx_counts = {0}; |
| 143 | + gr->eval(); |
| 144 | + |
| 145 | + unsigned int num_bits = gr->outputrows * gr->outputcols; |
| 146 | + if (num_bits % wordsize != 0) { |
| 147 | + return; |
| 148 | + } |
| 149 | + // we'll go bit-by-bit, grouping by words |
| 150 | + unsigned int num_words = num_bits / wordsize; |
| 151 | + for (int word = 0; word < num_words; word++) { |
| 152 | + uint32_t w = 0, wd = 0; |
| 153 | + |
| 154 | + for (int bit = wordsize - 1; bit >= 0; bit--) { |
| 155 | + unsigned int row = this->get_row_offset(idx_counts); |
| 156 | + unsigned int col = this->get_col_offset(idx_counts); |
| 157 | + this->inc_idx_counts(idx_counts); |
| 158 | + GatoBit *B = gr->outputbit(row, col); |
| 159 | + assert(B); |
| 160 | + |
| 161 | + B->adr = adr; |
| 162 | + B->mask = 1 << bit; |
| 163 | + if (B->getVal()) |
| 164 | + w |= B->mask; |
| 165 | + if (B->ambiguous) |
| 166 | + wd |= B->mask; |
| 167 | + } |
| 168 | + |
| 169 | + // This is implicitly little endian |
| 170 | + for (int bitcount = wordsize; bitcount > 0; bitcount -= 8) { |
| 171 | + ba.append(w & 0xFF); |
| 172 | + w = w >> 8; |
| 173 | + bad.append(wd & 0xff); |
| 174 | + wd = wd >> 8; |
| 175 | + |
| 176 | + adr++; |
| 177 | + } |
| 178 | + } |
| 179 | + gr->decoded = ba; |
| 180 | + gr->decodedDamage = bad; |
| 181 | +} |
| 182 | +#endif // AFFINEDECODER_H |
0 commit comments