05dccc3551
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8375 a1c6a512-1295-4272-9138-f99709370657
200 lines
8.5 KiB
Text
200 lines
8.5 KiB
Text
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.
|