mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 19:41:30 +11:00
320 lines
20 KiB
HTML
320 lines
20 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="sidebar-visible no-js">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>Direct Memory Access - Rust GBA Guide</title>
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
<meta name="description" content="">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff" />
|
|
|
|
<link rel="shortcut icon" href="../favicon.png">
|
|
<link rel="stylesheet" href="../css/variables.css">
|
|
<link rel="stylesheet" href="../css/general.css">
|
|
<link rel="stylesheet" href="../css/chrome.css">
|
|
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
|
|
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" href="../highlight.css">
|
|
<link rel="stylesheet" href="../tomorrow-night.css">
|
|
<link rel="stylesheet" href="../ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
|
|
</head>
|
|
<body class="light">
|
|
<!-- Provide site root to javascript -->
|
|
<script type="text/javascript">var path_to_root = "../";</script>
|
|
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script type="text/javascript">
|
|
try {
|
|
var theme = localStorage.getItem('mdbook-theme');
|
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script type="text/javascript">
|
|
var theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = 'light'; }
|
|
document.body.className = theme;
|
|
document.querySelector('html').className = theme + ' js';
|
|
</script>
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script type="text/javascript">
|
|
var html = document.querySelector('html');
|
|
var sidebar = 'hidden';
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
}
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<ol class="chapter"><li><a href="../00-introduction/00-index.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li><a href="../00-introduction/01-requirements.html"><strong aria-hidden="true">1.1.</strong> Reader Requirements</a></li><li><a href="../00-introduction/02-goals_and_style.html"><strong aria-hidden="true">1.2.</strong> Book Goals and Style</a></li><li><a href="../00-introduction/03-development-setup.html"><strong aria-hidden="true">1.3.</strong> Development Setup</a></li><li><a href="../00-introduction/04-hello-magic.html"><strong aria-hidden="true">1.4.</strong> Hello, Magic</a></li><li><a href="../00-introduction/05-help_and_resources.html"><strong aria-hidden="true">1.5.</strong> Help and Resources</a></li></ol></li><li><a href="../01-quirks/00-index.html"><strong aria-hidden="true">2.</strong> Quirks</a></li><li><ol class="section"><li><a href="../01-quirks/01-no_std.html"><strong aria-hidden="true">2.1.</strong> No Std</a></li><li><a href="../01-quirks/02-fixed_only.html"><strong aria-hidden="true">2.2.</strong> Fixed Only</a></li><li><a href="../01-quirks/03-volatile_destination.html"><strong aria-hidden="true">2.3.</strong> Volatile Destination</a></li><li><a href="../01-quirks/04-newtype.html"><strong aria-hidden="true">2.4.</strong> Newtype</a></li><li><a href="../01-quirks/05-const_asserts.html"><strong aria-hidden="true">2.5.</strong> Const Asserts</a></li></ol></li><li><a href="../02-concepts/00-index.html"><strong aria-hidden="true">3.</strong> Concepts</a></li><li><ol class="section"><li><a href="../02-concepts/01-cpu.html"><strong aria-hidden="true">3.1.</strong> CPU</a></li><li><a href="../02-concepts/02-bios.html"><strong aria-hidden="true">3.2.</strong> BIOS</a></li><li><a href="../02-concepts/03-wram.html"><strong aria-hidden="true">3.3.</strong> Work RAM</a></li><li><a href="../02-concepts/04-io-registers.html"><strong aria-hidden="true">3.4.</strong> IO Registers</a></li><li><a href="../02-concepts/05-palram.html"><strong aria-hidden="true">3.5.</strong> Palette RAM</a></li><li><a href="../02-concepts/06-vram.html"><strong aria-hidden="true">3.6.</strong> Video RAM</a></li><li><a href="../02-concepts/07-oam.html"><strong aria-hidden="true">3.7.</strong> Object Attribute Memory</a></li><li><a href="../02-concepts/08-rom.html"><strong aria-hidden="true">3.8.</strong> Game Pak ROM / Flash ROM</a></li><li><a href="../02-concepts/09-sram.html"><strong aria-hidden="true">3.9.</strong> Save RAM</a></li></ol></li><li><a href="../03-video/00-index.html"><strong aria-hidden="true">4.</strong> Video</a></li><li><ol class="section"><li><a href="../03-video/01-rgb15.html"><strong aria-hidden="true">4.1.</strong> RBG15 Color</a></li><li><a href="../03-video/TODO.html"><strong aria-hidden="true">4.2.</strong> TODO</a></li></ol></li><li><a href="../04-non-video/00-index.html"><strong aria-hidden="true">5.</strong> Non-Video</a></li><li><ol class="section"><li><a href="../04-non-video/01-buttons.html"><strong aria-hidden="true">5.1.</strong> Buttons</a></li><li><a href="../04-non-video/02-timers.html"><strong aria-hidden="true">5.2.</strong> Timers</a></li><li><a href="../04-non-video/03-dma.html" class="active"><strong aria-hidden="true">5.3.</strong> Direct Memory Access</a></li><li><a href="../04-non-video/04-sound.html"><strong aria-hidden="true">5.4.</strong> Sound</a></li><li><a href="../04-non-video/05-interrupts.html"><strong aria-hidden="true">5.5.</strong> Interrupts</a></li><li><a href="../04-non-video/06-link_cable.html"><strong aria-hidden="true">5.6.</strong> Link Cable</a></li><li><a href="../04-non-video/07-game_pak.html"><strong aria-hidden="true">5.7.</strong> Game Pak</a></li></ol></li><li><a href="../05-examples/00-index.html"><strong aria-hidden="true">6.</strong> Examples</a></li></ol>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
|
|
<div id="menu-bar" class="menu-bar">
|
|
<div id="menu-bar-sticky-container">
|
|
<div class="left-buttons">
|
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</button>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<h1 class="menu-title">Rust GBA Guide</h1>
|
|
|
|
<div class="right-buttons">
|
|
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script type="text/javascript">
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<a class="header" href="#direct-memory-access" id="direct-memory-access"><h1>Direct Memory Access</h1></a>
|
|
<p>The GBA has four Direct Memory Access (DMA) units that can be utilized. They're
|
|
mostly the same in terms of overall operation, but each unit has special rules
|
|
that make it better suited to a particular task.</p>
|
|
<p><strong>Please Note:</strong> TONC and GBATEK have slightly different concepts of how a DMA
|
|
unit's registers should be viewed. I've chosen to go by what GBATEK uses.</p>
|
|
<a class="header" href="#general-dma" id="general-dma"><h2>General DMA</h2></a>
|
|
<p>A single DMA unit is controlled through four different IO Registers.</p>
|
|
<ul>
|
|
<li><strong>Source:</strong> (<code>DMAxSAD</code>, read only) A <code>*const</code> pointer that the DMA reads from.</li>
|
|
<li><strong>Destination:</strong> (<code>DMAxDAD</code>, read only) A <code>*mut</code> pointer that the DMA writes
|
|
to.</li>
|
|
<li><strong>Count:</strong> (<code>DMAxCNT_L</code>, read only) How many transfers to perform.</li>
|
|
<li><strong>Control:</strong> (<code>DMAxCNT_H</code>, read/write) A register full of bit-flags that
|
|
controls all sorts of details.</li>
|
|
</ul>
|
|
<p>Here, the <code>x</code> is replaced with 0 through 3 when utilizing whichever particular
|
|
DMA unit.</p>
|
|
<a class="header" href="#source-address" id="source-address"><h3>Source Address</h3></a>
|
|
<p>This is either a <code>u32</code> or <code>u16</code> address depending on the unit's assigned
|
|
transfer mode (see Control). The address MUST be aligned.</p>
|
|
<p>With DMA0 the source must be internal memory. With other DMA units the source
|
|
can be any non-<code>SRAM</code> location.</p>
|
|
<a class="header" href="#destination-address" id="destination-address"><h3>Destination Address</h3></a>
|
|
<p>As with the Source, this is either a <code>u32</code> or <code>u16</code> address depending on the
|
|
unit's assigned transfer mode (see Control). The address MUST be aligned.</p>
|
|
<p>With DMA0/1/2 the destination must be internal memory. With DMA3 the destination
|
|
can be any non-<code>SRAM</code> memory (allowing writes into Game Pak ROM / FlashROM,
|
|
assuming that your Game Pak hardware supports that).</p>
|
|
<a class="header" href="#count" id="count"><h3>Count</h3></a>
|
|
<p>This is a <code>u16</code> that says how many transfers (<code>u16</code> or <code>u32</code>) to make.</p>
|
|
<p>DMA0/1/2 will only actually accept a 14-bit value, while DMA3 will accept a full
|
|
16-bit value. A value of 0 instead acts as if you'd used the <em>maximum</em> value for
|
|
the DMA in question. Put another way, DMA0/1/2 transfer <code>1</code> through <code>0x4000</code>
|
|
words, with <code>0</code> as the <code>0x4000</code> value, and DMA3 transfers <code>1</code> through <code>0x1_0000</code>
|
|
words, with <code>0</code> as the <code>0x1_0000</code> value.</p>
|
|
<p>The maximum value isn't a very harsh limit. Even in just <code>u16</code> mode, <code>0x4000</code>
|
|
transfers is 32k, which would for example be all 32k of <code>IWRAM</code> (including your
|
|
own user stack). If you for some reason do need to transfer more than a single
|
|
DMA use can move around at once then you can just setup the DMA a second time
|
|
and keep going.</p>
|
|
<a class="header" href="#control" id="control"><h3>Control</h3></a>
|
|
<p>This <code>u16</code> bit-flag field is where things get wild.</p>
|
|
<ul>
|
|
<li>Bits 0-4 do nothing</li>
|
|
<li>Bit 5-6 control how the destination address changes per transfer:
|
|
<ul>
|
|
<li>0: Offset +1</li>
|
|
<li>1: Offset -1</li>
|
|
<li>2: No Change</li>
|
|
<li>3: Offset +1 and reload when a Repeat starts (below)</li>
|
|
</ul>
|
|
</li>
|
|
<li>Bit 7-8 similarly control how the source address changes per transfer:
|
|
<ul>
|
|
<li>0: Offset +1</li>
|
|
<li>1: Offset -1</li>
|
|
<li>2: No Change</li>
|
|
<li>3: Prohibited</li>
|
|
</ul>
|
|
</li>
|
|
<li>Bit 9: enables Repeat mode.</li>
|
|
<li>Bit 10: Transfer <code>u16</code> (false) or <code>u32</code> (true) data.</li>
|
|
<li>Bit 11: "Game Pak DRQ" flag. GBATEK says that this is only allowed for DMA3,
|
|
and also your Game Pak hardware must be equipped to use DRQ mode. I don't even
|
|
know what DRQ mode is all about, and GBATEK doesn't say much either. If DRQ is
|
|
set then you <em>must not</em> set the Repeat bit as well. The <code>gba</code> crate simply
|
|
doesn't bother to expose this flag to users.</li>
|
|
<li>Bit 12-13: DMA Start:
|
|
<ul>
|
|
<li>0: "Immediate", which is 2 cycles after requested.</li>
|
|
<li>1: VBlank</li>
|
|
<li>2: HBlank</li>
|
|
<li>3: Special, depending on what DMA unit is involved:
|
|
<ul>
|
|
<li>DMA0: Prohibited.</li>
|
|
<li>DMA1/2: Sound FIFO (see the <a href="04-sound.html">Sound</a> section)</li>
|
|
<li>DMA3: Video Capture, intended for use with the Repeat flag, performs a
|
|
transfer per scanline (similar to HBlank) starting at <code>VCOUNT</code> 2 and
|
|
stopping at <code>VCOUNT</code> 162. Intended for copying things from ROM or camera
|
|
into VRAM.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Bit 14: Interrupt upon DMA complete.</li>
|
|
<li>Bit 15: Enable this DMA unit.</li>
|
|
</ul>
|
|
<a class="header" href="#dma-life-cycle" id="dma-life-cycle"><h2>DMA Life Cycle</h2></a>
|
|
<p>The general technique for using a DMA unit involves first setting the relevent
|
|
source, destination, and count registers, then setting the appropriate control
|
|
register value with the Enable bit set.</p>
|
|
<p>Once the Enable flag is set the appropriate DMA unit will trigger at the
|
|
assigned time (Bit 12-13). The CPU's operation is halted while any DMA unit is
|
|
active, until the DMA completes its task. If more than one DMA unit is supposed
|
|
to be active at once, then the DMA unit with the lower number will activate and
|
|
complete before any others.</p>
|
|
<p>When the DMA triggers via <em>Enable</em>, the <code>Source</code>, <code>Destination</code>, and <code>Count</code>
|
|
values are copied from the GBA's registers into the DMA unit's internal
|
|
registers. Changes to the DMA unit's internal copy of the data don't affect the
|
|
values in the GBA registers. Another <em>Enable</em> will read the same values as
|
|
before.</p>
|
|
<p>If DMA is triggered via having <em>Repeat</em> active then <em>only</em> the Count is copied
|
|
in to the DMA unit registers. The <code>Source</code> and <code>Destination</code> are unaffected
|
|
during a Repeat. The exception to this is if the destination address control
|
|
value (Bits 5-6) are set to 3 (<code>0b11</code>), in which case a <em>Repeat</em> will also
|
|
re-copy the <code>Destination</code> as well as the <code>Count</code>.</p>
|
|
<p>Once a DMA operation completes, the Enable flag of its Control register will
|
|
automatically be disabled, <em>unless</em> the Repeat flag is on, in which case the
|
|
Enable flag is left active. You will have to manually disable it if you don't
|
|
want the DMA to kick in again over and over at the specified starting time.</p>
|
|
<a class="header" href="#dma-limitations" id="dma-limitations"><h2>DMA Limitations</h2></a>
|
|
<p>The DMA units cannot access <code>SRAM</code> at all.</p>
|
|
<p>If you're using HBlank to access any part of the memory that the display
|
|
controller utilizes (<code>OAM</code>, <code>PALRAM</code>, <code>VRAM</code>), you need to have enabled the
|
|
"HBlank Interval Free" bit in the Display Control Register (<code>DISPCNT</code>).</p>
|
|
<p>Whenever DMA is active the CPU is <em>not</em> active, which means that
|
|
<a href="05-interrupts.html">Interrupts</a> will not fire while DMA is happening. This can
|
|
cause any number of hard to track down bugs. Try to limit your use of the DMA
|
|
units if you can.</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
<a rel="prev" href="../04-non-video/02-timers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a rel="next" href="../04-non-video/04-sound.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
<a href="../04-non-video/02-timers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
|
|
|
|
<a href="../04-non-video/04-sound.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
|
|
<script src="../book.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
|
|
|
|
</body>
|
|
</html>
|