posts: add diagram for shared Guix profiles and store
[software/elephly-net.git] / posts / 2014-09-18-wavedrum-firmware-disassembler.markdown
1 ---
2 title: Disassembling the Wavedrum firmware
3 tags: DIY,electronics,music,hacking,wavedrum,SHARC
4 ---
6 The Wavedrum's processing unit is an ADSP-21375 by Analog Devices, a
7 member of the SHARC processor family. The firmware of the Wavedrum,
8 which is stored on a micro SD-card and, more importantly, on the flash
9 memory chip is loaded into the processor during the boot process.
11 [Last time](2013-12-09-wavedrum-connectors.html) I confirmed by tracing the
12 connections of the two boot pins that the processor is wired to boot
13 from EPROM/Flash (`BOOT_CFG1-0 = 10`). I'm too lazy to try to verify
14 that the firmware on the micro SD-card is identical to the contents of
15 the flash memory, so I'll just assume that this is the case.
17 When the processor is initially powered on, the internal memory is in
18 an undefined state. According to the
19 [ADSP hardware reference](
20 (section 17-7 *Processor Booting*), the processor core is put into
21 `IDLE` mode while loading the boot kernel from an external source (in
22 our case this is the flash memory) into the internal memory at address
23 0x90000 (`IVT_START_ADDR`), and finally executes the boot kernel code
24 when a peripheral interrupt signals that the kernel has been loaded.
25 Then the application code is loaded from the memory and finally the
26 application's Interrupt Vector Table (IVT) is loaded. The boot kernel
27 is 256 48-bit words long, as is the IVT. The application code is of
28 arbitrary length.
31 # Word packing
33 The boot kernel is exactly 256 48-bit words long (shorter kernels are
34 padded with NOPs), but the words are not transferred as 48-bit words.
35 The boot kernel is transferred from the external memory as a stream of
36 384 "packed" 32-bit words (see table 17-6 in the hardware reference).
37 To understand packing we have to know that conceptionally the internal
38 memory consists of many rows of four columns, each of which is 16 bit
39 wide. Accessing 48-bit words is often referred to as 3-column access
40 in the reference, whereas accessing 32-bit words is called 2-column
41 access. All of the SHARC instructions are 48 bit wide. This means
42 that any 32-bit wide package never contains the full instruction.
43 Dependent on the order of the packages, the 48-bit words can be
44 reconstructed from a stream of 32-bit words.
46 Here's the original explanation in the hardware reference on page
47 17-27:
49 > During the boot process, word packing (for example 8 to 32-bit) is
50 > performed over the SPI. In other words, the kernel is not loaded
51 > directly with 256 x 48-bit words, instead it is loaded with 384 x
52 > 32-bit ‘packed words’ (2-column access). The same physical memory
53 > for instruction boot is loaded via DMA in normal word (NW) 2
54 > column. However, after booting the same physical memory region is
55 > fetched by the sequencer in NW 3-column. For example the loader
56 > kernel itself has a NW 2 columns count of 256 x 3/2 = 384 words but
57 > the kernel is executed with 256 instruction fetches.
59 When booting from external memory the bus width is set to 8 bits.
60 According to the
61 [ADSP hardware reference](
62 (section "External Port Booting"), the processor reads a stream of
63 8-bit words from the data port and packs four of them into 32-bit
64 words (LSB first) before storing them into the internal memory.
66 Figure 17-5 in the hardware reference visualises this process rather
67 nicely. It shows how streams of different word sizes end up being
68 stored in the internal memory.
70 <img class="full stretch" src="/images/posts/2014/wavedrum-word-packing.png" alt="word packing" />
72 Once I understood that words are transferred from the memory in 8-bit
73 chuncks with the LSB first, writing a disassembler that would
74 translate the binary boot kernel into assembly code was no longer very
75 challenging.
78 # A free disassembler for ADSP-213xx
80 I implemented a simple tool in Haskell that takes a binary firmware
81 and spits out assembly code for the ADSP. At the moment it only
82 supports a limited set of instructions, just enough so that I could
83 translate the boot kernel. The remainder of the instructions
84 will be implemented later as I happen to encounter them in the
85 application code.
87 It currently only parses the first 256 words of the firmware,
88 i.e. only the boot kernel. Before I can parse the remainder I need to
89 figure out the memory layout.
91 The code is freely available under the
92 [GPL]( and can be
93 [downloaded here](
94 See the included instructions for assistance in compiling and using
95 the disassembler.
98 # Next steps
100 My work isn't over yet. Next I'll focus on the following tasks:
102 - figure out how the boot kernel loads the application code into the
103 processor
104 - disassemble (parts of) the application code
105 - look out for snippets that involve loading code from the micro-SD
106 card to the flash memory, because that's our ticket to upgrade the
107 firmware easily
109 If you want to help me, I'd be happy if you could send me a copy of
110 the Global Edition's firmware. To do this you only need to take out
111 the micro SD-card and create a disk image of it. (On GNU/Linux this
112 can easily be done with `dd` on the command line; see
113 [my first post on hacking the Wavedrum](
114 for more detailed instructions.)
116 I would also be very grateful for code reviews and patches.
117 Translating the various specifications into executable code wasn't
118 always easy and I'm sure there are bugs in the code here and there.
120 Read [more posts about the Wavedrum here](