Nintendo DS Architecture

A practical analysis by Rodrigo Copetti

Classic edition - Last updated: January 7, 2024

Languages available: 🇬🇧 - English, 🇨🇳 - 简体字, 👋 - Add translation


About this edition

The ‘classic’ edition is an alternative version to the ‘modern’ counterpart. It doesn‘t require Javascript, state-of-the-art CSS or convoluted HTML to work, which makes it ideal for readers who use accessibility tools or legacy internet browsers. On the other hand, eBook users can now check the eBook edition.

This edition is identical content-wise. However, interactive widgets have been simplified to work with pure HTML, though these will offer an link to the original article in case the reader wants to try the ‘full version’.

As always, this article is available on Github to enable readers to report mistakes or propose changes. There‘s also a supporting reading list available to help understand the series. The author also accepts donations to help improve the quality of current articles and upcoming ones.


Table of Contents

  1. Supporting imagery
  2. A quick introduction
  3. CPU
    1. ARM’s new territories
    2. Nintendo’s debuting SoC
      1. ARM7TDMI
      2. ARM946E-S
    3. Interconnection
    4. Main memory
    5. Backwards compatibility
    6. Unused Power
  4. Graphics
    1. Architecture
    2. Constructing a frame with 2D graphics
      1. Tiles
      2. Background types
      3. Background modes
      4. Sprites
      5. Result
    3. The 3D accelerator
      1. Geometry Engine
      2. Rendering Engine
      3. Result
    4. Famous comparisons
      1. First example
      2. Second example
    5. Interactive models
  5. Audio
    1. An eccentric PSG (or two)
    2. Interactive comparison
    3. Some struggles
  6. I/O
    1. Accessing cartridges and memory
    2. Peripherals
    3. Wireless network
  7. Operating System
    1. Entry point
    2. Window of opportunity
    3. Interactive shell
    4. Updatability
  8. Games
    1. Medium
    2. Program structure
    3. Development ecosystem
      1. The hardware
      2. The software
    4. Freedom of interaction
    5. Network service
  9. Anti-Piracy and Homebrew
    1. Security Mechanisms
      1. Encryption system
      2. DS card validation
      3. Download Play protection
    2. Defeat
      1. Existing Slot-2
      2. Enhanced Slot-2
      3. Native Slot-1
      4. Observations
  10. That’s all folks
  11. Copyright and permissions
  12. Sources / Keep Reading
  13. Contributing
  14. Changelog

Supporting imagery

Model

Image
The original Nintendo DS (Blue edition).
Released on 21/11/2004 in America, 02/12/2004 in Japan and 11/03/2005 in Europe.
Image
The Nintendo DS Lite (Black edition).
Released on 02/03/2006 in Japan, 11/06/2006 in America and 23/06/2006 in Europe.

Motherboard

Image
Motherboard
Showing first revision.
Image
Motherboard with important parts labelled

Diagram

Image
Main architecture diagram
If you have trouble following the components: Top is only accessed by ARM9, bottom section is ARM7-only, middle section is shared.

A quick introduction

This console is an interesting answer to many needs that weren’t possible to fulfil in the handheld ecosystem. There will be some innovation and a few compromises, but this combination may pave the way for new and ingenious content.


CPU

As with Nintendo’s previous portable console, the system revolves around a big chip named CPU NTR. ‘NTR’ is shorthand for Nitro, the codename of the original Nintendo DS. This SoC is also the continuation of a prosperous Nintendo-ARM partnership, which originally started with the Game Boy Advance.

Now, before we check out the new CPUs, let’s look at how ARM evolved during the late 90s, as this impacted the technology ultimately found inside the Nintendo DS.

ARM’s new territories

During the mid-90s, ARM was experiencing an influx of businesses from the mobile market (before cellphones became ‘smart’). Yet, it struggled to please a particular sector: high-performance computing. The ARM7 was enjoyed by many mobile devices, but it didn’t quite satisfy Apple (with its ‘Newton’ PDA line) and Acorn (with its RiscPC line), both of whom shipped software that could benefit from a faster CPU. Aside from the lack of a 64-bit solution (something MIPS was already commercialising), ARM was also unable to produce a CPU that operated faster than 40 MHz. Altogether, the bottlenecks were starting to pile up.

Nevertheless, during the commercialisation of the ARM7 line, ARM had already started work on a successor called ARM8, in an attempt to please the high-performance market. In the meantime, Digital Equipment Corporation (DEC), the American company historically famous for their line of PDPs (the so-called ‘minicomputers’), was experiencing an opposite problem: They struggled to deliver a low-power CPU based on their high-performance solutions. Well, it so happened that ARM’s licensing model turned into an opportunity for DEC, who chose to develop a new CPU by borrowing materials from ARM (its instruction set and microarchitecture).

In the end, DEC grabbed the datapath design of their Alpha processor and, with the help of ARM, mixed it with ARM’s microarchitecture [1]. This collaboration led to the StrongARM CPU, which was released in 1996 and targeted the performance sector.

Image
A 233 MHz StrongARM CPU, part of the CPU upgrade card offered for the Acorn RiscPC.

StrongARM was a new ARM-based CPU that featured [2]:

It’s worth mentioning that this chip still managed to work with a 3.3 V supply, like previous ARM chips. In fact, the StrongARM only needs 2 Volts [3].

As expected, Acorn and Apple were so dazzled by the new chip that they immediately shipped CPU upgrades and further Newton models, respectively, using DEC’s invention.

In the same year, ARM also released their promised ARM8-based CPU (called ARM810). The latter was comparably slower and offered no practical advantages over the StrongARM. So, too little and too late resulted in no commercial interest. Consequently, ARM moved on to improving the ARM7 line for the mobile market. However, the potential of StrongARM was so disruptive that ARM Holdings absorbed some of StrongARM’s features to produce their next line of CPUs, the ARM9 (which the Nintendo DS houses).

Unfortunately for DEC, this CPU will be their last major achievement before being acquired by Compaq in 1998.

Nintendo’s debuting SoC

Aside from the aforementioned advancements, CPU NTR also bundles an interesting multi-processor architecture using two different ARM CPUs, the ARM7TDMI and the ARM946E-S. This design was done before ARM Holdings officially released multi-processor solutions. So, their functioning may be considered a bit unorthodox (taking into account the present technology available).

Image
The CPU NTR chip.

While this is not the first parallel system analysed for this series, its design is very different from the rest. For instance, we are not talking about the ‘experimental’ master-slave configuration that the Saturn debuted or the ‘co-processor’ approach found on the PS1 or N64. The Nintendo DS includes two very independent computers that will perform exclusive operations, each one having a dedicated bus. This design methodology is called Asymmetric multiprocessing and the resulting CPUs’ co-dependency will condition the overall performance of this console.

Let’s now take a look at the two CPUs:

ARM7TDMI

Image
ARM7 structure and components.

Starting with the more familiar one, the ARM7TDMI is the same CPU found on the Game Boy Advance but now running at ~34 MHz (double its original speed). It still includes all its original features (especially Thumb).

Now for the changes: Because Nintendo’s engineers placed the ARM7 next to most of the I/O ports, this CPU will be tasked with arbitrating and assisting I/O operations. In fact, no other processor can directly connect to the I/O. As you can see, this is not the ‘main’ processor that will be in charge of the system, but rather the ‘sub-processor’ offloading the main CPU by passing data around many components.

ARM946E-S

Image
ARM9 structure and components.

Here is the ‘main’ CPU of the Nintendo DS, the ARM946E-S. It runs at ~67 MHz, so not exactly ‘StrongARM speed’. Yet, being part of the ARM9 series, this core in particular not only inherits all the features of the ARM7TDMI and StrongARM, but also includes some additional bits you may find interesting [4]:

Nintendo also added the following components around it:

I guess with hardware like this, it’s easy to figure out the real reason kids loved this console, eh?

Interconnection

So far I’ve talked about how the two CPUs work individually. But to work as a whole, they are required to cooperate constantly. To accomplish this, both CPUs directly ‘talk’ to each other using a dedicated FIFO unit [5], this block of data holds two 64-byte queues (up to 16 elements) for bi-directional communication.

Image
Representation of FIFO unit.

This works as follows: The ‘sender’ CPU (that effectively needs to send the other a message) places a 32-bit block of data in the queue, and the CPU acting as a ‘receiver’ can then pull that block from the queue and perform the required operations with it.

Whenever there’s a value written on the queue, either CPU can fetch it manually (polling) however, this requires constantly checking for new values (which can be expensive). Alternatively, an interrupt unit can be activated to notify the receiver whenever there’s a new value in the queue.

Main memory

Just like its predecessor, RAM is spread around many different locations, enabling it to prioritise data placement by access rate. In summary, we have the following general-purpose memory available:

Image
RAM model of this console.

Backwards compatibility

Even though the architecture is significantly different from its predecessor, it still managed to maintain the critical bits that would grant it native compatibility with Game Boy Advance games.

But for the DS to revert to an ‘internal’ GBA, the former includes a set of software routines that set the console in AGB Compatibility Mode. In doing so, it effectively halts the ARM9, disables most of the ‘special’ hardware, redirects the buses, puts the ARM7 in charge and slows it down at 16.78 MHz. Finally, the ARM7 proceeds to boot the original AGB BIOS which bootstraps the GamePak cartridge (just like an original Game Boy Advance). This mode still exhibits some features not found in the original console, such as displaying the game with black margins (we’ll see in the next section that the new screen resolution happens to be bigger). Moreover, since the DS has two screens, users can set which screen will be used to display the GBA game.

Once in GBA mode there’s no going back, the console must be reset to re-activate the rest of the hardware.

Unused Power

With so many sophisticated components fitted in a single and inexpensive chip, it’s no mystery that some issues emerged due to the way they were forced to work with each other.

Let me start with the ARM9, this CPU runs at twice the speed of the ARM7, but most (if not all) of the I/O depends on the ARM7. Thus, the ARM9 is vulnerable to excessive stalling until the ARM7 answers. If that wasn’t enough, ARM9’s external bus runs at half the speed, another bottleneck to add to the list.

Additionally, the Main Memory bus is only 16-bit wide. Thus, whenever any CPU needs to fetch a word (32-bit wide) from memory, the interface stalls the CPU, using up to 3 ‘wait’ cycles, until a full word is reconstructed. The worst impact happens when memory access is not sequential, which makes it stall for every single access. This issue will also arise when instructions are fetched (unfortunately, ARM didn’t support sequential opcode fetching back then) which, to my dismay, also affects Thumb code (since every 16-bit fetch is done as a 32-bit block). On the other hand, this ‘penalty’, as some sources call it, can be alleviated by making full use of cache and TCM.

All in all, this means that in the worst case, the ARM9’s whopping 66 MHz horsepower is practically reduced to a mere ~8 MHz. That is if the program makes an abysmal use of cache and TCM.

For a detailed report, I recommend checking out Martin Korth’s document [6], specifically, the ‘DS Memory Timings’ section.


Graphics

This section is a bit unusual because not only this console has multiple screens to draw, but also a combination of traditional tile engines working alongside a modern renderer.

Let’s begin with the physical attributes: The Nintendo DS contains two LCD screens, each one being 256x192 pixels wide, which is ~20% more pixels than the GBA. They can display 262,144 colours (18-bit) and refresh at ~60 Hz.

Architecture

The graphics subsystem can draw 2D and 3D objects. The former is composed of two-dimensional geometry that is filled with bitmaps of 8x8 pixels wide (called ‘tiles’), while the latter draws three-dimensional objects (polygons) using vertices.

Diving into the internal chip that operates those screens, we can observe this console has distinctive hardware for 2D and 3D geometry. The 2D data is operated by a familiar engine, the PPU (now just called 2D engine), while 3D data is handled by a completely new subsystem. It’s worth mentioning that while this is not the first console to debut 3D graphics, it’s still the first one to include an in-house design to render 3D graphics.

Image
Layout of the different graphic units.

Now, these engines must be linked to either screen, this is not an issue for 2D-only games since there’s one 2D engine for each screen. However, for those games who want to show off cutting-the-edge features, there’s only one 3D engine available. As a consequence, 3D capabilities are only available on one screen at a time. But what about mixing 2D and 3D objects? Absolutely, let me explain each engine separately so we can discuss this afterwards.

Constructing a frame with 2D graphics

Before we review each stage, I recommend reading a previous article about the GBA’s PPU since here I’ll just mention the changes that construct the ‘next-gen’ of 2D games. Also, since there are two engines, the first one is named Main while the second one is called Sub. This doesn’t necessarily imply which screen is each one connected to. On the other side, ‘Main’ contains a bit more functions than ‘Sub’.

To help the explanations, this time I’m going to borrow the assets of New Super Mario Bros.

Tiles

Image
Some tiles found in VRAM. For demonstration purposes, a default palette is used.

By now we all know how a basic tile system works, but how are tiles particularly managed in this console? Well, there’s a total of 656 KB of VRAM available, and this chunk is split into different banks: Four 128 KB, one 64 KB, one 32 KB and three 16 KB. Programmers are free to fill the banks with drawings and then point the engine where the required data is. Both engines can read from any of these banks, but they can’t access the same one concurrently.

Nonetheless, there are some limitations on how data can be distributed. For instance, the ARM7 can only access two 128 KB banks. At the same time, these two banks can’t store sprites, and ‘sub’ is the only one capable of accessing the last 16 KB bank. The list goes on… but you get the idea.

One last thing, the 3D engine, which we will discuss later on, will access some of these banks to fetch textures.

Background types

Since the days of the Super Nintendo, the PPU has been leaning towards providing more flexibility for building background layers. 14 years later, we found ourselves with a chip that can fetch tiles and apply many affine transformations and if that wasn’t enough, the layer can be ultimately built from a frame buffer.

Before we discuss the different modes the 2D engine can operate to generate backgrounds, let me show you this list which specifies the types of backgrounds the engine can generate:

These modes can’t be chosen arbitrarily, instead, the console provides a series of background modes with different combinations set. Nevertheless, you can see here that the Affine Extended mode is available in three different flavours (‘Character’, ‘256 colours’ and ‘Direct colour’). So, in the next section, when you see that X background mode supports the ‘Affine Extended’ type, developers can choose which variant they want.

Background modes

Image
Background Layer 0 (BG0). This particular layer will be shifted horizontally at certain scan lines to simulate the clouds moving.
Image
Background Layer 2 (BG2).
Image
Background Layer 3 (BG3).
Static Background layers in use.

Here the background types are put into action. ‘Main’ and ‘Sub’ provide multiple modes of operation. All of them generate four background layers, however, each layer will have different capabilities depending on the mode activated:

Additionally, in Mode 0 to 5, the ‘Main’ engine can use the first static layer as a 3D background instead. The 3D capabilities will be discussed later on.

Sprites

Image
Rendered Sprite layer.

Sprites or ‘Objects’ inherit the same functionality from the GBA’s PPU, but we have two considerable additions.

Firstly, OAM (the region where sprites entries are stored) is now 2 KB wide, enabling to display up to 128 sprites per frame per screen. Thus, 1 KB is allocated per engine.

Secondly, OAM can now reference bitmaps from VRAM as opposed to only using tiles and palettes. This is another departure from the tiling system. In fact, both sprite ‘modes’ can coexist in the same frame, since this option is set on each individual sprite.

Result

Image
All layers merged… is there something missing?

As each layer renders on-the-fly, the final stage is tasked with merging everything and sending it to the selected screen. This is pretty much what happens with previous PPU-based consoles, does that mean we are done here?

Not yet! ‘Main’ still has to fetch a layer from another engine, the most powerful one.

The 3D accelerator

If you played with a Nintendo DS before, you know by now that this console can display a particular amount of 3D graphics. Unlike some GBA games, these aren’t processed by the CPU. Instead, CPU-NTR includes two components that compose the 3D engine. Curiously enough, the design Nintendo applied reminds me of SGI’s RCP.

Revisiting the ‘Background modes’ section, you’ll notice every mode has at least one static background, this is because you can fill that layer with graphics produced by the 3D engine. The only caveat is that only the ‘Main’ can do this, hence one of the reasons Mode 6 is only available for ‘Main’.

Geometry Engine

Image
Architecture of the Geometry Engine.

If you read any of the articles from the 4th or 5th generation, you may be wondering… Where’s the SIMD processor? That’s a good question because the ARM9 is not particularly good at vector operations and I don’t think the dedicated divider is enough. That’s why Nintendo embedded a component called Geometry Engine that takes care of vertex transformations, projection, lighting, clipping, culling and polygon sorting, the latter is essential to properly use the transparency features.

This engine has some strict limitations, specifically the count of polygons it can process: There’s an extra 248 KB of RAM available used to store processed geometry, this amount accounts for up to 2048 triangles or 1706 quadrilaterals, although this limit is reduced by using polygon strips (as opposed to individual polys). To get a sense of this number, I suggest checking out the ‘interactive models’ sections in previous articles, you’ll see that it’s a concerning constraint, but don’t forget that the screen resolution of this console is also much smaller… so that compensates a bit.

Anyway, this engine is commanded using a Command FIFO which is filled with data from the CPU or DMA. The FIFO stores 256 entries, yet it’s complemented by another buffer called PIPE that stores four more commands (giving a total of 260).

Rendering Engine

Image
The architecture of the Rendering Engine.

The rendering engine is in charge of converting vectors to pixels (rasterising), colouring them (texture mapping) and applying lighting and other effects. It relies on perspective correction and Gouraud shading for interpolating textures and light, respectively. Moreover, the unit provides modern features like fog, alpha blending, depth buffering (either Z-buffering or a variant called W-buffering), stencil tests and anti-aliasing. However, the latter is very primitive (it just sets the outer edges of polygons as transparent) and it only works with opaque pixels.

The rendering system is a mix of old and new: Instead of rendering to a frame buffer, it employs line buffer rendering, where it fills scan lines (similarly to the 2D engine) and stores the results in a smaller buffer. This is because the 3D engine must work at pace with the 2D drawer.

Without the traditional frame buffer, the rasteriser employs scan-line rendering, traversing each scan-line to process polygon edges found within. Arisotura (the developer of MelonDS emulator) reported that for each quadrangle, the renderer can only fill one span per scan-line [7]. This can be a bit troubling, since the result will get messy if the quad is concave or has crossed edges, for instance.

Regarding effects, the unit also provides shadowing and a distinct feature called Toon Shading (another name for Cel Shading): Even though this unit is not programmable, the lighting parameters can be altered to achieve a cartoony effect.

Result

Image
Ah, that’s more like it.

Instead of writing the results back to a frame buffer for display, the rendering engine will write to a block called Colour Buffer which stores up to 48 scan lines. Each scan line is fetched by the 2D engine to fill the BG0 layer in a FIFO manner.

3D rendering starts before the 2D one, enabling the latter to apply transformations on the new layer if required. ‘Main’ also allows to capture the 2D, 3D or combined frame generated, blend it with another frame in VRAM and write the result back to VRAM, which can be displayed afterwards.

In terms of control, the rendering engine also allows altering its parameters during mid-frame, due to employing a mechanism based on double-buffering that keeps a copy of the old state until the current frame finishes being drawn. Thus, no tearing will appear.

Famous comparisons

Some of the first games released for this console attempt to resemble the ones from another console (namely, the Nintendo 64). So I wanted to give a quick summary of why players may see some substantial differences between the two versions:

First example

Image
Super Mario 64 (1996).
Rendered at 320×240 pixels.
Image
Super Mario 64 DS (2004).
Rendered at 256x192 pixels.

Second example

Image
Mario Kart 64 (1996).
Rendered at 320×240 pixels.
Image
Mario Kart DS (2005).
Rendered at 256x192 pixels.

So, to explain what’s happening here, I’ve organised the different explanations based on what some people said on forums:

That’s pretty much in a nutshell, for more specialised cases, you’ll have to dive deeper into both engines and possibly disassemble both games to investigate which functions are being used and how.

Interactive models

I’ve updated the wee model viewer to apply ‘nearest neighbour’, allowing you to visualise Nintendo DS models using your GPU.

Image Image Image Interactive model available in the modern edition
Nintendogs (2005).
750 triangles.
Image Image Image Interactive model available in the modern edition
New Super Mario Bros (2006).
636 triangles.

Despite the fact we talked about a lot of limitations of the graphics subsystem, lots of games did make really good use of it.


Audio

Most of the audio improvements focus on enhancing those PCM channels that the GBA featured. We’ve seen before that GBA games ultimately prioritised software sequencing over the PSG, and the result was quite impressive.

Last Window: The Secret of Cape West (2010). Showing mixed stereo output.

Consequently, the new audio system features a total of 16 PCM channels, allowing to shift the mixing task to the hardware. PCM samples can either be 8-bit (GBA-style), 16-bit (optimal resolution) or ACPCM (compressed form). In any case, the mixer produces a stereo signal that can be played through the speaker (now stereo) or headphones. It can also write the resulting stereo data to WRAM, enabling the sub-processor (ARM7) to apply some effects such as reverb.

With all being said, does this mean that the Nintendo DS can finally play encoded music (i.e. MP3)? It’s possible (in fact, a lot of homebrew programs implemented some form of it), but audio decoding takes up a lot of bandwidth and processing power [8]. So, audio sequencing still retains its place as the most feasible option.

An eccentric PSG (or two)

Since this console runs GBA games, it should then have something that reassembles the predecessor’s PSG (whether through hardware or software). Well, it so happens the last 6 channels contain a ‘PSG mode’ allowing any of them to synthesise either a pulse or a custom wave; and only two of them can create noise. But GBA games don’t use any of these!

You see, the mixer’s output frequency rate is 32 kHz with a resolution of 10-bit (considerably lower than the quality of the samples fed). Furthermore, it does not perform any form of interpolation to smooth out the loss of precision. These restrictions are not ideal for samples, as it adds noise. Though the actual perception of this phenomenon depends on your auditory capacity (I don’t notice the ‘hiss’ unless I boost the volume and compare it with a 16-bit version side-by-side), besides, it’s still a step forward coming from software-mixed samples with 8-bit resolution. Conversely, the aliasing effect is more problematic with PSG sounds, as downsampling the signal may introduce erroneous harmonics which distorts the original PSG tone. Nevertheless, games like New Super Mario Bros. happily make use of pulse waves for accompaniment, so I wouldn’t consider the PSG completely useless.

Back on topic, how does a GBA game handle all of this? It doesn’t, Nintendo fitted a separate sound system (within the same enclosure) for GBA mode that includes its own channels and mixer that follows the specifications of the predecessor. This way, GBA games won’t be affected by the new mixer’s limitations. Unfortunately, since this subsystem is segregated from the DS one (in other words, it doesn’t output to the DS’s mixer), DS games aren’t able to use it.

Interactive comparison

I’ve constructed this interactive widget that will allow you to compare how the new audio system affected the new generation of soundtracks. Each widget plays the same score but allows you to alternate between the old and new arrangements (I suggest wearing headphones to really notice the difference). Give it a whirl!

Interactive player available in the modern edition
Audio samples
GBA: Gyakuten Saiban (2001, JAP only).
NDS: Phoenix Wright: Ace Attorney (2005).
Interactive player available in the modern edition
Audio samples
GBA: Mario Kart: Super Circuit (2001).
NDS: Mario Kart DS (2005).

(If you have trouble listening to it, please contact me mentioning the browser and device you are using)

Be as it may, I had to boost the gain of the GBA soundtrack a little bit to normalise the loudness, which tends to affect the signal-to-noise ratio (just something to bear in mind while you switch between the two). Anyway, I hope you got a sense of how the sound subsystem has evolved.

Some struggles

Let me show you some tricky cases now, where the original console had some unique audio features that weren’t straightforward to recreate for this console, but I’ll let you be the judge of that:

Interactive player available in the modern edition
Audio samples
SNES: Super Mario Kart (1992).
NDS: Mario Kart DS (2005).
Interactive player available in the modern edition
Audio samples
Mega Drive: Sonic 3D Blast (1996).
NDS: Sonic Chronicles (2008).

As you can hear from the first example (especially in the last 10 seconds), it’s a bit hard to compete with the features that the SNES’ S-SMP provided.

I must confess the second one was put on purpose, I mean, what the freck happened there right? As if the new arrangement were initially done for an Atari console instead. If you ask me, I think the Nintendo DS could have handled some sort of FM to PCM re-sampling, so the new minimalistic arrangement may just be a creative approach.


I/O

To make a long story short, I/O is strictly handled by the ARM7. In fact, you won’t see much going on with that CPU apart from passing data around… which is too bad really.

Accessing cartridges and memory

There’s an external memory interface connecting three endpoints: Slot-1 (where Nintendo DS cards go), Slot-2 (where GBA cartridges or accessories go) and the 4 MB of PSRAM (Main memory). The interface can be accessed by both CPUs, but it contains registers that can be modified to prioritise one CPU over the other in case there are two requests from the same bus at the same time.

Image
External memory model with labelled data bus width.

Now, here’s the important bit: DS cards are not memory-mapped, so for either CPU to read game data, the content must be copied to RAM first. This is done by sending to the cartridge blocks of 8-bit commands referencing 32-bit addresses. Afterwards, the data can be manually retrieved by pulling it from a 32-bit register or through DMA. The data bus is 8-bit wide but can reach speeds of up to 5.96 MB/sec (as claimed by Nintendo).

The ‘backup’ chip used for saves (i.e. EEPROM, FLASH or FRAM) is accessed through an SPI bus (serial) which uses its own set of commands and it’s connected to a 24-bit address bus.

The Slot-2 cartridge is memory-mapped using the original pinout, but the addresses are shifted in DS mode to accommodate the hardware that provides expansion functionality (extra RAM, rumble, etc). Just like the GBA, the ROM bus is 16-bit wide and the RAM bus is 8-bit wide.

Peripherals

The ARM7 is also connected to another SPI node interfacing the TouchScreen controller, which operates the bottom screen (it’s the resistive type, requiring the use of a stylus); and the flash memory (which is where the firmware is stored, more details later on).

Image
Hotel Dusk: Room 215 (2007) showing the aforementioned switchboard puzzle. To rescue the lassie, the player had to swipe the screen using two fingers at the same time to switch on the lights.
Image
But if you do it wrong…

A curious thing about this touchscreen is that apart from detecting the X/Y positions, it can also return the diagonal position (used to calculate the ‘pressure value’, which represents the area where pressure is being applied). Unfortunately, this was never exposed in the official SDK, so as far as I know, no game ended up using this undocumented feature (except homebrew).

Many have pointed out that ‘Hotel Dusk: Room 215’ relied on this feature for one of its puzzles, which required users to use two fingers at the same time. This is not the case, however. After experimenting with the no$gba debugger, the puzzle does not make use of pressure data. Instead, it checks whether the x/y values alternate drastically. The game interprets this effect as if the user had pressed the screen with two fingers.

Finally, in the same stack, we find the real-time clock or ‘RTC’.

Wireless network

Last but not least, the console contains a Wireless controller operating in the 2.4 GHz band that provides some innovative features:


Operating System

I guess it’s safe to say that by this generation every console now comes bundled with some sort of interactive interface. The NDS still inherits the previous operating system model consisting in lightweight APIs to simplify I/O access, but also provides a minimal user interface to tweak some settings and fiddle with some of its ‘apps’.

Having said that, its operating system is diversified into multiple chips, so let’s start with the ones that are read upon boot.

Entry point

At some point, the ARM7 and ARM9 will need to initialise the hardware and to do this, NTR-CPU includes two different small ROM chips:

When the console starts up, each CPU boots from its respective ROM. This is because their reset vector points to each chip (for reference, ARM9’s vector is at 0xFFFF0000 while ARM7’s one is 0x00000000) [9].

Moving forward, each BIOS stores two sets of routines: Boot code and interrupt calls. The latter is no stranger giving the history of the previous console, however the former has increased in complexity: Apart from initialising the hardware, ARM7’s code will also handle security by running some checks on the DS cartridge (if there is one inserted).

After running the boot code, both CPUs will synchronise so they can start acting as a ‘single machine’: It turns out the ARM9 finishes loading way before the ARM7, so the ARM9 sends a 4-bit value to the ARM7, stalls on a semi-endless loop waiting for the ARM7 to respond and once it does, both ‘cross the finish line’ at the same time, that is to say, they are now in-sync.

Window of opportunity

If you have or had a DS, you probably noticed you can only play games if the cartridge was inserted before turning on the console. This is because the ARM7’s BIOS carries out some checks on the cartridge during boot (more details in the last section) and if all the tests pass, ARM7’s game executable is copied to WRAM and ARM9’s one is copied to Main Memory.

If for some reason the executables are not copied (due to the cartridge not being valid or not found during boot), then the game can’t be started and the user will have to reset the console to play one.

Interactive shell

Whether there’s a game or not, the system will finish booting by loading an interactive shell. This is just a program that resides on an external 256 KB Flash memory [10].

Image
Home screen.
Image
You see this screen every time you switch the DS on. The ‘Nintendo’ logo appears when there is a valid card inserted.
Image
Settings screen.

The same chip stores the firmware along with some user settings (language, nickname, birthday, alarm and a welcome message) and some system settings (touchscreen calibration, first startup flag, firmware version and Wi-Fi settings).

The shell is more-or-less the same as the rest of its contemporaries. Users rely on it to start their game, change settings, download a game (using ‘Download Play’) or fiddle with Pictochat: an open chat room that talks with nearby Nintendo DSes.

It’s worth emphasising that both read-only and writable data reside in the same re-writable chip, so it’s theoretically possible to write over the firmware! Luckily (or for obvious reasons), Nintendo protected the upper quarter of the chip (64 KB) from being written by requiring a jumper placed on a point in the motherboard called SL1, which is exposed by removing the battery compartment. Nonetheless, over-writing the rest of the flash memory can still produce catastrophic results [11]!

Updatability

Lastly, this firmware ended up being updated by Nintendo a couple of times (5 to be precise) in an effort to patch some security vulnerabilities. The updates weren’t installable by the user (recall the SL1 protection). Instead, Nintendo embedded the updated firmware in the next lot manufactured.


Games

Oh, there’s a lot to talk about here, primarily because the capabilities of this console did inspire a lot of programmers and artists to come up with really innovative designs. Let’s see…

Medium

This console runs games from three sources, where only two of them can make ‘full’ utilisation of the hardware:

Image
Example of a retail game.

Program structure

You’ve seen that the BIOS requires to be split up with separate code for ARM9 and ARM7, this is pretty much what also happens with games. Thus, NDS cards are structured in the following areas:

Development ecosystem

For game studios interested in developing games for this console, Nintendo distributed both hardware kits and SDKs with lots of utilities.

The hardware

The devkit, called IS-NITRO-EMULATOR, consisted of a medium-size blue box containing most of the DS’s internal hardware and I/O [12]. This is followed by a thick cable connected to a dummy Nintendo DS case, serving as a ‘controller’ and display. At request, the devkit was enhanced with optional capabilities like audio/video out, Wi-Fi (by default it was emulated using Ethernet) and debugging. I was expecting the latter to be already included but I realised these units could also be used by test teams.

The kit reads DS cards, but a different type with a larger case and swappable backup chips. These cards are flashed using another unit called IS-NITRO-WRITER.

The software

The software kit included utilities for interacting with the devkit, the C/C++ toolchains and the hardware APIs. One point to mention is that the docs are explicit in forbidding any circumvention of their APIs to access the hardware directly: Even though games will run on bare metal, Nintendo won’t approve their distribution if it executes ‘prohibited’ operations. This includes controlling the ARM7 directly, exceeding display resolution or turning off the LCDs.

There are understandable reasons for imposing these norms, such as maintaining quality levels. Although, in my opinion, limiting the ARM7 to I/O tasks was a waste of potential…

Freedom of interaction

Image
Dr Kawashima’s Brain Training (2005).
New categories of games attracted audiences beyond the youth circle.

With all the new forms of interaction available, studios had the opportunity to prioritise gameplay experience over graphics.

For the first time in consumer electronics, there was a touchscreen, microphone, Wi-Fi and a real-time clock packaged in the same console. Nevertheless, some games even presented new forms of interaction, such as instructing the user to hold the console sideways.

Network service

After the success of a previous competitor, Nintendo joined the club of online multiplayer and deployed their centralised infrastructure. Games using the ‘Internet Play’ could connect to Nintendo’s servers (called Nintendo Wi-Fi Connection) to enjoy some online gaming.


Anti-Piracy and Homebrew

Even though DS cards weren’t affected by the curse of the compact disc, Nintendo implemented some protection systems to keep control of game distribution.

Security Mechanisms

Let’s take a look at each area:

Encryption system

The Nintendo DS mainly uses a symmetric encryption system to encrypt the communication between the Memory Interface and the Slot-1 card. Before we discuss how encryption is performed, let’s talk about the algorithms used and how the keys (which will be used to perform encryption) are generated.

The ‘Header’ area of the card contains a value called Gamecode (the unique identifier of the game), the memory interface grabs this block to generate the KEY1 and uses it to encrypt further commands sent to the card. KEY1 encryption is based on the Blowfish algorithm.

Afterwards, KEY1 is mixed with the internal clock and some other values of the cartridge header to generate a new key called KEY2. The fundamental difference with KEY1 is that the former uses random values to make it unpredictable. KEY2 encryption relies on multiple XOR and Shift operations to obfuscate the data.

KEY1 and KEY2 are used, at different stages, by the Slot-1 interface to protect its communication with the card. While KEY1 is also used by the ARM7 BIOS to validate the DS card and initialise the card interface.

DS card validation

As we’ve seen before, the BIOS includes some routines that validate the NDS card upon startup. This works as follows:

  1. The ARM7 BIOS retrieves the chip ID of the cartridge, saves it on RAM and then proceeds to enable KEY1 encryption.
  2. The first 2 KB of the ‘Secure area’ are copied to RAM as well. The first 8 B of this chunk stores a string called Secure Area ID, the next values contain some checksums (CRC16 type) and other metadata. All of it comes encrypted with KEY1, and the Secure Area ID is encrypted twice with KEY1 using different parameters.
  3. The ARM7 BIOS decrypts the Secure Area ID and checks that the decrypted value matches encryObj. If it does, it means card validation passed the first test. After this, the string is destroyed to prevent revealing the algorithm. If the validation fails, the 2 KB of Secure Area are filled with garbage, preventing the rest of the card from being read.
  4. At this point, the cartridge interface is setup with KEY2. The second test consists of retrieving the chip ID again at random times (the seed depends on the internal clock). If the value of chip ID matches the first chip ID stored, the second test passes.
  5. Finally, the rest of the Secure area is fetched in random order and re-constructed in RAM. After this, the firmware is executed.

If everything goes well, the firmware will find the required executable of the card in RAM, allowing the user to boot up the game. Otherwise, the game selector will be shown greyed out.

Download Play protection

Programs received via Download Play must be signed by Nintendo using an RSA signature (only Nintendo knows the private key).

This check is performed by the firmware.

Defeat

If you were a homebrew user back then you probably ran across tons of options available to run this software. The truth is, before all the current cracks were discovered, hackers had a hard time circumventing Nintendo’s complex anti-piracy system.

Existing Slot-2

Because the GBA subsystem still executes cartridges without any protection implemented (aside from trademark tricks), existing GBA flashcarts were still compatible with the NDS. This enabled to run GBA homebrew, which worked fine if you didn’t mind missing out on all the new functionality exclusive to DS games.

As always, flash cartridges also enabled to run pirated ROMs, but since Nintendo couldn’t change the protection system of the GBA (as it could potentially render existing games unusable), the company just had to deal with it.

Enhanced Slot-2

After more clandestine research was conducted on the DS BIOS and firmware, it was ultimately discovered that the execution of an NDS card could be redirected to the GBA slot. The NDS card wasn’t cracked yet, but this method allowed to provisionally bypass the security system of Slot-1 cards and execute Slot-2 programs in DS mode.

Thus, a new generation of Slot-2 flashcarts appeared on the market. They embed ARM9 code that is executed once bootstrapped from Slot-1. The bootstrap itself was accomplished using one of these methods discovered (called ‘pass-through methods’):

As expected, Nintendo produced DS revisions that included an updated firmware that patched these tricks. So hackers tried to find other methods that focused on more BIOS exploitation (which is difficult to patch).

Native Slot-1

Martin Korth, the developer of the famous Nintendo DS emulator called ‘NO$GBA’, later managed to extract the BIOS and reverse engineer the Slot-1 security. With this, newer tools and documentation revealed the true mechanisms of Nintendo DS security. As you have seen in this article, the encryption system worked as long as nobody reversed it (this is a limitation of symmetric encryption systems, unlike asymmetric encryption systems, such as RSA where the private key is never stored).

Anyway, these led to a massive influx of plug-and-play Slot-1 flashcards which worked on any type of console and ran Nintendo DS programs natively. The pass-through method was also improved with the debut of ‘NoPass’ cards which allowed to load Slot-2 flashcarts without requiring a genuine game.

Since the encryption system couldn’t be altered without making breaking changes that affect all existing retail games, Nintendo ultimately lost this battle. The only thing left was to pursue the legal route, just like they did with their previous console.

Observations

This is my personal opinion, but it’s really striking how simple are flashcards compared to other homebrew methods from previous consoles. In older articles, I’ve described that if users ultimately wanted to run homebrew programs or pirated games, they would have to get down in the rabbit hole and follow some sort of complicated method.

In the case of the DS, flashcards were literally sold just like retail games, and I bet it was truly concerning for game studios to see how painless was to resort to piracy.

Another thing, it’s also surprising the amount of branded flashcards (aside from all knock-offs) that appeared on the market. If you look at it from a technical perspective, flashcards are just SD adapters [14]. The only thing that differentiates one card from another is the boot code and SD reader. Some manufacturers also took more effort to design a better file browser (referred to as kernel/firmware) and include some additional hardware.


That’s all folks

Image
My current DS used for this study.
I actually sold my first one a long time ago… I wonder where it’s now.

Alrighty! I think I covered 99% of what I wanted to talk about…

I hope I didn’t sound too harsh when criticising some sections. Don’t get me wrong, I still think this console is a good piece of engineering! But there are some defects which make me wonder if it’s really a cost-effective compromise, or part of a design flaw. Truth to be told, that didn’t stop 11-year-old me from wanting one back then. So I guess that’s pretty much ‘mission accomplished’ for the company!

I would also like to thank friends and the MelonDS community for taking the time to check out the draft and pointing out lots of corrections. The Nintendo DS allowed me to mention many topics I’ve been interested in writing about for a while and I was afraid I would end up biting off more than I could chew, but hopefully you’ve enjoyed this article.

Until next time!
Rodrigo


Contributing

This article is part of the Architecture of Consoles series. If you found it interesting then please consider donating. Your contribution will be used to fund the purchase of tools and resources that will help me to improve the quality of existing articles and upcoming ones.

Donate with PayPal
Become a Patreon

You can also buy the eBook edition in English. I treat profits as donations.

Image

Big thanks to the following people for their donation:

Alternatively, you can help out by suggesting changes and/or adding translations.


Copyright and permissions

This work is licensed under a Creative Commons Attribution 4.0 International License. You may use it for your work at no cost, even for commercial purposes. But you have to respect the license and reference the article properly. Please take a look at the following guidelines and permissions:

Article information and referencing

For any referencing style, you can use the following information:

For instance, to use with BibTeX:

@misc{copetti-nintendods,
    url = {https://classic.copetti.org/writings/consoles/nintendo-ds/},
    title = {Nintendo DS Architecture - A Practical Analysis},
    author = {Rodrigo Copetti},
    year = {2020}
}

or a IEEE style citation:

[1]R. Copetti, "Nintendo DS Architecture - A Practical Analysis", Copetti.org, 2020. [Online]. Available: https://classic.copetti.org/writings/consoles/nintendo-ds/. [Accessed: day- month- year].

Special use in multimedia (Youtube, Twitch, etc)

I only ask that you at least state the author’s name, the title of the article and the URL of the article, using any style of choice.

You don’t have to include all the information in the same place if it’s not feasible. For instance, if you use the article’s imagery in a Youtube video, you may state either the author’s name or URL of the article at the bottom of the image, and then include the complete reference in the video description. In other words, for any resource used from this website, let your viewers know where it originates from.

This is a very nice example because the channel shows this website directly and their viewers know where to find it. In fact, I was so impressed with their content and commentary that I gave them an interview 🙂.

Appreciated additions

If this article has significantly contributed to your work, I would appreciate it if you could dedicate an acknowledgement section, just like I do with the people and communities that helped me.

This is of course optional and beyond the requirements of the CC license, but I think it’s a nice detail that makes us, the random authors on the net, feel part of something bigger.

Third-party publishing

If you are interested in publishing this article on a third-party website, please get in touch.

If you have translated an article and wish to publish it on a third-party website, I tend to be open about it, but please contact me first.


Sources / Keep Reading

Anti-Piracy

CPU

Games

Graphics

Operating System

Photography


Changelog

It's always nice to keep a record of changes.

2024-01-08

2022-01-12

2020-08-25

2020-08-24

2020-08-19

2020-08-12