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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
Rockbox From A Technical Angle
==============================
Background
Björn Stenberg started this venture back in the late year 2001. The first
Rockbox code was committed to CVS end of March 2002. Rockbox 1.0 was
released in June.
Booting and (De)Scrambling
The built-in firmware in the Archos Jukebox reads a file from disk into
memory, descrambles it, verifies the checksum and then runs it as code. When
we build Rockbox images, we scramble the result file to use the same kind of
scrambling that the original Archos firmware uses so that it can be loaded
by the built-in firmware.
1) The built-in firmware starts
2) It looks in the root directory for a file called "archos.mod" (player)
or "ajbrec.ajz" (recorder)
3) If it finds one, it loads the file, descrambles it and runs it
CPU
The CPU in use is a SH7034 from Hitachi, running at 11.0592MHz (recorder)
or 12MHz (player).
Most single instructions are executed in 1 cycle. There is a 4KB internal RAM
and a 2MB external RAM.
Memory Usage
All Archos Jukebox models have only 2MB RAM. The RAM is used for everything,
including code, graphics and config. To be able to play as long as possible
without having to load more data, the size of the mpeg playing buffer must
remain as big as possible. Also, since we need to be able to do almost
everything in Rockbox simultaneously, we use no dynamic memory allocation
system at all. All sub-parts that needs memory must allocate their needs
staticly. This puts a great responsibility on all coders.
Playing MPEG
The MPEG decoding is performed by an external circuit, MAS3507D (for the
Player/Studio models) or MAS3587F (for the Recorder models).
The CPU has a serial connection to the MAS for MP3 playback, using serial
port 0 at approx. 1mbit/s. The MAS has a handshake signal called DEMAND,
that informs the CPU when it wants more MP3 data. Whenever the DEMAND
signal goes high, it wants data sent over the serial line, and it wants it
quickly, within ~1ms. When the MAS has received enough data, it negates the
DEMAND signal and expects the incoming data stream to stop within 1ms.
The DEMAND signal is connected to a port pin on the CPU which can generate
an IRQ, but only on the falling edge. That means that the mpeg driver code
must poll the DEMAND signal every ms to keep the MAS happy. The mpeg code
does use the IRQ to detect the falling edge when the MAS is "full".
Unfortunately, the serial port on the CPU sends the LSB first, and the MAS
expects the MSB first. Therefore we have to revers the bit order in every
byte in the loaded MP3 data. This is referred to as "bit swapping" in the
Rockbox code.
The internal DMA controller is used to feed the serial port with data. The
driver works roughly like this:
1) Load MP3 data into the RAM buffer
2) Bitswap the data
3) Load the DMA source pointer to the next 64Kbyte block to be transferred
4) Wait until DEMAND is high
5) Enable the DMA
6) Wait until the falling DEMAND pin generates an IRQ
7) Disable the DMA
8) Go to 4
The DMA generates an IRQ when the 64Kbyte block is transferred, and the
IRQ handler updates the DMA source pointer.
_____________________________
| |
DEMAND __________| |_____________
_ _ _ _ _ _ _ _ _
SC0 _____________/ \/ \/ \/ \/ \/ \/ \/ \/ \____________
\_/\_/\_/\_/\_/\_/\_/\_/\_/
^ ^
| |
Poll sees the DEMAND The DEMAND pin generates
signal go high and an IRQ that in turn disables
enables the DMA the DMA again
Spinning The Disk Up/Down
To save battery, the spinning of the harddrive must be kept at a minimum.
Rockbox features a timeout, so that if no action has been performed within N
seconds, the disk will spin-down automaticly. However, if the disk was used
for mpeg-loading for music playback, the spin-down will be almost immediate
as then there's no point in timing out. The N second timer is thus only used
when the disk-activity is trigged by a user.
FAT and Mounting
Rockbox scans the partitions of the disk and tries to mount them as fat32
filesystems at boot.
Directory Buffer
When using the "dir browser" in Rockbox to display a single directory, it
loads all entries in the directory into memory first, then sorts them and
presents them on screen. The buffer used for all file entries is limited to
maximum 16K or 400 entries. If the file names are longish, the 16K will run
out before 400 entries have been used.
This rather limited buffer size is of course again related to the necessity
to keep the footprint small to keep the mpeg buffer as large as possible.
Playlist Concepts
One of the most obvious limitations in the firmware Rockbox tries to
outperform, was the way playlists were dealt with.
When loading a playlist (which is a plain text file with file names
separated by newlines), Rockbox will scan through the file and store indexes
to all file names in an array. The array itself has a 10000-entry limit (for
memory size reasons).
To play a specific song from the playlist, Rockbox checks the index and then
seeks to that position in the original file on disk and gets the file name
from there. This way, very little memory is wasted and yet very large
playlists are supported.
Playing a Directory
Playing a full directory is using the same technique as with playlists. The
difference is that the playlist is not a file on disk, but is the directory
buffer.
Shuffle
Since the playlist is a an array of indexes to where to read the file name,
shuffle modifies the order of these indexes in the array. The algorithm is
pretty much like shuffling a deck of cards, and it uses a pseudo random
generator called the Mersenne Twister. The randomness is identical for the
same random seed. This is the secret to good resume. Even when you've shut
down your unit and re-starts it, using the same random seed as the previous
time will give exactly the same random order.
Saving Config Data
The Player/Studio models have no battery-backuped memory while the Recorder
models have 44 bytes battery-backuped.
To save data to be persistent and around even after reboots, Rockbox uses
harddisk sector 63, which is outside the FAT32 filesystem. (Recorder models
also get some data stored in the battery-backuped area).
The config is only saved when the disk is spinning. This is important to
realize, as if you change a config setting and then immediately shuts your
unit down, the new config is not saved.
DEVELOPERS:
The config checksum includes a header with a version number. This version
number must be increased when the config structure becomes incompatible.
This makes the checksum check fail, and the settings are reset to default
values.
Resume Explained
...
Charging
(Charging concerns Recorder models only, the other models have hardware-
controlled charging that Rockbox can't affect.)
...
Profiling
Rockbox contains a profiling system which can be used to monitor call count
and time in function for a specific set of functions on a single thread.
To use this functionality:
1) Configure a developer build with profiling support.
2) Make sure that the functions of interest will be compiled with the
PROFILE_OPTS added to their CFLAGS
3) On the same thread as these functions will be run, surround the relevent
running time with calls to profile_thread and profstop. (For codecs,
this can be done in the codec.c file for example)
4) Compile and run the code on the target, after the section to be profiled
exits (when profstop is called) a profile.out file will be written to
the player's root.
5) Use the tools/profile_reader/profile_reader.pl script to convert the
profile.out into a human readable format. This script requires the
relevent map files and object (or library) files created in the build.
(ex: ./profile_reader.pl profile.out vorbis.map libTremor.a 0)
There is also a profile_comparator.pl script which can compare two profile
runs as output by the above script to show percent change from optimization
profile_reader.pl requires a recent binutils that can automatically handle
target object files, or objdump in path to be the target-objdump.
|