├── LICENSE ├── README.rst ├── doc ├── bit-isa.rst └── bit.rst ├── meson.build ├── meson_options.txt └── src ├── bitdis.c ├── bitspl.c ├── coda-fwinfo.c ├── iset.h ├── regs.h ├── reorder.c └── reorder.h /LICENSE: -------------------------------------------------------------------------------- 1 | Permission to use, copy, modify, and/or distribute this software for any 2 | purpose with or without fee is hereby granted. 3 | 4 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 5 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 6 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 7 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 8 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 9 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 10 | PERFORMANCE OF THIS SOFTWARE. 11 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | CODA bits 2 | ========= 3 | 4 | This repository contains bits and pieces of information about the CODA series 5 | of video processing units found in i.MX application processors. There is a 6 | `firmware identification tool`_, a `firmware splitter`_, a rudimentary 7 | disassembler_, and some unfinished documentation: 8 | 9 | * `BIT processor overview`_ 10 | * `Instruction set description`_ 11 | 12 | .. _`BIT processor overview`: doc/bit.rst 13 | .. _`Instruction set description`: doc/bit-isa.rst 14 | 15 | Setup and build 16 | --------------- 17 | 18 | To configure the build system and build the tools, follow the standard Meson_ 19 | build procedure:: 20 | 21 | $ meson build 22 | $ cd build 23 | $ ninja 24 | 25 | .. _Meson: http://mesonbuild.com 26 | 27 | Firmware identification tool 28 | ---------------------------- 29 | 30 | The coda-fwinfo tool matches a machine code template against the firmware file 31 | to determine the product id, firmware version number, and code revision 32 | (CODA960 only) as returned by the FIRMWARE_VERNUM command if run on the 33 | hardware:: 34 | 35 | $ coda-fwinfo vpu_fw_imx6q.bin 36 | Firmware in host memory order 37 | Product ID: 0xf020, CODA960 (i.MX6) 38 | Version Number: 0x3101 (3.1.1) 39 | Code Revision: 46072 40 | 41 | Firmware splitter 42 | ----------------- 43 | 44 | The bitspl tool looks for reset vector signatures and splits the firmware into 45 | individual components at those boundaries:: 46 | 47 | $ bitspl vpu_fw_imx6q.bin 48 | vector at 0x00000, writing 00000.bin 49 | vector at 0x05000, writing 05000.bin 50 | [...] 51 | 52 | For example, the i.MX6Q firmware version 3.1.1 splits into the following parts. 53 | Their function can be determined from the code at address 0x01c4, which checks 54 | the RUN_COD_STD and RUN_AUX_STD parameters: 55 | 56 | ========= ================ 57 | Part Function 58 | ========= ================ 59 | 00000.bin h.264 AVC decode 60 | 05000.bin 61 | 0a000.bin h.264 MVC decode 62 | 0f000.bin VC1 decode 63 | 13000.bin MPEG-2 decode 64 | 16000.bin MPEG-4 decode 65 | 1a000.bin DivX 3 decode 66 | 1d000.bin RV decode 67 | 1f800.bin AVS decode 68 | 22800.bin MJPEG decode 69 | 24800.bin Theora decode 70 | 28800.bin VP6 decode 71 | 2c800.bin VP8 decode 72 | 31800.bin h.264 AVC encode 73 | 35000.bin MPEG-4 encode 74 | 38000.bin 75 | 3a000.bin h.264 MVC encode 76 | ========= ================ 77 | 78 | The i.MX51 firmware version 1.4.50 splits into the following parts. 79 | Their function can be determined from the code at address 0x010a, which checks 80 | the RUN_COD_STD parameter: 81 | 82 | ========= ================ 83 | Part Function 84 | ========= ================ 85 | 00000.bin h.264 AVC decode 86 | 04800.bin 87 | 09000.bin VC1 decode 88 | 0d000.bin MPEG-2 decode 89 | 10000.bin MPEG-4 decode 90 | 14800.bin 91 | 17800.bin RV decode 92 | 19800.bin MJPEG decode 93 | 1c000.bin h.264 encode 94 | 1e000.bin 95 | 1f000.bin MPEG-4 encode 96 | 22000.bin MJPEG encode 97 | ========= ================ 98 | 99 | Note that the output of bitspl is always in BIT processor order, even if the 100 | input is in host memory order:: 101 | 102 | $ coda-fwinfo 00000.bin 103 | Firmware in BIT processor memory order 104 | [...] 105 | 106 | The parts can be put back together using cat:: 107 | 108 | $ cat ?????.bin > vpu_fw_imx6q.bin 109 | 110 | Disassembler 111 | ------------ 112 | 113 | The bitdis tool is a rudimentary disassembler that translates the firmware 114 | machine code into made up mnemonics, as far as the instruction set is 115 | understood:: 116 | 117 | $ bitdis 00000.bin 118 | Firmware in host memory order 119 | Disassembly of 00000.bin: 120 | 121 | 0000: e40e 0020 jump $0, 0x40 122 | [...] 123 | 124 | Firmware download 125 | ----------------- 126 | 127 | The CODA firmware binaries can be downloaded as part of the i.MX firmware 128 | package provided by NXP. Here is how to download and extract a few versions of 129 | the CODA VPU firmware files:: 130 | 131 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-3.0.35-4.0.0.bin 132 | $ dd if=firmware-imx-3.0.35-4.0.0.bin bs=15586 skip=1 | tar xj 133 | 134 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-3.5.7-1.0.0.bin 135 | $ dd if=firmware-imx-3.5.7-1.0.0.bin bs=15584 skip=1 | tar xj 136 | 137 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-3.10.17-1.0.0.bin 138 | $ dd if=firmware-imx-3.10.17-1.0.0.bin bs=28056 skip=1 | tar xj 139 | 140 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-3.14.28-1.0.0.bin 141 | $ dd if=firmware-imx-3.14.28-1.0.0.bin bs=33936 skip=1 | tar xj 142 | 143 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-5.0.bin 144 | $ dd if=firmware-imx-5.0.bin bs=34172 skip=1 | tar xj 145 | 146 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-5.2.bin 147 | $ dd if=firmware-imx-5.2.bin bs=34172 skip=1 | tar xj 148 | 149 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-5.3.bin 150 | $ dd if=firmware-imx-5.3.bin bs=34479 skip=1 | tar xj 151 | 152 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-5.4.bin 153 | $ dd if=firmware-imx-5.4.bin bs=34087 skip=1 | tar xj 154 | 155 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-6.0.bin 156 | $ dd if=firmware-imx-6.0.bin bs=36566 skip=1 | tar xj 157 | 158 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.1.bin 159 | $ dd if=firmware-imx-7.1.bin bs=36909 skip=1 | tar xj 160 | 161 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.2.bin 162 | $ dd if=firmware-imx-7.2.bin bs=36909 skip=1 | tar xj 163 | 164 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.4.bin 165 | $ dd if=firmware-imx-7.4.bin bs=36909 skip=1 | tar xj 166 | 167 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.5.bin 168 | $ dd if=firmware-imx-7.5.bin bs=37083 skip=1 | tar xj 169 | 170 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.6.bin 171 | $ dd if=firmware-imx-7.6.bin bs=37623 skip=1 | tar xj 172 | 173 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.7.bin 174 | $ dd if=firmware-imx-7.7.bin bs=37622 skip=1 | tar xj 175 | 176 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.8.bin 177 | $ dd if=firmware-imx-7.8.bin bs=38868 skip=1 | tar xj 178 | 179 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-7.9.bin 180 | $ dd if=firmware-imx-7.9.bin bs=38868 skip=1 | tar xj 181 | 182 | $ wget http://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.0.bin 183 | $ dd if=firmware-imx-8.0.bin bs=37180 skip=1 | tar xj 184 | 185 | $ https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.1.bin 186 | $ dd if=firmware-imx-8.1.bin bs=37164 skip=1 | tar xj 187 | 188 | $ https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.2.bin 189 | $ dd if=firmware-imx-8.2.bin bs=37775 skip=1 | tar xj 190 | 191 | $ https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.3.bin 192 | $ dd if=firmware-imx-8.3.bin bs=37908 skip=1 | tar xj 193 | 194 | These all contain the same firmware versions for i.MX 27 to i.MX53 in the 195 | firmware/vpu subdirectory: 196 | 197 | ========== ======== ==================== ======= 198 | SoC CODA Firmware Version 199 | ========== ======== ==================== ======= 200 | i.MX27 TO1 CodaDx6 vpu_fw_imx27_TO1.bin 1.7.1 201 | i.MX27 TO2 CodaDx6 vpu_fw_imx27_TO2.bin 2.2.2 202 | i.MX51 CodaHx14 vpu_fw_imx51.bin 1.4.50 203 | i.MX53 CODA7541 vpu_fw_imx53.bin 1.4.50 204 | ========== ======== ==================== ======= 205 | 206 | The firmware versions for i.MX6Q/D and i.MX6DL/S differ between the packages: 207 | 208 | ========= ======= ================ 209 | SoC CODA Firmware 210 | ========= ======= ================ 211 | i.MX6Q/D CODA960 vpu_fw_imx6q.bin 212 | i.MX6DL/S CODA960 vpu_fw_imx6d.bin 213 | ========= ======= ================ 214 | 215 | =============== ======================= 216 | Package version Firmware version 217 | =============== ======================= 218 | 3.0.38-4.0.0 2.1.9 r36350 219 | 3.5.7-1.0.0 2.3.10 r40778 220 | 3.10.17-1.0.0 3.1.1 r46056 221 | 3.14.28-1.0.0 3.1.1 r46063 222 | 5.0 3.1.1 r46067 223 | 5.2-5.3 3.1.1 r46070 224 | 5.4 3.1.1 r46072 225 | 6.0-7.1 3.1.1 r46075 (0xb3fb) 226 | 7.2-8.3 3.1.1 r570363 (0x8b3fb) 227 | =============== ======================= 228 | -------------------------------------------------------------------------------- /doc/bit-isa.rst: -------------------------------------------------------------------------------- 1 | Disclaimer 2 | ---------- 3 | 4 | The following information has been obtained by staring at the CODA firmware 5 | files distributed by Freescale, for a really long time, until patterns emerged. 6 | None of this is validated, anything could be wrong. Read this document not as 7 | a statement of fact, but as a snapshot of the author's understanding of the BIT 8 | processor instruction set. The mnemonics are completely made up. Code addresses 9 | and mailbox register offsets are in units of 16-bit words, unless otherwise 10 | noted. 11 | 12 | The possibility to read the program counter in a running system helped to 13 | identify a tight loop where the BIT processor spins waiting for the host to 14 | issue a new command by writing to the RUN_COMMAND mailbox register, helpfully 15 | demonstrating a load into an accumulator register from a mailbox register and a 16 | conditional jump. Further, the known 32-bit return value of the FIRMWARE_GET 17 | command allowed to identify the location where the firmware moves two known 18 | immediate 16-bit values into the low bits of both accumulator registers, 19 | combines them with a left shift and an or instruction, and stores the result 20 | into a mailbox register as return value. The rest followed from there. 21 | 22 | Instruction set encoding overview 23 | --------------------------------- 24 | 25 | Instructions consist of either a single 16-bit instruction word, or for some 26 | operations, of an instruction word followed by a 16-bit parameter word. 27 | 28 | +------------------------------------+--------------+--------------------------------+ 29 | | Instruction word |Parameter word| Description | 30 | +=======+======+=====+=+=+==+==+==+==+==============+================================+ 31 | |15 - 12|11 - 8|7 - 6|5|4|3 - 2| 1| 0| 15 - 0 | | 32 | +-------+------+-----+-+-+-----+--+--+--------------+--------------------------------+ 33 | | 1010 | op | operand | A| -- | `immediate 7-bit operations`_ | 34 | +-------+------+-----+------------+--+--------------+--------------------------------+ 35 | | 1110 | 0000 | 00 | op | A| operand | `immediate 16-bit operations`_ | 36 | +-------+------+-----+---------+--+--+--------------+--------------------------------+ 37 | | 1110 | 0000 | 01 | op | B| A| -- | `binary operations`_ | 38 | +-------+------+-----+---+-----+--+--+--------------+--------------------------------+ 39 | | 1110 | 0000 | 1100 | 00 | S| A| -- | `mailbox loads and stores`_ | 40 | +-------+------+---------+-----+--+--+--------------+--------------------------------+ 41 | | 1110 | 0001 | 1001 | 0000 | -- | `no-op`_ | 42 | +-------+------+-----+-+-+-----+--+--+--------------+--------------------------------+ 43 | | 1110 | 0100 | 00 |0|L| cond | 0| address | `absolute jumps and calls`_ | 44 | +-------+------+-----+-+-+--------+--+--------------+--------------------------------+ 45 | | 1110 | 0100 | 0010 | cond | 0| -- | `returns`_ | 46 | +-------+------+---------+--------+--+--------------+--------------------------------+ 47 | | 1111 | offset | cond | 0| -- | `relative jumps`_ | 48 | +-------+----------------+--------+--+--------------+--------------------------------+ 49 | 50 | Instructions that operate on one or both of the two accumulator registers 51 | contain accumulator register selection bits *A*, *B*. The *S* bit determines 52 | whether a memory access is a store, and the *L* bit in the branch instructions 53 | determines whether an absolute jump is a call that stores the next program 54 | counter address for a later return. 55 | 56 | Immediate 7-bit Operations 57 | -------------------------- 58 | 59 | Arithmetic and bitwise operations with an accumulator register *A* and a 7-bit 60 | immediate value *operand*. 61 | 62 | +----------------------------+----------+----------------+ 63 | | Instruction word | Mnemonic | Description | 64 | +=======+======+=====+=====+=+==========+================+ 65 | |15 - 12|11 - 8|7 - 4|3 - 1|0| | | 66 | +-------+------+-----+-----+-+----------+----------------+ 67 | | 1010 | 0000 | operand |A|``add.b`` | A += operand | 68 | +-------+------+-----------+-+----------+----------------+ 69 | | 1010 | 0001 | operand |A|``sub.b`` | A -= operand | 70 | +-------+------+-----------+-+----------+----------------+ 71 | | 1010 | 0010 | operand |A|``mv.b`` | A = operand | 72 | +-------+------+-----------+-+----------+----------------+ 73 | | 1010 | 1000 | operand |A|``and.b`` | A &= operand | 74 | +-------+------+-----------+-+----------+----------------+ 75 | | 1010 | 1110 | operand |A|``lsl`` | A <<= operand | 76 | +-------+------+-----------+-+----------+----------------+ 77 | | 1010 | 1111 | operand |A|``lsr`` | A >>= operand | 78 | +-------+------+-----------+-+----------+----------------+ 79 | 80 | Immediate 16-bit operations 81 | --------------------------- 82 | 83 | Arithmetic and bitwise operations with an accumulator register *A* and a 16-bit 84 | immediate value *operand*. The instruction word is followed by a parameter word 85 | containing the 16-bit immediate operand. 86 | 87 | +-----------------------------+--------------+---------+------------------+ 88 | | Instruction word |Parameter word|Mnemonic | Description | 89 | +=======+======+======+=====+=+==============+=========+==================+ 90 | |15 - 12|11 - 8| 7 - 4|3 - 1|0| 15 - 0 | | | 91 | +-------+------+------+-----+-+--------------+---------+------------------+ 92 | | 1110 | 0000 | 0000 | 001 |A| operand |``sub.h``| A -= operand | 93 | +-------+------+------+-----+-+--------------+---------+------------------+ 94 | | 1110 | 0000 | 0000 | 010 |A| operand |``mv.h`` | A = operand | 95 | +-------+------+------+-----+-+--------------+---------+------------------+ 96 | | 1110 | 0000 | 0000 | 100 |A| operand |``and.h``| A &= operand | 97 | +-------+------+------+-----+-+--------------+---------+------------------+ 98 | | 1110 | 0000 | 0000 | 101 |A| operand |``or.h`` | A |= operand | 99 | +-------+------+------+-----+-+--------------+---------+------------------+ 100 | 101 | Binary operations 102 | ----------------- 103 | 104 | Arithmetic and bitwise operations with two accumulator registers *A* and *B* 105 | 106 | +-------------------------------+--------------+---------+--------------+ 107 | | Instruction word |Parameter word|Mnemonic | Description | 108 | +=======+======+======+=====+=+=+==============+=========+==============+ 109 | |15 - 12|11 - 8| 7 - 4|3 - 2|1|0| 15 - 0 | | | 110 | +-------+------+------+-----+-+-+--------------+---------+--------------+ 111 | | 1110 | 0000 | 0100 | 00 |B|A| operand |``add.w``| A += B | 112 | +-------+------+------+-----+-+-+--------------+---------+--------------+ 113 | | 1110 | 0000 | 0101 | 00 |B|A| operand |``and.w``| A &= B | 114 | +-------+------+------+-----+-+-+--------------+---------+--------------+ 115 | | 1110 | 0000 | 0101 | 01 |B|A| operand |``or.w`` | A |= B | 116 | +-------+------+------+-----+-+-+--------------+---------+--------------+ 117 | 118 | Peripheral Loads and Stores 119 | --------------------------- 120 | Loads of 32-bit values from an *address* on the internal register bus into 121 | accumulator register *A* and stores of 32-bit values from accumulator register 122 | *A* to an *address* on the internal register bus. The instruction word is 123 | followed by a parameter word containing the register address. 124 | 125 | +-----------------------------+--------------+--------+------------------+ 126 | | Instruction word |Parameter word|Mnemonic| Description | 127 | +=======+======+======+=====+=+==============+========+==================+ 128 | |15 - 12|11 - 8| 7 - 4|3 - 1|0| 15 - 0 | | | 129 | +-------+------+------+-----+-+--------------+--------+------------------+ 130 | | 1110 | 0000 | 1100 | 000 |A| address |``ld.w``| A = reg[address] | 131 | +-------+------+------+-----+-+--------------+--------+------------------+ 132 | | 1110 | 0000 | 1100 | 001 |A| address |``st.w``| reg[address] = A | 133 | +-------+------+------+-----+-+--------------+--------+------------------+ 134 | 135 | The internal register bus is connected to the host interface (mailbox) register 136 | block and to the registers of the peripheral acceleration units. 137 | 138 | No-op 139 | ----- 140 | 141 | +----------------------------+----------+-------------+ 142 | | Instruction word | Mnemonic | Description | 143 | +=======+======+======+======+==========+=============+ 144 | |15 - 12|11 - 8| 7 - 4| 3 - 0| | | 145 | +-------+------+------+------+----------+-------------+ 146 | | 1110 | 0001 | 1001 | 0000 | ``nop`` | -- | 147 | +-------+------+------+------+----------+-------------+ 148 | 149 | Absolute jumps and calls 150 | ------------------------ 151 | 152 | These instructions move the program counter *PC* to an absolute *address*, if a 153 | condition is met. ``call`` instructions additionally store *PC + 1* as return 154 | address *RA* before *PC* is changed. The instruction word is followed by a 155 | parameter word containing the absolute address. 156 | 157 | +----------------------------+--------------+----------+---------------------------------+ 158 | | Instruction word |Parameter word| Mnemonic | Description | 159 | +=======+======+======+======+==============+==========+=================================+ 160 | |15 - 12|11 - 8| 7 - 4| 3 - 0| 15 - 0 | | | 161 | +-------+------+------+------+--------------+----------+---------------------------------+ 162 | | 1110 | 0100 | 0000 | 0010 | address |``jumple``| if (le) PC = address | 163 | +-------+------+------+------+--------------+----------+---------------------------------+ 164 | | 1110 | 0100 | 0000 | 1000 | address |``jumpnz``| if (!z) PC = address | 165 | +-------+------+------+------+--------------+----------+---------------------------------+ 166 | | 1110 | 0100 | 0000 | 1010 | address |``jumpz`` | if (z) PC = address | 167 | +-------+------+------+------+--------------+----------+---------------------------------+ 168 | | 1110 | 0100 | 0000 | 1110 | address |``jump`` | PC = address | 169 | +-------+------+------+------+--------------+----------+---------------------------------+ 170 | | 1110 | 0100 | 0000 | 0010 | address |``callle``| if (le) RA = PC+1, PC = address | 171 | +-------+------+------+------+--------------+----------+---------------------------------+ 172 | | 1110 | 0100 | 0000 | 1000 | address |``callnz``| if (!z) RA = PC+1, PC = address | 173 | +-------+------+------+------+--------------+----------+---------------------------------+ 174 | | 1110 | 0100 | 0000 | 1010 | address |``callz`` | if (z) RA = PC+1, PC = address | 175 | +-------+------+------+------+--------------+----------+---------------------------------+ 176 | | 1110 | 0100 | 0000 | 1110 | address |``call`` | RA = PC+1, PC = address | 177 | +-------+------+------+------+--------------+----------+---------------------------------+ 178 | 179 | Returns 180 | ------- 181 | 182 | Return instructions move the program counter to the return address *RA* stored 183 | by the last ``call`` instruction, if a condition is met. 184 | 185 | +----------------------------+----------+-----------------+ 186 | | Instruction word | Mnemonic | Description | 187 | +=======+======+======+======+==========+=================+ 188 | |15 - 12|11 - 8| 7 - 4| 3 - 0| | | 189 | +-------+------+------+------+----------+-----------------+ 190 | | 1110 | 0100 | 0010 | 0010 |``retle`` | if (le) PC = RA | 191 | +-------+------+------+------+----------+-----------------+ 192 | | 1110 | 0100 | 0010 | 1000 |``retnz`` | if (!z) PC = RA | 193 | +-------+------+------+------+----------+-----------------+ 194 | | 1110 | 0100 | 0010 | 1010 |``retz`` | if (z) PC = RA | 195 | +-------+------+------+------+----------+-----------------+ 196 | | 1110 | 0100 | 0010 | 1110 |``ret`` | PC = RA | 197 | +-------+------+------+------+----------+-----------------+ 198 | 199 | Relative jumps 200 | -------------- 201 | 202 | These instructions move the program counter *PC* relative to its current value, 203 | by a signed 8-bit *offset*, if a condition is met. 204 | 205 | +----------------------------+--------+----------------------+ 206 | | Instruction word |Mnemonic| Description | 207 | +=======+======+======+======+========+======================+ 208 | |15 - 12|11 - 8| 7 - 4| 3 - 0| | | 209 | +-------+------+------+------+--------+----------------------+ 210 | | 1111 | offset | 0010 |``jle`` | if (le) PC += offset | 211 | +-------+-------------+------+--------+----------------------+ 212 | | 1111 | offset | 1000 |``jnz`` | if (!z) PC += offset | 213 | +-------+-------------+------+--------+----------------------+ 214 | | 1111 | offset | 1010 |``jz`` | if (z) PC += offset | 215 | +-------+-------------+------+--------+----------------------+ 216 | | 1111 | offset | 1110 |``j`` | PC += offset | 217 | +-------+-------------+------+--------+----------------------+ 218 | -------------------------------------------------------------------------------- /doc/bit.rst: -------------------------------------------------------------------------------- 1 | BIT processor overview 2 | ====================== 3 | 4 | The CODA VPUs contain an embedded programmable 16-bit DSP processor called 5 | BIT processor. According to a CodaDx6 Datasheet that was once freely 6 | downloadable from the `Chips&Media web site`_, the BIT processor contains 7 | separate program memory SRAM and data memory SRAM. 8 | 9 | .. _`Chips&Media web site`: http://www.chipsnmedia.com 10 | 11 | Instructions can be written directly into the boot code region (lower 4 KiB) of 12 | the program memory while the BIT processor is not running, by storing address 13 | and value into a special register in the host interface register region from 14 | the host. 15 | 16 | BIT processor units 17 | ------------------- 18 | 19 | The BIT processor core consists of these units that are directly involved 20 | in execution of the firmware code in program memory: 21 | 22 | +-----+------------------------------------------------------------------------+ 23 | | Unit| Description | 24 | +=====+========================================================================+ 25 | | PFU | The prefetch unit loads instructions from program memory. It contains | 26 | | | the program counter *PC*, which is controlled with the ``jump``, | 27 | | | ``call``, ``ret``, and ``j`` instructions. | 28 | +-----+------------------------------------------------------------------------+ 29 | | CTU | The control unit contains the instruction decoder. | 30 | +-----+------------------------------------------------------------------------+ 31 | | AGU | The address generation unit contains 8 16-bit address registers and an | 32 | | | arithmetic unit for the data memory. | 33 | +-----+------------------------------------------------------------------------+ 34 | | ALU | The arithmetic logic unit operates on two 36-bit accumulator | 35 | | | registers. It handles arithmetic and logic operations such as ``add``, | 36 | | | ``sub``, ``mv``, ``and``, ``or``, ``lsl``, and ``lsr`` instructions. | 37 | +-----+------------------------------------------------------------------------+ 38 | | MPU | The multiply unit operates on two 16-bit 2's complement inputs, | 39 | | | returning the product in a 32-bit value. | 40 | +-----+------------------------------------------------------------------------+ 41 | | PCU | The peripheral control unit is connected to the | 42 | | | `internal peripheral bus`_ and handles loads and stores to the host | 43 | | | interface register block and to the hardware accelerator unit | 44 | | | registers. It handles the 32-bit ``ld.w`` and ``st.w`` instructions. | 45 | +-----+------------------------------------------------------------------------+ 46 | | MCU | The memory control unit connects to the data memory. | 47 | +-----+------------------------------------------------------------------------+ 48 | 49 | The BIT processor further contains a hardware stack with 16 dedicated stack 50 | registers, which probably handles the call stack for ``call`` and ``ret`` 51 | instructions and it has the ability to switch context on interrupts. 52 | 53 | There is a bitstream read/write unit (GBU) that accelerates bitstream 54 | (un)packing operations, supposedly as part of the core. 55 | 56 | Internal Peripheral Bus 57 | ----------------------- 58 | 59 | The internal peripheral bus (IPB) connects the peripheral control unit to the 60 | following register blocks: 61 | 62 | +------+-----------------------------------------------------------------------+ 63 | | HOST | The host interface (mailbox) register block is accessible from the | 64 | | | host via the APB bus. | 65 | +------+-----------------------------------------------------------------------+ 66 | | MMU | The MMU interface connects to the AXI bus and provides a DMA | 67 | | | controller for transfers between program/data memory and external | 68 | | | SDRAM. | 69 | +------+-----------------------------------------------------------------------+ 70 | | MVP | Motion vector prediction and reconstruction unit | 71 | +------+-----------------------------------------------------------------------+ 72 | | TC | The transform and coefficient management block handles entropy | 73 | | | encoding/decoding and interfaces with the video codec transform | 74 | | | coefficient buffers. | 75 | +------+-----------------------------------------------------------------------+ 76 | | NB | Neighboring macroblock information unit for h.264 and MPEG4. | 77 | +------+-----------------------------------------------------------------------+ 78 | | NAL | The NAL accelerator accelerates parsing and packing of h.264 Annex B | 79 | | | NAL streams. | 80 | +------+-----------------------------------------------------------------------+ 81 | 82 | The IPB is also connected to the host APB via a bridge. Its address bus is 83 | 12-bit wide and supports 32-bit word access only. The least significant two 84 | bits of the address are ignored and should be zero. 85 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: 0BSD 2 | 3 | project('coda-bits', 'c', 4 | version : '0.1', 5 | license : '0BSD') 6 | 7 | add_global_arguments('-Wall', language : 'c') 8 | 9 | bitdis_sources = [ 10 | 'src/bitdis.c', 11 | 'src/iset.h', 12 | 'src/regs.h', 13 | 'src/reorder.c', 14 | 'src/reorder.h' 15 | ] 16 | executable('bitdis', bitdis_sources, install : true) 17 | 18 | bitspl_sources = [ 19 | 'src/bitspl.c', 20 | 'src/reorder.c', 21 | 'src/reorder.h' 22 | ] 23 | executable('bitspl', bitspl_sources, install : true) 24 | 25 | coda_fwinfo_sources = [ 26 | 'src/coda-fwinfo.c', 27 | 'src/reorder.c', 28 | 'src/reorder.h' 29 | ] 30 | executable('coda-fwinfo', coda_fwinfo_sources, install : true) 31 | 32 | codabits_docs = [ 33 | 'README.rst', 34 | 'doc/bit-isa.rst', 35 | 'doc/bit.rst' 36 | ] 37 | if get_option('docs') 38 | install_data(codabits_docs, install_dir: 'share/doc/coda-bits') 39 | endif 40 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: 0BSD 2 | 3 | option('docs', 4 | type: 'boolean', 5 | value: false, 6 | description: 'Install documentation') 7 | -------------------------------------------------------------------------------- /src/bitdis.c: -------------------------------------------------------------------------------- 1 | /* CODA BIT processor disassembler 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "iset.h" 12 | #include "regs.h" 13 | #include "reorder.h" 14 | 15 | const char *find_reg_name(uint16_t addr) 16 | { 17 | static char reg_name[22]; 18 | int i; 19 | 20 | for (i = 0; regs[i].name; i++) { 21 | if (regs[i].addr == addr) { 22 | snprintf(reg_name, 22, " ; %s", regs[i].name); 23 | return reg_name; 24 | } 25 | } 26 | 27 | return ""; 28 | } 29 | 30 | static int usage() 31 | { 32 | fprintf(stderr, "Usage: bitdis vpu_fw.bin\n"); 33 | return EXIT_FAILURE; 34 | } 35 | 36 | int main(int argc, char *argv[]) 37 | { 38 | unsigned char buf[2]; 39 | unsigned int addr, insn, parm; 40 | char *inpath; 41 | FILE *f; 42 | int i, n; 43 | int opt; 44 | 45 | while ((opt = getopt(argc, argv, "h")) != -1) { 46 | switch (opt) { 47 | case 'h': 48 | usage(); 49 | return EXIT_SUCCESS; 50 | default: 51 | return usage(); 52 | } 53 | } 54 | 55 | if (optind != argc - 1) 56 | return usage(); 57 | inpath = argv[optind]; 58 | 59 | f = fopen(inpath, "rb"); 60 | if (!f) { 61 | fprintf(stderr, "Failed to open '%s': %s\n", argv[1], 62 | strerror(errno)); 63 | return EXIT_FAILURE; 64 | } 65 | 66 | n = get_word(buf, f); 67 | if (n != 2) { 68 | fprintf(stderr, "Failed to read from '%s': %s\n", argv[1], 69 | strerror(errno)); 70 | return EXIT_FAILURE; 71 | } 72 | 73 | printf("Disassembly of %s:\n\n", argv[1]); 74 | while (n == 2) { 75 | const struct inst_mask *imask; 76 | uint16_t code, reg_mask, imm_mask; 77 | enum inst_type type; 78 | 79 | insn = buf[0] | buf[1] << 8; 80 | for (i = 0; iset[i].code; i++) { 81 | type = iset[i].type; 82 | imask = &imasks[type]; 83 | if ((insn & imask->code_mask) == iset[i].code) { 84 | code = iset[i].code; 85 | break; 86 | } 87 | } 88 | 89 | if (!iset[i].code) { 90 | printf(" %04x: %04x\n", addr, insn); 91 | addr += 2; 92 | n = get_word(buf, f); 93 | continue; 94 | } 95 | 96 | if (imask->parm) { 97 | n = get_word(buf, f); 98 | if (n != 2) 99 | break; 100 | parm = buf[0] | buf[1] << 8; 101 | printf(" %04x: %04x %04x", addr, insn, parm); 102 | } else { 103 | printf(" %04x: %04x ", addr, insn); 104 | } 105 | 106 | printf("\t%s\t", iset[i].name); 107 | 108 | reg_mask = imask->reg_mask; 109 | imm_mask = imask->imm_mask; 110 | 111 | if (reg_mask == 0x3) { 112 | printf("$%u, $%u", insn & 1, (insn >> 1) & 1); 113 | } else if (reg_mask) { 114 | printf("$%u", !!(insn & reg_mask)); 115 | if (imm_mask || imask->parm) 116 | printf(", "); 117 | } 118 | 119 | if (imm_mask) { 120 | int shift = ffs(imm_mask) - 1; 121 | uint16_t imm = (insn & imm_mask) >> shift; 122 | 123 | if (code == 0xa800) { /* and.b */ 124 | printf("#0x%x", imm); 125 | } else if (type == INST_J) { 126 | /* short jumps */ 127 | if (imm < 64) 128 | imm = addr + imm * 2; 129 | else 130 | imm = addr + imm * 2 - 256; 131 | printf("0x%x", imm); 132 | } else { 133 | printf("#%d", imm); 134 | } 135 | 136 | if (imask->parm) 137 | printf(", "); 138 | } 139 | 140 | if (imask->parm) { 141 | if (type == INST_PCU) { 142 | /* ipb load & store */ 143 | parm *= 4; 144 | printf("0x%x%s", parm, find_reg_name(parm)); 145 | } else if (type == INST_JUMP || type == INST_CALL) { 146 | /* long jumps and calls */ 147 | parm *= 2; 148 | printf("0x%x", parm); 149 | } else { 150 | printf("0x%x", parm); 151 | } 152 | addr += 2; 153 | } 154 | 155 | printf("\n"); 156 | 157 | /* unconditional jumps without return outside vector table */ 158 | if ((type == INST_JUMP || type == INST_RET || type == INST_J) && 159 | (code & 0x000f) == 0x000e && addr >= 0x40) 160 | printf("\n"); 161 | 162 | addr += 2; 163 | n = get_word(buf, f); 164 | }; 165 | } 166 | -------------------------------------------------------------------------------- /src/bitspl.c: -------------------------------------------------------------------------------- 1 | /* CODA firmware splitter 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "reorder.h" 12 | 13 | static int usage() 14 | { 15 | fprintf(stderr, "Usage: bitspl vpu_fw.bin\n"); 16 | return EXIT_FAILURE; 17 | } 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | unsigned char buf[0x800]; 22 | unsigned char vector_start[8]; 23 | char outname[32] = "00000.bin"; 24 | unsigned int n, i, addr = 0; 25 | FILE *f, *outf; 26 | 27 | if (argc < 2) 28 | return usage(); 29 | 30 | f = fopen(argv[1], "rb"); 31 | if (!f) { 32 | fprintf(stderr, "Failed to open '%s': %s\n", argv[1], 33 | strerror(errno)); 34 | return EXIT_FAILURE; 35 | } 36 | 37 | outf = fopen(outname, "wb"); 38 | if (!f) { 39 | fprintf(stderr, "Failed to open '%s': %s\n", outname, 40 | strerror(errno)); 41 | return EXIT_FAILURE; 42 | } 43 | 44 | for (i = 0; i < 8; i += 2) { 45 | n = get_word(buf + i, f); 46 | if (n != 2) { 47 | fprintf(stderr, "Failed to read from '%s': %s\n", 48 | argv[1], strerror(errno)); 49 | return EXIT_FAILURE; 50 | } 51 | } 52 | 53 | memcpy(vector_start, buf, 8); 54 | 55 | printf("vector at 0x%05x, writing %05x.bin\n", addr, addr); 56 | 57 | while (n == 2) { 58 | for (i = 8; i < 0x800; i += 2) { 59 | n = get_word(buf + i, f); 60 | if (n != 2) 61 | break; 62 | } 63 | 64 | n = fwrite(buf, 1, 0x800, outf); 65 | if (n != 0x800) { 66 | fprintf(stderr, "Failed to write 0x%05x: %s\n", addr, 67 | strerror(errno)); 68 | return EXIT_FAILURE; 69 | } 70 | 71 | memset(buf, 0, sizeof(buf)); 72 | 73 | for (i = 0; i < 8; i += 2) { 74 | n = get_word(buf + i, f); 75 | if (n != 2) 76 | break; 77 | } 78 | 79 | addr += 0x800; 80 | 81 | if (memcmp(buf, vector_start, 8) == 0) { 82 | printf("vector at 0x%05x, writing %05x.bin\n", addr, addr); 83 | 84 | fclose(outf); 85 | 86 | snprintf(outname, sizeof(outname), "%05x.bin", addr); 87 | outf = fopen(outname, "wb"); 88 | if (!f) { 89 | fprintf(stderr, "Failed to open '%s': %s\n", outname, 90 | strerror(errno)); 91 | return EXIT_FAILURE; 92 | } 93 | } 94 | } 95 | 96 | return EXIT_SUCCESS; 97 | } 98 | -------------------------------------------------------------------------------- /src/coda-fwinfo.c: -------------------------------------------------------------------------------- 1 | /* CODA firmware information tool 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "reorder.h" 13 | 14 | #define MAX_TEMPLATE_LEN 12 15 | 16 | enum coda_product_id { 17 | CODA_MX27_TO1 = 0xf000, 18 | CODA_DX6 = 0xf001, 19 | CODA_MX51 = 0xf00a, 20 | CODA_7541 = 0xf012, 21 | CODA_960 = 0xf020, 22 | }; 23 | 24 | #define ANY 0xffff 25 | 26 | static const uint16_t template_product_id[3] = { 27 | 0xe004, ANY, /* mv.h $0, product_id */ 28 | 0xae20, /* lsl $0, #16 */ 29 | }; 30 | 31 | static const uint16_t template_imx2[5] = { 32 | 0xe005, ANY, /* mv.h $1, firmware_version_number */ 33 | 0xe056, /* or.w $0, $1 */ 34 | 0xe0c2, 0x0070, /* st.w $0, 0x1c0 ; FIRMWARE_VERNUM */ 35 | }; 36 | 37 | static const uint16_t template_imx5[4] = { 38 | 0xe00a, ANY, /* or.h $0, firmware_version_number */ 39 | 0xe0c2, 0x0070, /* st.w $0, 0x1c0 */ 40 | }; 41 | 42 | static const uint16_t template_imx6[12] = { 43 | 0xe005, ANY, /* mv.h $1, firmware_version_number */ 44 | 0xe056, /* or.w $0, $1 */ 45 | 0xe0c2, 0x0070, /* st.w $0, 0x1c0 ; FIRMWARE_VERNUM */ 46 | 0xe004, ANY, /* mv.h $0, #0x0 */ 47 | 0xae20, /* lsl $0, #16 */ 48 | 0xe00a, ANY, /* or.h $0, firmware_code_revision */ 49 | 0xe0c2, 0x0071, /* st.w $0, 0x1c4 ; FIRMWARE_CODE_REV */ 50 | }; 51 | 52 | static const char *coda_product_name(enum coda_product_id pid) 53 | { 54 | switch (pid) { 55 | case CODA_MX27_TO1: 56 | return "i.MX27 TO1"; 57 | case CODA_DX6: 58 | return "CodaDx6 (i.MX27 TO2)"; 59 | case CODA_MX51: 60 | return "i.MX51"; 61 | case CODA_7541: 62 | return "CODA7541 (i.MX53)"; 63 | case CODA_960: 64 | return "CODA960 (i.MX6)"; 65 | default: 66 | return "unknown"; 67 | } 68 | } 69 | 70 | static const uint16_t *find_template(FILE *f, const uint16_t *template, 71 | int template_len) 72 | { 73 | static uint16_t code[MAX_TEMPLATE_LEN]; 74 | unsigned char buf[2]; 75 | uint16_t insn; 76 | int n, i = 0; 77 | int addr = 0; 78 | 79 | n = get_word(buf, f); 80 | if (n != 2) 81 | return NULL; 82 | 83 | while (n == 2) { 84 | insn = buf[0] | buf[1] << 8; 85 | if (insn == template[i] || template[i] == ANY) 86 | code[i++] = insn; 87 | else 88 | i = 0; 89 | if (i == template_len) 90 | return code; 91 | n = get_word(buf, f); 92 | addr += n; 93 | } 94 | return NULL; 95 | } 96 | 97 | int usage() 98 | { 99 | fprintf(stderr, "Usage: coda-fwinfo vpu_fw.bin\n"); 100 | return EXIT_FAILURE; 101 | } 102 | 103 | int main(int argc, char *argv[]) { 104 | uint16_t pid, ver = 0; 105 | uint32_t rev = 0; 106 | const uint16_t *code; 107 | const char *inpath; 108 | FILE *f; 109 | int opt; 110 | 111 | while ((opt = getopt(argc, argv, "h")) != -1) { 112 | switch (opt) { 113 | case 'h': 114 | usage(); 115 | return EXIT_SUCCESS; 116 | default: 117 | return usage(); 118 | } 119 | } 120 | 121 | if (optind != argc - 1) 122 | return usage(); 123 | inpath = argv[optind]; 124 | 125 | f = fopen(inpath, "rb"); 126 | if (!f) { 127 | fprintf(stderr, "Failed to open '%s': %s\n", argv[1], 128 | strerror(errno)); 129 | return EXIT_FAILURE; 130 | } 131 | 132 | code = find_template(f, template_product_id, 3); 133 | if (code == NULL) { 134 | if (errno) 135 | fprintf(stderr, "Failed to read from '%s': %d (%m)\n", 136 | argv[1], errno); 137 | else 138 | fprintf(stderr, "Failed to find product id template\n"); 139 | return EXIT_FAILURE; 140 | } 141 | pid = code[1]; 142 | 143 | printf("Product ID: 0x%04x, %s\n", pid, coda_product_name(pid)); 144 | switch (pid) { 145 | case CODA_MX27_TO1: 146 | case CODA_DX6: 147 | code = find_template(f, template_imx2, 5); 148 | break; 149 | case CODA_MX51: 150 | case CODA_7541: 151 | code = find_template(f, template_imx5, 4); 152 | break; 153 | case CODA_960: 154 | code = find_template(f, template_imx6, 12); 155 | if (code) 156 | rev = (code[6] << 16) | code[9]; 157 | break; 158 | } 159 | if (code == NULL) { 160 | fprintf(stderr, "Failed to find firmware version template\n"); 161 | return EXIT_FAILURE; 162 | } 163 | ver = code[1]; 164 | 165 | printf("Version Number: 0x%04x (%d.%d.%d)\n", ver, ver >> 12, (ver >> 8) & 0xf, ver & 0xff); 166 | if (rev) 167 | printf("Code Revision: 0x%x\n", rev); 168 | }; 169 | -------------------------------------------------------------------------------- /src/iset.h: -------------------------------------------------------------------------------- 1 | /* CODA BIT processor instruction set 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #ifndef __ISET_H__ 5 | #define __ISET_H__ 6 | 7 | #include 8 | #include 9 | 10 | enum inst_type { 11 | INST_ALUB, 12 | INST_ALUH, 13 | INST_ALUW, 14 | INST_PCU, 15 | INST_JUMP, 16 | INST_CALL, 17 | INST_RET, 18 | INST_J, 19 | INST_UNIQ, 20 | NUM_INST_TYPES, 21 | }; 22 | 23 | static const struct inst_mask { 24 | uint16_t code_mask; 25 | uint16_t imm_mask; 26 | uint16_t reg_mask; 27 | bool parm; 28 | } imasks[NUM_INST_TYPES] = { 29 | [INST_ALUB] = { 0xff00, 0x00fe, 0x0001, 0 }, 30 | [INST_ALUH] = { 0xfffe, 0x0000, 0x0001, 1 }, 31 | [INST_ALUW] = { 0xfffc, 0x0000, 0x0003, 0 }, 32 | [INST_PCU] = { 0xfffe, 0x0000, 0x0001, 1 }, 33 | [INST_JUMP] = { 0xfffe, 0x0000, 0x0001, 1 }, 34 | [INST_CALL] = { 0xfffe, 0x0000, 0x0001, 1 }, 35 | [INST_RET] = { 0xfffe, 0x0000, 0x0001, 0 }, 36 | [INST_J] = { 0xf00e, 0x0ff0, 0x0001, 0 }, 37 | [INST_UNIQ] = { 0xffff, 0x0000, 0x0000, 0 }, 38 | }; 39 | 40 | static const struct inst { 41 | uint16_t code; 42 | enum inst_type type; 43 | char *name; 44 | } iset[] = { 45 | { 0xa000, INST_ALUB, "add.b" }, 46 | { 0xa100, INST_ALUB, "sub.b" }, 47 | { 0xa200, INST_ALUB, "mv.b" }, 48 | { 0xa800, INST_ALUB, "and.b" }, 49 | { 0xae00, INST_ALUB, "lsl" }, 50 | { 0xaf00, INST_ALUB, "lsr" }, 51 | { 0xce00, INST_UNIQ, "int" }, 52 | { 0xe002, INST_ALUH, "sub.h" }, 53 | { 0xe004, INST_ALUH, "mv.h" }, 54 | { 0xe008, INST_ALUH, "and.h" }, 55 | { 0xe00a, INST_ALUH, "or.h" }, 56 | { 0xe040, INST_ALUW, "add.w" }, 57 | { 0xe044, INST_ALUW, "sub.w" }, 58 | { 0xe050, INST_ALUW, "and.w" }, 59 | { 0xe054, INST_ALUW, "or.w" }, 60 | { 0xe0c0, INST_PCU, "ld.w" }, 61 | { 0xe0c2, INST_PCU, "st.w" }, 62 | { 0xe190, INST_UNIQ, "nop" }, 63 | { 0xe402, INST_JUMP, "jumple" }, 64 | { 0xe408, INST_JUMP, "jumpnz" }, 65 | { 0xe40a, INST_JUMP, "jumpz" }, 66 | { 0xe40e, INST_JUMP, "jump" }, 67 | { 0xe412, INST_CALL, "callle" }, 68 | { 0xe418, INST_CALL, "callnz" }, 69 | { 0xe41a, INST_CALL, "callz" }, 70 | { 0xe41e, INST_CALL, "call" }, 71 | { 0xe422, INST_RET, "retle" }, 72 | { 0xe428, INST_RET, "retnz" }, 73 | { 0xe42a, INST_RET, "retz" }, 74 | { 0xe42e, INST_RET, "ret" }, 75 | { 0xf002, INST_J, "jle" }, 76 | { 0xf008, INST_J, "jnz" }, 77 | { 0xf00a, INST_J, "jz" }, 78 | { 0xf00e, INST_J, "j" }, 79 | { /* sentinel */ } 80 | }; 81 | 82 | #endif /* __ISET_H__ */ 83 | -------------------------------------------------------------------------------- /src/regs.h: -------------------------------------------------------------------------------- 1 | /* CODA register layout 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #ifndef __REGS_H__ 5 | #define __REGS_H__ 6 | 7 | #include 8 | 9 | static const struct reg { 10 | uint16_t addr; 11 | char *name; 12 | } regs[] = { 13 | { 0x000, "CODE_RUN" }, 14 | { 0x004, "CODE_DOWN" }, 15 | { 0x008, "HOST_IN_REQ" }, 16 | { 0x00c, "INT_CLEAR" }, 17 | { 0x010, "INT_STATUS" }, 18 | { 0x014, "CODE_RESET" }, 19 | { 0x018, "CUR_PC" }, 20 | { 0x024, "SW_RESET" }, 21 | { 0x034, "SW_RESET_STATUS" }, 22 | { 0x100, "CODE_BUF_ADDR" }, 23 | { 0x104, "WORK_BUF_ADDR" }, 24 | { 0x108, "PARA_BUF_ADDR" }, 25 | { 0x10c, "STREAM_CTRL" }, 26 | { 0x110, "FRAME_MEM_CTRL" }, 27 | { 0x114, "BIT_STREAM_PARAM" }, 28 | { 0x118, "TEMP_BUF_ADDR" }, 29 | { 0x11c, "BIT_RESET_CTRL" }, 30 | { 0x120, "RD_PTR" }, 31 | { 0x124, "WR_PTR" }, 32 | { 0x140, "AXI_SRAM_USE" }, 33 | { 0x150, "FRM_DIS_FLG" }, 34 | { 0x160, "BUSY" }, 35 | { 0x164, "RUN_COMMAND" }, 36 | { 0x168, "RUN_INDEX" }, 37 | { 0x16c, "RUN_COD_STD" }, 38 | { 0x170, "INT_ENABLE" }, 39 | { 0x174, "INT_REASON" }, 40 | { 0x178, "RUN_AUX_STD" }, 41 | 42 | { 0x1000, "GDI_PRI_RD_PRIO_L" }, 43 | { 0x1004, "GDI_PRI_RD_PRIO_H" }, 44 | { 0x1008, "GDI_PRI_WR_PRIO_L" }, 45 | { 0x100c, "GDI_PRI_WR_PRIO_H" }, 46 | { 0x1010, "GDI_PRI_RD_LOCK_CNT" }, 47 | { 0x1014, "GDI_PRI_WR_LOCK_CNT" }, 48 | { 0x1018, "GDI_SEC_RD_PRIO_L" }, 49 | { 0x101c, "GDI_SEC_RD_PRIO_H" }, 50 | { 0x1020, "GDI_SEC_WR_PRIO_L" }, 51 | { 0x1024, "GDI_SEC_WR_PRIO_H" }, 52 | { 0x1028, "GDI_SEC_RD_LOCK_CNT" }, 53 | { 0x102c, "GDI_SEC_WR_LOCK_CNT" }, 54 | { 0x1030, "GDI_SEC_CLIENT_EN" }, 55 | { 0x1034, "GDI_CONTROL" }, 56 | { 0x1038, "GDI_PIC_INIT_HOST" }, 57 | { 0x1060, "GDI_PINFO_REQ" }, 58 | { 0x1064, "GDI_PINFO_ACK" }, 59 | { 0x1068, "GDI_PINFO_ADDR" }, 60 | { 0x106c, "GDI_PINFO_DATA" }, 61 | { 0x1070, "GDI_BWB_ENABLE" }, 62 | { 0x1074, "GDI_BWB_SIZE" }, 63 | { 0x1078, "GDI_BWB_STD_STRUCT" }, 64 | { 0x107c, "GDI_BWB_STATUS" }, 65 | { 0x1080, "GDI_STATUS" }, 66 | { 0x1084, "GDI_DEBUG_0" }, 67 | { 0x1088, "GDI_DEBUG_1" }, 68 | { 0x108c, "GDI_DEBUG_2" }, 69 | { 0x1090, "GDI_DEBUG_3" }, 70 | { 0x10a0, "GDI_WPROT_ERR_CLR" }, 71 | { 0x10a4, "GDI_WPROT_ERR_RSN" }, 72 | { 0x10a8, "GDI_WPROT_ERR_ADR" }, 73 | { 0x10ac, "GDI_WPROT_RGN_EN" }, 74 | { 0x10b0, "GDI_WPROT_RGN0_STA" }, 75 | { 0x10b4, "GDI_WPROT_RGN0_END" }, 76 | { 0x10b8, "GDI_WPROT_RGN1_STA" }, 77 | { 0x10bc, "GDI_WPROT_RGN1_END" }, 78 | { 0x10c0, "GDI_WPROT_RGN2_STA" }, 79 | { 0x10c4, "GDI_WPROT_RGN2_END" }, 80 | { 0x10c8, "GDI_WPROT_RGN3_STA" }, 81 | { 0x10cc, "GDI_WPROT_RGN3_END" }, 82 | { 0x10d0, "GDI_WPROT_RGN4_STA" }, 83 | { 0x10d4, "GDI_WPROT_RGN4_END" }, 84 | { 0x10d8, "GDI_WPROT_RGN5_STA" }, 85 | { 0x10dc, "GDI_WPROT_RGN5_END" }, 86 | { 0x10e0, "GDI_SIZE_ERR_FLAG" }, 87 | { 0x10f0, "GDI_BUS_CTRL" }, 88 | { 0x10f4, "GDI_BUS_STATUS" }, 89 | { 0x1100, "GDI_ADR_RQ_SIZE_ERR_PRI0" }, 90 | { 0x1104, "GDI_ADR_RQ_SIZE_ERR_PRI1" }, 91 | { 0x1108, "GDI_ADR_RQ_SIZE_ERR_PRI2" }, 92 | { 0x110c, "GDI_ADR_WQ_SIZE_ERR_PRI0" }, 93 | { 0x1110, "GDI_ADR_WQ_SIZE_ERR_PRI1" }, 94 | { 0x1114, "GDI_ADR_WQ_SIZE_ERR_PRI2" }, 95 | { 0x1100, "GDI_ADR_RQ_SIZE_ERR_SEC0" }, 96 | { 0x1104, "GDI_ADR_RQ_SIZE_ERR_SEC1" }, 97 | { 0x1108, "GDI_ADR_RQ_SIZE_ERR_SEC2" }, 98 | { 0x110c, "GDI_ADR_WQ_SIZE_ERR_SEC0" }, 99 | { 0x1110, "GDI_ADR_WQ_SIZE_ERR_SEC1" }, 100 | { 0x1114, "GDI_ADR_WQ_SIZE_ERR_SEC2" }, 101 | { 0x1400, "GDI_INFO_CONTROL" }, 102 | { 0x1404, "GDI_INFO_PIC_SIZE" }, 103 | { 0x1408, "GDI_INFO_BASE_Y" }, 104 | { 0x140c, "GDI_INFO_BASE_CB" }, 105 | { 0x1410, "GDI_INFO_BASE_CR" }, 106 | { /* sentinel */ } 107 | }; 108 | 109 | #endif /* __REGS_H__ */ 110 | -------------------------------------------------------------------------------- /src/reorder.c: -------------------------------------------------------------------------------- 1 | /* CODA host memory layout to BIT processor layout reordering code 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #include 5 | #include 6 | 7 | ssize_t get_word(unsigned char word[2], FILE *f) 8 | { 9 | static int pos = 4; 10 | static bool reorder = false; 11 | static unsigned char buf[8]; 12 | ssize_t n; 13 | int i; 14 | 15 | if (pos == 4) { 16 | n = fread(buf, 1, 8, f); 17 | if (n < 2) 18 | return n; 19 | pos = 0; 20 | 21 | if (buf[0] == 'M' && buf[1] == 'X') { 22 | /* skip Freescale header */ 23 | fseek(f, 8, SEEK_CUR); 24 | n = fread(buf, 1, 8, f); 25 | if (n < 0) 26 | return 0; 27 | } 28 | 29 | if (buf[0] == 0x90 && buf[1] == 0xe1) { 30 | printf("Firmware in host memory order\n"); 31 | reorder = true; 32 | } else if (buf[0] == 0x0e && buf[1] == 0xe4) { 33 | printf("Firmware in BIT processor memory order\n"); 34 | } else { 35 | fprintf(stderr, "Unknown file type\n"); 36 | } 37 | } else if (pos == 0) { 38 | n = fread(buf, 1, 8, f); 39 | if (n < 2) 40 | return n; 41 | } 42 | 43 | /* FIXME - this correctly reorders for i.MX51 and above only */ 44 | if (reorder) 45 | i = 3 - pos; 46 | else 47 | i = pos; 48 | 49 | word[0] = buf[2 * i]; 50 | word[1] = buf[2 * i + 1]; 51 | 52 | pos = (pos + 1) % 4; 53 | 54 | return 2; 55 | } 56 | -------------------------------------------------------------------------------- /src/reorder.h: -------------------------------------------------------------------------------- 1 | /* CODA host memory layout to BIT processor layout reordering code 2 | * SPDX-License-Identifier: 0BSD 3 | */ 4 | #ifndef __REORDER_H__ 5 | #define __REORDER_H__ 6 | 7 | #include 8 | 9 | ssize_t get_word(unsigned char word[2], FILE *f); 10 | 11 | #endif /* __REORDER_H__ */ 12 | --------------------------------------------------------------------------------