summaryrefslogtreecommitdiff
path: root/posts/2014-09-18-wavedrum-firmware-disassembler.markdown
blob: af8d0430dd748273c6908490069500d47323a5be (about) (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
---
title: Disassembling the Wavedrum firmware
tags: DIY,electronics,music,hacking,wavedrum,SHARC
---

The Wavedrum's processing unit is an ADSP-21375 by Analog Devices, a
member of the SHARC processor family.  The firmware of the Wavedrum,
which is stored on a micro SD-card and, more importantly, on the flash
memory chip is loaded into the processor during the boot process.

[Last time](2013-12-09-wavedrum-connectors.html) I confirmed by tracing the
connections of the two boot pins that the processor is wired to boot
from EPROM/Flash (`BOOT_CFG1-0 = 10`).  I'm too lazy to try to verify
that the firmware on the micro SD-card is identical to the contents of
the flash memory, so I'll just assume that this is the case.

When the processor is initially powered on, the internal memory is in
an undefined state.  According to the
[ADSP hardware reference](http://www.analog.com/static/imported-files/processor_manuals/ADSP-21367_hwr_rev2-1.pdf)
(section 17-7 *Processor Booting*), the processor core is put into
`IDLE` mode while loading the boot kernel from an external source (in
our case this is the flash memory) into the internal memory at address
0x90000 (`IVT_START_ADDR`), and finally executes the boot kernel code
when a peripheral interrupt signals that the kernel has been loaded.
Then the application code is loaded from the memory and finally the
application's Interrupt Vector Table (IVT) is loaded.  The boot kernel
is 256 48-bit words long, as is the IVT.  The application code is of
arbitrary length.


# Word packing

The boot kernel is exactly 256 48-bit words long (shorter kernels are
padded with NOPs), but the words are not transferred as 48-bit words.
The boot kernel is transferred from the external memory as a stream of
384 "packed" 32-bit words (see table 17-6 in the hardware reference).
To understand packing we have to know that conceptionally the internal
memory consists of many rows of four columns, each of which is 16 bit
wide.  Accessing 48-bit words is often referred to as 3-column access
in the reference, whereas accessing 32-bit words is called 2-column
access.  All of the SHARC instructions are 48 bit wide.  This means
that any 32-bit wide package never contains the full instruction.
Dependent on the order of the packages, the 48-bit words can be
reconstructed from a stream of 32-bit words.

Here's the original explanation in the hardware reference on page
17-27:

> During the boot process, word packing (for example 8 to 32-bit) is
> performed over the SPI. In other words, the kernel is not loaded
> directly with 256 x 48-bit words, instead it is loaded with 384 x
> 32-bit ‘packed words’ (2-column access). The same physical memory
> for instruction boot is loaded via DMA in normal word (NW) 2
> column. However, after booting the same physical memory region is
> fetched by the sequencer in NW 3-column. For example the loader
> kernel itself has a NW 2 columns count of 256 x 3/2 = 384 words but
> the kernel is executed with 256 instruction fetches.

When booting from external memory the bus width is set to 8 bits.
According to the
[ADSP hardware reference](http://www.analog.com/static/imported-files/processor_manuals/ADSP-21367_hwr_rev2-1.pdf)
(section "External Port Booting"), the processor reads a stream of
8-bit words from the data port and packs four of them into 32-bit
words (LSB first) before storing them into the internal memory.

Figure 17-5 in the hardware reference visualises this process rather
nicely.  It shows how streams of different word sizes end up being
stored in the internal memory.

<img class="full stretch" src="/images/posts/2014/wavedrum-word-packing.png" alt="word packing" />

Once I understood that words are transferred from the memory in 8-bit
chuncks with the LSB first, writing a disassembler that would
translate the binary boot kernel into assembly code was no longer very
challenging.


# A free disassembler for ADSP-213xx

I implemented a simple tool in Haskell that takes a binary firmware
and spits out assembly code for the ADSP.  At the moment it only
supports a limited set of instructions, just enough so that I could
translate the boot kernel.  The remainder of the instructions
will be implemented later as I happen to encounter them in the
application code.

It currently only parses the first 256 words of the firmware,
i.e. only the boot kernel.  Before I can parse the remainder I need to
figure out the memory layout.

The code is freely available under the
[GPL](http://www.gnu.org/licenses/#GPL) and can be
[downloaded here](http://git.elephly.net/wavedrum/sharc-disassembler.git).
See the included instructions for assistance in compiling and using
the disassembler.


# Next steps

My work isn't over yet.  Next I'll focus on the following tasks:

- figure out how the boot kernel loads the application code into the
  processor
- disassemble (parts of) the application code
- look out for snippets that involve loading code from the micro-SD
  card to the flash memory, because that's our ticket to upgrade the
  firmware easily

If you want to help me, I'd be happy if you could send me a copy of
the Global Edition's firmware.  To do this you only need to take out
the micro SD-card and create a disk image of it.  (On GNU/Linux this
can easily be done with `dd` on the command line; see
[my first post on hacking the Wavedrum](http://elephly.net/posts/2013-08-11-hacking-the-wavedrum.html)
for more detailed instructions.)

I would also be very grateful for code reviews and patches.
Translating the various specifications into executable code wasn't
always easy and I'm sure there are bugs in the code here and there.

Read [more posts about the Wavedrum here](http://elephly.net/tags/wavedrum.html).