PageSourceSearch

https://famicom.party/_app/immutable/nodes/23.UdYrcJT3.js

js famicom.party collected 2026-10-04 00:10:20 UTC 77,543 bytes, 487 lines download raw bytes

1import{s as fo,a as zs,e as ho,n as Xt}from"../chunks/scheduler.JUJmIPAY.js";import{S as Co,i as bo,j as X,k as Z,m as Q,t as K,l as U,n as V,e as a,s as h,o as p,a as o,g as l,c as y,p as oe,q as i,d as t,b as Yt,f as n,r}from"../chunks/index.pbL1css2.js";import{C as vo,g as Eo,a as yo}from"../chunks/chapter.A3xyNKks.js";import{M as le}from"../chunks/Margin.Zlb7RIw7.js";import{N as wo}from"../chunks/Nes.3wSicTgZ.js";function Fo(T){let u;return{c(){u=p("As a reminder, “cartridge ROM” or PRG-ROM is the read-only part of your game, and in the NES’ memory map, it is located from $8000 to $ffff. All of your game’s code is located there, though your game code can refer to memory addresses outside of PRG-ROM, like when we wrote sprite data to $0200-$02ff.")},l(c){u=i(c,"As a reminder, “cartridge ROM” or PRG-ROM is the read-only part of your game, and in the NES’ memory map, it is located from $8000 to $ffff. All of your game’s code is located there, though your game code can refer to memory addresses outside of PRG-ROM, like when we wrote sprite data to $0200-$02ff.")},m(c,E){n(c,u,E)},d(c){c&&t(u)}}}function xo(T){let u,c,E="must",C,d,b="LDA $003b",F,m,x="LDA $3b",H;return{c(){u=p("Note that you "),c=a("em"),c.textContent=E,C=p(" use just one byte in order to take advantage of zero-page addressing mode. The assembler does not know anything about the memory addresses passing through it. If you were to type "),d=a("code"),d.textContent=b,F=p(" instead of "),m=a("code"),m.textContent=x,H=p(" in your assembly code, the resulting machine code would use (slower) absolute mode, even though the memory address you are loading from is located in page zero.")},l(v){u=i(v,"Note that you "),c=o(v,"EM",{"data-svelte-h":!0}),l(c)!=="svelte-6lfldj"&&(c.textContent=E),C=i(v," use just one byte in order to take advantage of zero-page addressing mode. The assembler does not know anything about the memory addresses passing through it. If you were to type "),d=o(v,"CODE",{"data-svelte-h":!0}),l(d)!=="svelte-1xbn2w"&&(d.textContent=b),F=i(v," instead of "),m=o(v,"CODE",{"data-svelte-h":!0}),l(m)!=="svelte-cwsb6g"&&(m.textContent=x),H=i(v," in your assembly code, the resulting machine code would use (slower) absolute mode, even though the memory address you are loading from is located in page zero.")},m(v,L){n(v,u,L),n(v,c,L),n(v,C,L),n(v,d,L),n(v,F,L),n(v,m,L),n(v,H,L)},p:Xt,d(v){v&&(t(u),t(c),t(C),t(d),t(F),t(m),t(H))}}}function go(T){let u;return{c(){u=p("Notice that I said the position of “the player”, and not the positions of the individual tiles that make up the player. Any game that hopes to have more than a very small number of objects on screen at one time will need to carefully ration the use of zero-page addresses.")},l(c){u=i(c,"Notice that I said the position of “the player”, and not the positions of the individual tiles that make up the player. Any game that hopes to have more than a very small number of objects on screen at one time will need to carefully ration the use of zero-page addresses.")},m(c,E){n(c,u,E)},d(c){c&&t(u)}}}function _o(T){let u;return{c(){u=p("Note the ”:” after the name of each reserved byte - these look like the labels that we’ve already been using, and that’s because they are! When we use the name of a reserved byte later in our code, we’re telling the assembler to find the memory address that corresponds to that label and replace the name with the address, exactly the same as any other label in our code.")},l(c){u=i(c,"Note the ”:” after the name of each reserved byte - these look like the labels that we’ve already been using, and that’s because they are! When we use the name of a reserved byte later in our code, we’re telling the assembler to find the memory address that corresponds to that label and replace the name with the address, exactly the same as any other label in our code.")},m(c,E){n(c,u,E)},d(c){c&&t(u)}}}function $o(T){let u,c,E=".importzp",C,d,b=".segment “ZEROPAGE”",F;return{c(){u=p("The "),c=a("code"),c.textContent=E,C=p(" directive should go inside of a "),d=a("code"),d.textContent=b,F=p(", even if you are not doing anything else with page zero values in that file.")},l(m){u=i(m,"The "),c=o(m,"CODE",{"data-svelte-h":!0}
1),l(c)!=="svelte-mofkpx"&&(c.textContent=E),C=i(m," directive should go inside of a "),d=o(m,"CODE",{"data-svelte-h":!0}),l(d)!=="svelte-3ttn6t"&&(d.textContent=b),F=i(m,", even if you are not doing anything else with page zero values in that file.")},m(m,x){n(m,u,x),n(m,c,x),n(m,C,x),n(m,d,x),n(m,F,x)},p:Xt,d(m){m&&(t(u),t(c),t(C),t(d),t(F))}}}function Ao(T){let u,c,E="stack overflow",C,d,b="underflow",F;return{c(){u=p("Attempting to write more than 256 items to the stack at one time causes the stack pointer to wrap around from $00 to $ff, meaning that further writes to the stack will overwrite already existing stack data. This generally-catastrophic scenario is called a "),c=a("em"),c.textContent=E,C=p(" (though in the case of the 6502, it’s more properly called a stack "),d=a("em"),d.textContent=b,F=p(").")},l(m){u=i(m,"Attempting to write more than 256 items to the stack at one time causes the stack pointer to wrap around from $00 to $ff, meaning that further writes to the stack will overwrite already existing stack data. This generally-catastrophic scenario is called a "),c=o(m,"EM",{"data-svelte-h":!0}),l(c)!=="svelte-1o3fiag"&&(c.textContent=E),C=i(m," (though in the case of the 6502, it’s more properly called a stack "),d=o(m,"EM",{"data-svelte-h":!0}),l(d)!=="svelte-13drw1o"&&(d.textContent=b),F=i(m,").")},m(m,x){n(m,u,x),n(m,c,x),n(m,C,x),n(m,d,x),n(m,F,x)},p:Xt,d(m){m&&(t(u),t(c),t(C),t(d),t(F))}}}function ko(T){let u,c,E="interrupt",C;return{c(){u=p(`Thankfully, since
2the NES is single-threaded, the only thing that can alter register values
3without your knowledge is an interrupt vector - by definition, they `),c=a("em"),c.textContent=E,C=p(`
4the normal flow of your code. That means that the main place to use this
5technique is in your NMI handler.`)},l(d){u=i(d,`Thankfully, since
6the NES is single-threaded, the only thing that can alter register values
7without your knowledge is an interrupt vector - by definition, they `),c=o(d,"EM",{"data-svelte-h":!0}),l(c)!=="svelte-1vzh0df"&&(c.textContent=E),C=i(d,`
8the normal flow of your code. That means that the main place to use this
9technique is in your NMI handler.`)},m(d,b){n(d,u,b),n(d,c,b),n(d,C,b)},p:Xt,d(d){d&&(t(u),t(c),t(C))}}}function To(T){let u,c,E="RTS",C,d,b=".proc",F,m,x="you",H,v,L,I,w,M="PHP",re,O,Zt="PLP",pe,z,Qt="PHP",ie,R,we="PLP",N,ee,Fe="RTS",q,W,j="PHP",ae,D,ht="PLP",B;return{c(){u=p("If you forget to include "),c=a("code"),c.textContent=E,C=p(" at the end of your subroutine, the 6502 will not return to where the subroutine was called and will instead happily continue with the next byte after your subroutine code. The processor doesn’t know anything about "),d=a("code"),d.textContent=b,F=p("s, they are simply a tool to help "),m=a("em"),m.textContent=x,H=p(" organize your code."),v=a("br"),L=a("br"),I=p(`
10Additionally, subroutines might need to add `),w=a("code"),w.textContent=M,re=p(" at the beginning and "),O=a("code"),O.textContent=Zt,pe=p(` at the end to save and restore the processor status register.
11`),z=a("code"),z.textContent=Qt,ie=p(" must be run before any other opcode, and "),R=a("code"),R.textContent=we,N=p(" must be the last instruction before "),ee=a("code"),ee.textContent=Fe,q=p(`, because most opcodes change
12the value of the processor status register. Here, we don’t need it, because interrupts automatically save and restore the processor
13status register. If the state of the processor status register does not matter (because, for example, you explicitly check for
14flags before trying to make use of them), then your subroutines can skip `),W=a("code"),W.textContent=j,ae=p("/"),D=a("code"),D.textContent=ht,B=p(" as well.")},l(f){u=i(f,"If you forget to include "),c=o(f,"CODE",{"data-svelte-h":!0}),l(c)!=="svelte-145hg73"&&(c.textContent=E),C=i(f," at the end of your subroutine, the 6502 will not return to where the subroutine was called and will instead happily continue with the next byte after your subroutine code. The processor doesn’t know anything about "),d=o(f,"CODE",{"data-svelte-h":!0}),l(d)!=="svelte-j4ac4k"&&(d.textContent=b),F=i(f,"s, they are simply a tool to help "),m=o(f,"EM",{"data-svelte-h":!0}),l(m)!=="svelte-e5l62f"&&(m.textContent=x),H=i(f," organize your co
14de."),v=o(f,"BR",{}),L=o(f,"BR",{}),I=i(f,`
15Additionally, subroutines might need to add `),w=o(f,"CODE",{"data-svelte-h":!0}),l(w)!=="svelte-89i0me"&&(w.textContent=M),re=i(f," at the beginning and "),O=o(f,"CODE",{"data-svelte-h":!0}),l(O)!=="svelte-12xyj2q"&&(O.textContent=Zt),pe=i(f,` at the end to save and restore the processor status register.
16`),z=o(f,"CODE",{"data-svelte-h":!0}),l(z)!=="svelte-89i0me"&&(z.textContent=Qt),ie=i(f," must be run before any other opcode, and "),R=o(f,"CODE",{"data-svelte-h":!0}),l(R)!=="svelte-12xyj2q"&&(R.textContent=we),N=i(f," must be the last instruction before "),ee=o(f,"CODE",{"data-svelte-h":!0}),l(ee)!=="svelte-145hg73"&&(ee.textContent=Fe),q=i(f,`, because most opcodes change
17the value of the processor status register. Here, we don’t need it, because interrupts automatically save and restore the processor
18status register. If the state of the processor status register does not matter (because, for example, you explicitly check for
19flags before trying to make use of them), then your subroutines can skip `),W=o(f,"CODE",{"data-svelte-h":!0}),l(W)!=="svelte-89i0me"&&(W.textContent=j),ae=i(f,"/"),D=o(f,"CODE",{"data-svelte-h":!0}),l(D)!=="svelte-12xyj2q"&&(D.textContent=ht),B=i(f," as well.")},m(f,$){n(f,u,$),n(f,c,$),n(f,C,$),n(f,d,$),n(f,F,$),n(f,m,$),n(f,H,$),n(f,v,$),n(f,L,$),n(f,I,$),n(f,w,$),n(f,re,$),n(f,O,$),n(f,pe,$),n(f,z,$),n(f,ie,$),n(f,R,$),n(f,N,$),n(f,ee,$),n(f,q,$),n(f,W,$),n(f,ae,$),n(f,D,$),n(f,B,$)},p:Xt,d(f){f&&(t(u),t(c),t(C),t(d),t(F),t(m),t(H),t(v),t(L),t(I),t(w),t(re),t(O),t(pe),t(z),t(ie),t(R),t(N),t(ee),t(q),t(W),t(ae),t(D),t(B))}}}function Mo(T){let u,c,E="update_player",C,d,b="either",F,m,x="player_dir",H,v,L="player_x",I;return{c(){u=p("Note that, with the way "),c=a("code"),c.textContent=E,C=p(" is structured, if the player’s ship is not near "),d=a("em"),d.textContent=b,F=p(" edge of the screen, "),m=a("code"),m.textContent=x,H=p(" will not be updated, but we will still increment or decrement "),v=a("code"),v.textContent=L,I=p(" as appropriate.")},l(w){u=i(w,"Note that, with the way "),c=o(w,"CODE",{"data-svelte-h":!0}),l(c)!=="svelte-eezwsz"&&(c.textContent=E),C=i(w," is structured, if the player’s ship is not near "),d=o(w,"EM",{"data-svelte-h":!0}),l(d)!=="svelte-19crb57"&&(d.textContent=b),F=i(w," edge of the screen, "),m=o(w,"CODE",{"data-svelte-h":!0}),l(m)!=="svelte-mpju21"&&(m.textContent=x),H=i(w," will not be updated, but we will still increment or decrement "),v=o(w,"CODE",{"data-svelte-h":!0}),l(v)!=="svelte-mq7vv6"&&(v.textContent=L),I=i(w," as appropriate.")},m(w,M){n(w,u,M),n(w,c,M),n(w,C,M),n(w,d,M),n(w,F,M),n(w,m,M),n(w,H,M),n(w,v,M),n(w,I,M)},p:Xt,d(w){w&&(t(u),t(c),t(C),t(d),t(F),t(m),t(H),t(v),t(I))}}}function Lo(T){let u,c=`In the last chapter, we created background graphics to display
20behind our sprites. While the addition of backgrounds helps
21make our game look more like an actual game, it is still
22entirely static - no different from a still picture. In this
23chapter, we’ll look at how to move sprites around the screen.
24To do so, we will need to make some changes to how our game
25is drawing sprites.`,E,C,d,b,F,m,x,H="Zero-Page RAM",v,L,I=`A “page” of memory on the NES is a contiguous block of 256 bytes
26of memory. For any memory address, the <em>high</em> byte determines the
27page number, and the <em>low</em> byte determines the specific address
28within the page. As an example, the range from <code>$0200</code> to <code>$02ff</code>
29is “page <code>$02</code>”, and the range from <code>$8000</code> to <code>$80ff</code> is
30“page <code>$80</code>“.`,w,M,re,O,Zt="$0000",pe,z,Qt="$00ff",ie,R,we,N,ee=`<code><span data-line-number="1"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$8000</span><span style="color: #10C26F"> </span><span style="color: #F2D338">; &quot;regular&quot;, absolute mode addressing</span></span>
31<span data-line-number="2"><span style="color: #10C26F">            </span><span style="color: #F2D338">; load contents of address $8000 into A</span></span>
32<span data-line-number="3"></span>
33<span data-line-number="4"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$3b</span><span style="color: #10C26F">   </span><span style="color: #F2D338">; zero-page addressing</span></span>
34<span data-line-number="5"><span style="color: #10C26F">            </span><span style="color: #F2D338">; load contents of address $003b into A</span></span>
35<span data-line-number="6"></span>
36<span data-line-number="7"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$3b</span><span style="color: #10C26F">  </span><span style="color: #F2D338">; immediate mode addressing</span></span>
37<span data-line-number="8"><span style="color: #10C26F">            </span><span style="color: #F2D338">; load literal value $3b into A</span></span>
38</code>`,Fe,q,W,j,ae,D,ht,B,f="$8000",$,yt,Is="reserve",Vn,ce,es,Kt,xe,Ns=`<code><span data-line-number="1"><span style="color: #10C26F">.segment </span><span style="color: #10C26F">&quot;ZEROPAGE&quot;</span></span>
39<span data-line-number="2"><span style="color: #10C26F">player_x: .res </span><span style="color: #0593A3">1</span></span>
40<span data-line-number="3"><span style="color: #10C26F">player_y: .res </span><span style="color: #0593A3">1</span></span>
41</code>`,Ut,ge,qs=`First, we tell the assembler that we want to reserve page zero memory
42by using the appropriate segment from our linker config file - in this
43case, <code>&quot;ZEROPAGE&quot;</code>. Then, for each memory range we want to reserve,
44we use the <code>.res</code> directive, followed by the number of bytes we want
45to reserve. Generally this will be “1” to reserve a single byte of memory,
46but being able to specify any number can be useful if, for example,
47you need to store a 16-bit number in page zero.`,Vt,_e,Ws=`Now that we have reserved memory, we need to initialize it to a good
48starting value somewhere in our code. Two good options for this are
49either as part of the reset handler, or at the beginning of <code>main</code>.
50We’ll opt for the reset handler approach here. In <code>reset.asm</code>, just
51before <code>JMP main</code>, add the following code:`,en,$e,js=`<code><span data-line-number="1"><span style="color: #10C26F">  </span><span style="color: #F2D338">; initialize zero-page values</span></span>
52<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$80</span></span>
53<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> player_x</span></span>
54<span data-line-number="4"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$a0</span></span>
55<span data-line-number="5"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> player_y</span></span>
56</code>`,tn,Ae,Bs=`If you try to assemble this code, however (<code>ca65 src/reset.asm</code>), you
57will get an error:`,nn,ke,Gs=`<code><span data-line-number="1"><span style="color: #EEEEEE">Error: Symbol </span><span style="color: #EEEEEE">&#39;player_y&#39;</span><span style="color: #EEEEEE"> is undefined</span></span>
58<span data-line-number="2"><span style="color: #EEEEEE">Error: Symbol </span><span style="color: #EEEEEE">&#39;player_x&#39;</span><span style="color: #EEEEEE"> is undefined</span></span>
59</code>`,sn,Te,Js=`Generally, reserved memory names are only valid in the same file
60where they are defined. In this case, we reserved <code>player_x</code> and
61<code>player_y</code> in our main file, but we were trying to use them in
62<code>reset.asm</code>. Thankfully, ca65 provides directives to export and
63import reserved zero-page memory so it can be shared between files.
64We’ll just need to add an <code>.exportzp</code> directive in our main file:`,an,Me,Ys=`<code><span data-line-number="1"><span style="color: #10C26F">.segment </span><span style="color: #10C26F">&quot;ZEROPAGE&quot;</span></span>
65<span data-line-number="2"><span style="color: #10C26F">player_x: .res </span><span style="color: #0593A3">1</span></span>
66<span data-line-number="3"><span style="color: #10C26F">player_y: .res </span><span style="color: #0593A3">1</span></span>
67<span data-line-number="4"><span style="color: #10C26F">.exportzp player_x, player_y</span></span>
68</code>`,on,G,ts,mt,Xs="reset.asm",ns,ft,Zs=".importzp",ss,de,ln,Le,Qs=`<code><span data-line-number="1"><span style="color: #10C26F">.segment </span><span style="color: #10C26F">&quot;ZEROPAGE&quot;</span></span>
69<span data-line-number="2"><span style="color: #10C26F">.importzp player_x, player_y</span></span>
70</code>`,rn,De,Ks=`When you assemble these files, ca65 will look through the
71other source files in the same directory looking for imports
72and exports and it will figure out what data should go where.`,pn,ue,Us="Subroutines",cn,Pe,Vs=`Since we only have a limited number of zero-page addresses (256)
73available, we need to ration them out carefully. Instead of
74storing the position of every player sprite tile individually
75(which would take 8 bytes of zero page just for x/y positions),
76we will store just an overall player X and Y coordinate and
77offload the drawing of the actual player sprites to a <em>subroutine</em>.
78Subroutines are assembly’s version of functions - named, reusable
79code fragments.`,dn,He,ea=`To create a subroutine, make a new <code>.proc</code> in your code. The only
80requirement for a subroutine is that it <em>must</em> end with the opcode
81<code>RTS</code>, “Return from Subroutine”. To <em>call</em> a subroutine, use the
82opcode <code>JSR</code>, “Jump to Subroutine”, followed by the name of
83the subroutine (whatever follows <code>.proc</code>).`,un,Se,ta=`Before we go further, let’s take a look at what actually happens when
84we call a subroutine. Here is some example code:`,hn,Re,na=`<code data-line-numbers=""><span data-line-number="1"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$80</span></span>
85<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #E3371E">JSR</span><span style="color: #10C26F"> do_something_else</span></span>
86<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$8000</span></span>
87<span data-line-number="4"></span>
88<span data-line-number="5"><span style="color: #10C26F">.proc do_something_else</span></span>
89<span data-line-number="6"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$90</span></span>
90<span data-line-number="7"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTS</span></span>
91<span data-line-number="8"><span style="color: #10C26F">.endproc</span></span>
92</code>`,yn,Oe,sa=`When this code runs, the processor first puts the literal value
93<code>$80</code> into the accumulator. Then it calls the subroutine <code>do_something_else</code>.
94When the 6502 sees a <code>JSR</code> opcode, it pushes the current value
95of the program counter (the special register that holds the
96memory address of the next byte to be processed) onto the <em>stack</em>.
97A stack, in computer science, is a “last in, first out” data structure,
98similar to a stack of real-life plates. Adding something to the stack
99means putting it on top of the pile, and only the top-most element
100is available at any given time.`,mn,P,as,Ct,aa="$0100",os,bt,oa="$01ff",ls,vt,la="$ff",rs,Et,ra="$0100",ps,wt,pa="$01ff",is,he,cs,fn,g,ds,Ft,ia="JSR",us,xt,ca="JSR",hs,gt,da="$90",ys,_t,ua="RTS",ms,$t,ha="RTS",fs,At,ya="should",Cs,kt,ma="JSR",bs,Tt,fa="JSR",vs,Mt,Ca="STA $8000",Es,Lt,ba="$90",ws,Dt,va="$80",Fs,ye,Cn,me,Ea="Register Management",bn,ze,wa=`To help you save and restore the contents of registers, the 6502
101provides four opcodes: <code>PHA</code>, <code>PHP</code>, <code>PLA</code>, and <code>PLP</code>. <code>PHA</code> and
102<code>PHP</code> are used to “push” the accumulator (“A”) and processor status
103register (“P”), respectively, onto the stack. In the other direction,
104<code>PLA</code> and <code>PLP</code> “pull” the top value off of the stack and place it
105into the accumulator or processor status register. There are no
106special opcodes for the X and Y registers; to push their
107values, you must first transfer them into the accumulator (with
108<code>TXA</code> / <code>TYA</code>), and to restore them you must pull into the
109accumulator and then transfer again (with <code>TAX</code> / <code>TAY</code>).`,vn,Ie,Fa="Let’s look at how you might use these new opcodes in your N
109MI handler:",En,Ne,xa=`<code><span data-line-number="1"><span style="color: #10C26F">.proc nmi_handler</span></span>
110<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
111<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #E3371E">TXA</span></span>
112<span data-line-number="4"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
113<span data-line-number="5"><span style="color: #10C26F">  </span><span style="color: #E3371E">TYA</span></span>
114<span data-line-number="6"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
115<span data-line-number="7"></span>
116<span data-line-number="8"><span style="color: #10C26F">  </span><span style="color: #F2D338">; your actual NMI code here</span></span>
117<span data-line-number="9"></span>
118<span data-line-number="10"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
119<span data-line-number="11"><span style="color: #10C26F">  </span><span style="color: #E3371E">TAY</span></span>
120<span data-line-number="12"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
121<span data-line-number="13"><span style="color: #10C26F">  </span><span style="color: #E3371E">TAX</span></span>
122<span data-line-number="14"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
123<span data-line-number="15"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTI</span></span>
124<span data-line-number="16"><span style="color: #10C26F">.endproc</span></span>
125</code>`,wn,J,xs,Pt,ga="RTI",gs,Ht,_a="RTS",_s,fe,Fn,Ce,$a="Your First Subroutine: Drawing the Player",xn,qe,Aa=`Now that you’ve seen how subroutines work, it’s time to create your
126own. Let’s write a subroutine that draws the player’s ship at a given
127location. To do that, we’ll need to use the <code>player_x</code> and <code>player_y</code>
128zero-page variables we created earlier to write the appropriate bytes
129to memory range <code>$0200</code>-<code>$02ff</code>. Previously, we did this by storing
130the appropriate bytes in <code>RODATA</code> and copying them with a loop and
131indexed addressing, the same way we did with palettes. As a quick
132refresher, we need to write four bytes of data for each 8 pixel by
1338 pixel sprite tile: the sprite’s Y position, tile number, special
134attributes / palette, and X position. The tile number and palette
135for each of the four sprites that make up the player ship will not
136change, so let’s start there.`,gn,We,ka=`<code><span data-line-number="1"><span style="color: #10C26F">.proc draw_player</span></span>
137<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #F2D338">; write player ship tile numbers</span></span>
138<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$05</span></span>
139<span data-line-number="4"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0201</span></span>
140<span data-line-number="5"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$06</span></span>
141<span data-line-number="6"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0205</span></span>
142<span data-line-number="7"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$07</span></span>
143<span data-line-number="8"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0209</span></span>
144<span data-line-number="9"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$08</span></span>
145<span data-line-number="10"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$020d</span></span>
146<span data-line-number="11"></span>
147<span data-line-number="12"><span style="color: #10C26F">  </span><span style="color: #F2D338">; write player ship tile attributes</span></span>
148<span data-line-number="13"><span style="color: #10C26F">  </span><span style="color: #F2D338">; use palette 0</span></span>
149<span data-line-number="14"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$00</span></span>
150<span data-line-number="15"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0202</span></span>
151<span data-line-number="16"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0206</span></span>
152<span data-line-number="17"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$020a</span></span>
153<span data-line-number="18"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">
153$020e</span></span>
154<span data-line-number="19"></span>
155<span data-line-number="20"><span style="color: #10C26F">  </span><span style="color: #F2D338">; return to where the subroutine was called</span></span>
156<span data-line-number="21"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTS</span></span>
157<span data-line-number="22"><span style="color: #10C26F">.endproc</span></span>
158</code>`,_n,je,Ta=`The player ship uses tiles <code>$05</code> (top left), <code>$06</code> (top right),
159<code>$07</code> (bottom left), and <code>$08</code> (bottom right). We write those
160tile numbers to memory addresses <code>$0201</code>, <code>$0205</code>, <code>$0209</code>, and
161<code>$020d</code>, respectively, because those correspond to “byte 2” of
162the first four sprites. All of the player ship’s tiles use
163palette zero (the first palette), so the code to write sprite
164attributes is much shorter. <code>$0202</code>, <code>$0206</code>, <code>$020a</code>, and <code>$020e</code>
165are the bytes immediately following the previous tile number
166bytes, and so they hold the attributes for each of the first
167four sprites. Finally, we use <code>RTS</code> to end the subroutine.`,$n,Be,Ma=`What about the <em>location</em> of each tile on screen? For that, we
168will need to use <code>player_x</code>, <code>player_y</code>, and some basic math.
169Let’s assume, to make things easier, that <code>player_x</code> and
170<code>player_y</code> represent the top left corner of the top left tile
171of the player’s ship. In our reset handler, we positioned
172the top left corner of the top left player ship tile at
173(<code>$70</code>, <code>$a0</code>). Once we have placed the top left tile,
174we can add eight pixels to <code>player_x</code> and <code>player_y</code> to
175find the positions of the other three tiles.`,An,Ge,La=`In the past, we have used <code>INC</code> / <code>DEC</code> to add or subtract.
176When adding or subtracting more than 1, however, there
177are more efficient opcodes - specifically, <code>ADC</code> (“ADd with Carry”).`,kn,Je,Da=`Here’s what that
178looks like (previous code reduced to just comments):`,Tn,Ye,Pa=`<code><span data-line-number="1"><span style="color: #10C26F">.proc draw_player</span></span>
179<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #F2D338">; store tile numbers</span></span>
180<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #F2D338">; store attributes</span></span>
181<span data-line-number="4"></span>
182<span data-line-number="5"><span style="color: #10C26F">  </span><span style="color: #F2D338">; store tile locations</span></span>
183<span data-line-number="6"><span style="color: #10C26F">  </span><span style="color: #F2D338">; top left tile:</span></span>
184<span data-line-number="7"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_y</span></span>
185<span data-line-number="8"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0200</span></span>
186<span data-line-number="9"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
187<span data-line-number="10"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0203</span></span>
188<span data-line-number="11"></span>
189<span data-line-number="12"><span style="color: #10C26F">  </span><span style="color: #F2D338">; top right tile (x + 8):</span></span>
190<span data-line-number="13"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_y</span></span>
191<span data-line-number="14"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0204</span></span>
192<span data-line-number="15"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
193<span data-line-number="16"><span style="color: #10C26F">  </span><span style="color: #E3371E">CLC</span></span>
194<span data-line-number="17"><span style="color: #10C26F">  </span><span style="color: #E3371E">ADC</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$08</span></span>
195<span data-line-number="18"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0207</span></span>
196<span data-line-number="19"></span>
197<span data-line-number="20"><span style="color: #10C26F">  </span><span style="color: #F2D338">; bottom left tile (y + 8):</span></span>
198<span data-line-number="21"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_y</span></span>
199<span data-line-number="22"><span style="color: #10C26F">  </span><span style="color: #E3371E">CLC</span></span>
200<span data-line-number="23"><span style="color: #10C26F">  </span><span style="color: #E3371E">ADC</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$08</span></span>
201<span data-line-number="24"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$0208</span></span>
202<span data-line-number="25"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
203<span data-line-number="26"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$020b</span></span>
204<span data-line-number="27"></span>
205<span data-line-number="28"><span style="color: #10C26F">  </span><span style="color: #F2D338">; bottom right tile (x + 8, y + 8)</span></span>
206<span data-line-number="29"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_y</span></span>
207<span data-line-number="30"><span style="color: #10C26F">  </span><span style="color: #E3371E">CLC</span></span>
208<span data-line-number="31"><span style="color: #10C26F">  </span><span style="color: #E3371E">ADC</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$08</span></span>
209<span data-line-number="32"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$020c</span></span>
210<span data-line-number="33"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
211<span data-line-number="34"><span style="color: #10C26F">  </span><span style="color: #E3371E">CLC</span></span>
212<span data-line-number="35"><span style="color: #10C26F">  </span><span style="color: #E3371E">ADC</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$08</span></span>
213<span data-line-number="36"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$020f</span></span>
214<span data-line-number="37"></span>
215<span data-line-number="38"><span style="color: #10C26F">  </span><span style="color: #F2D338">; return to where the subroutine was called</span></span>
216<span data-line-number="39"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTS</span></span>
217<span data-line-number="40"><span style="color: #10C26F">.endproc</span></span>
218</code>`,Mn,Xe,Ha=`Remember that when you want to perform addition, first
219call <code>CLC</code>, then use <code>ADC</code> (unless you’re trying to add
220something to a 16-bit number, which will be rare for now).
221The result of the addition can be found in the accumulator;
222it does not get written to <code>player_y</code> or <code>player_x</code>.`,Ln,be,Sa="Putting It All Together",Dn,Ze,Ra=`With our subroutine written, it’s time to make use of it.
223We already set up the initial values of <code>player_x</code> and
224<code>player_y</code> in the reset handler. Now, we’ll call our
225new subroutine as part of the NMI handler, so it runs
226every frame:`,Pn,Qe,Oa=`<code data-line-numbers=""><span data-line-number="15"><span style="color: #10C26F">.proc nmi_handler</span></span>
227<span data-line-number="16"><span style="color: #10C26F">  </span><span style="color: #F2D338">; save registers</span></span>
228<span data-line-number="17"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
229<span data-line-number="18"><span style="color: #10C26F">  </span><span style="color: #E3371E">TXA</span></span>
230<span data-line-number="19"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
231<span data-line-number="20"><span style="color: #10C26F">  </span><span style="color: #E3371E">TYA</span></span>
232<span data-line-number="21"><span style="color: #10C26F">  </span><span style="color: #E3371E">PHA</span></span>
233<span data-line-number="22"></span>
234<span data-line-number="23"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$00</span></span>
235<span data-line-number="24"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> OAMADDR</span></span>
236<span data-line-number="25"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$02</span></span>
237<span data-line-number="26"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> OAMDMA</span></span>
238<span data-line-number="27"></span>
239<span data-line-number="28"><span style="color: #10C26F">  </span><span style="color: #F2D338">; update tiles *after* DMA transfer</span></span>
240<span data-highlighted="" data-line-number="29"><span style="color: #10C26F">  </span><span style="color: #E3371E">JSR</span><span style="color: #10C26F"> draw_player</span></span>
241<span data-line-number="30"></span>
242<span data-line-number="31"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$00</span></span>
243<span data-line-number="32"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$2005</span></span>
244<span data-line-number="33"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> </span><span style="color: #07E2FA">$2005</span></span>
245<span data-line-number="34"></span>
246<span data-line-number="35"><span style="color: #10C26F">  </span><span style="color: #F2D338">; restore registers</span></span>
247<span data-line-number="36"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
248<span data-line-number="37"><span style="color: #10C26F">  </span><span style="color: #E3371E">TAY</span></span>
249<span data-line-number="38"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
250<span data-line-number="39"><span style="color: #10C26F">  </span><span style="color: #E3371E">TAX</span></span>
251<span data-line-number="40"><span style="color: #10C26F">  </span><span style="color: #E3371E">PLA</span></span>
252<span data-line-number="41"></span>
253<span data-line-number="42"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTI</span></span>
254<span data-line-number="43"><span style="color: #10C26F">.endproc</span></span>
255</code>`,Hn,Ke,za=`Notice that we perform a DMA transfer of whatever is
256already in memory range <code>$0200</code>-<code>$02ff</code> <em>before</em>
257calling our subroutine. The amount of time you have
258available to complete your NMI handler is very short,
259so putting your DMA transfer first ensures that at
260least <em>something</em> will be drawn to the screen each frame.`,Sn,Ue,Ia=`Finally, we need to update <code>player_x</code> each frame so
261that our sprites will actually move around the screen.
262For this example, we will keep <code>player_y</code> the same,
263but we will modify <code>player_x</code> so that the player’s ship
264moves to the right until it is near the right edge of the
265screen and then moves left until it is near the left
266edge of the screen. To make this easier, we’ll need
267to store what direction the player’s ship is moving
268in. Let’s add another zero page variable, <code>player_dir</code>.
269A <code>0</code> will indicate that the player’s ship is moving
270left, and a <code>1</code> will indicate that the player’s ship
271is moving right.`,Rn,Ve,Na=`<code><span data-line-number="1"><span style="color: #10C26F">.segment </span><span style="color: #10C26F">&quot;ZEROPAGE&quot;</span></span>
272<span data-line-number="2"><span style="color: #10C26F">player_x: .res </span><span style="color: #0593A3">1</span></span>
273<span data-line-number="3"><span style="color: #10C26F">player_y: .res </span><span style="color: #0593A3">1</span></span>
274<span data-line-number="4"><span style="color: #10C26F">player_dir: .res </span><span style="color: #0593A3">1</span></span>
275<span data-line-number="5"><span style="color: #10C26F">.exportzp player_x, player_y</span></span>
276</code>`,On,et,qa=`I did not export <code>player_dir</code> because other files do not
277(yet) need to access it. Now we can write the code to
278update <code>player_x</code>. We could write out this code as part
279of the NMI handler directly, but in anticipation of more
280complicated player movement in the future, let’s put
281it into its own subroutine, <code>update_player</code>:`,zn,tt,Wa=`<code><span data-line-number="1"><span style="color: #10C26F">.proc update_player</span></span>
282<span data-line-number="2"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
283<span data-line-number="3"><span style="color: #10C26F">  </span><span style="color: #E3371E">CMP</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$e0</span></span>
284<span data-line-number="4"><span style="color: #10C26F">  </span><span style="color: #E3371E">BCC</span><span style="color: #10C26F"> not_at_right_edge</span></span>
285<span data-line-number="5"><span style="color: #10C26F">  </span><span style="color: #F2D338">; if BCC is not taken, we are greater than $e0</span></span>
286<span data-line-number="6"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$00</span></span>
287<span data-line-number="7"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> player_dir    </span><span style="color: #F2D338">; start moving left</span></span>
288<span data-line-number="8"><span style="color: #10C26F">  </span><span style="color: #E3371E">JMP</span><span style="color: #10C26F"> direction_set </span><span style="color: #F2D338">; we already chose a direction,</span></span>
289<span data-line-number="9"><span style="color: #10C26F">                    </span><span style="color: #F2D338">; so we can skip the left side check</span></span>
290<span data-line-number="10"><span style="color: #10C26F">not_at_right_edge:</span></span>
291<span data-line-number="11"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_x</span></span>
292<span data-line-number="12"><span style="color: #10C26F">  </span><span style="color: #E3371E">CMP</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$10</span></span>
293<span data-line-number="13"><span style="color: #10C26F">  </span><span style="color: #E3371E">BCS</span><span style="color: #10C26F"> direction_set</span></span>
294<span data-line-number="14"><span style="color: #10C26F">  </span><span style="color: #F2D338">; if BCS not taken, we are less than $10</span></span>
295<span data-line-number="15"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$01</span></span>
296<span data-line-number="16"><span style="color: #10C26F">  </span><span style="color: #E3371E">STA</span><span style="color: #10C26F"> player_dir   </span><span style="color: #F2D338">; start moving right</span></span>
297<span data-line-number="17"><span style="color: #10C26F">direction_set:</span></span>
298<span data-line-number="18"><span style="color: #10C26F">  </span><span style="color: #F2D338">; now, actually update player_x</span></span>
299<span data-line-number="19"><span style="color: #10C26F">  </span><span style="color: #E3371E">LDA</span><span style="color: #10C26F"> player_dir</span></span>
300<span data-line-number="20"><span style="color: #10C26F">  </span><span style="color: #E3371E">CMP</span><span style="color: #10C26F"> </span><span style="color: #FF7A48">#</span><span style="color: #07E2FA">$01</span></span>
301<span data-line-number="21"><span style="color: #10C26F">  </span><span style="color: #E3371E">BEQ</span><span style="color: #10C26F"> move_right</span></span>
302<span data-line-number="22"><span style="color: #10C26F">  </span><span style="color: #F2D338">; if player_dir minus $01 is not zero,</span></span>
303<span data-line-number="23"><span style="color: #10C26F">  </span><span style="color: #F2D338">; that means player_dir was $00 and</span></span>
304<span data-line-number="24"><span style="color: #10C26F">  </span><span style="color: #F2D338">; we need to move left</span></span>
305<span data-line-number="25"><span style="color: #10C26F">  </span><span style="color: #E3371E">DEC</span><span style="color: #10C26F"> player_x</span></span>
306<span data-line-number="26"><span style="color: #10C26F">  </span><span style="color: #E3371E">JMP</span><span style="color: #10C26F"> exit_subroutine</span></span>
307<span data-line-number="27"><span style="color: #10C26F">move_right:</span></span>
308<span data-line-number="28"><span style="color: #10C26F">  </span><span style="color: #E3371E">INC</span><span style="color: #10C26F"> player_x</span></span>
309<span data-line-number="29"><span style="color: #10C26F">exit_subroutine:</span></span>
310<span data-line-number="30"><span style="color: #10C26F">  </span><span style="color: #F2D338">; all done, return</span></span>
311<span data-line-number="31"><span style="color: #10C26F">  </span><span style="color: #E3371E">RTS</span></span>
312<span data-line-number="32"><span style="color: #10C26F">.endproc</span></span>
313</code>
313`,In,nt,ja=`This subroutine makes heavy use of the branching and
314comparison opcodes we saw in <a href="/book/11-branchingandloops">Chapter 11</a>.
315We first load <code>player_x</code> into the accumulator and compare
316with <code>$e0</code>. <code>CMP</code>, as we learned earlier, subtracts its
317own operand from the accumulator, but only sets the carry
318and zero flags. We can use the resulting processor status
319register flags to tell us whether the value in the accumulator
320(in this case, <code>player_x</code>) was greater than, equal to, or
321less than <code>CMP</code>’s operand. <code>BCC not_at_right_edge</code> tells
322the 6502 to skip ahead to <code>not_at_right_edge</code> if the carry
323flag is cleared. When performing a subtraction as part of
324a comparison, the 6502 first sets the carry flag, and it
325is only cleared if the accumulator is smaller than <code>CMP</code>’s
326operand. In this case, if the accumulator is smaller than
327<code>$e0</code>, we know we are not near the right edge of the screen,
328so we can skip ahead to <code>not_at_right_edge</code>. If the accumulator
329is greater than <code>$e0</code>, the carry flag will still be set and
330the 6502 will continue with the next line. In that case,
331we are near the right edge of the screen, so we will need
332to update <code>player_dir</code> with a zero (to signify “moving left”).
333Then we use <code>JMP</code> to skip over the checks for whether or
334not we are near the left edge of the screen, because we already
335know that’s not possible.`,Nn,_,$s,St,Ba="player_x",As,Rt,Ga="player_x",ks,Ot,Ja="player_x",Ts,zt,Ya="$10",Ms,It,Xa="BCS direction_set",Ls,Nt,Za="BCS",Ds,qt,Qa="player_x",Ps,Wt,Ka="$10",Hs,jt,Ua="player_x",Ss,Bt,Va="player_dir",Rs,Gt,eo="$01",Os,ve,qn,st,to=`Finally, it’s time to actually use the results of our
336edge tests. We compare <code>player_dir</code> with <code>$01</code> and look
337to see if the result is zero. If it is, <code>BEQ move_right</code>
338activates and we increment <code>player_x</code>. Otherwise, we
339decrement <code>player_x</code>. Having performed our update,
340we restore all of the registers and return from the subroutine.`,Wn,at,no=`Let’s call our new subrout
340ine inside of the NMI handler
341to finish off our example project:`,jn,ot,so=`<code data-line-numbers=""><span data-line-number="30"><span style="color: #10C26F">  </span><span style="color: #F2D338">; update tiles *after* DMA transfer</span></span>
342<span data-line-number="31"><span style="color: #10C26F">  </span><span style="color: #E3371E">JSR</span><span style="color: #10C26F"> update_player</span></span>
343<span data-line-number="32"><span style="color: #10C26F">  </span><span style="color: #E3371E">JSR</span><span style="color: #10C26F"> draw_player</span></span>
344</code>`,Bn,lt,ao=`All that’s left is to assemble and link the files
345into a NES ROM:`,Gn,rt,oo=`<code><span data-line-number="1"><span style="color: #EEEEEE">ca65 src/spritemovement.asm</span></span>
346<span data-line-number="2"><span style="color: #EEEEEE">ca65 src/reset.asm</span></span>
347<span data-line-number="3"><span style="color: #EEEEEE">ld65 src/reset.o src/spritemovement.o -C nes.cfg -o spritemovement.nes</span></span>
348</code>`,Jn,pt,lo=`If you open the resulting <code>.nes</code> file in an emulator,
349you should see this:`,Yn,it,Xn,Ee,ro="Homework",Zn,ct,po=`Now that you understand the basics of moving sprites around
350the screen, try these projects to explore and deepen your
351understanding.`,Qn,dt,io=`<li>Make the player ship move faster. Currently, we move the
352player’s ship one pixel per frame, or 60 pixels per second.
353How would you make that movement faster?</li> <li>Change <code>player_y</code> instead of (or in addition to) <code>player_x</code>.
354Keep in mind that sprite Y positions greater than <code>$e0</code> will
355be below the bottom of the viewable screen area.</li> <li>What happens if, instead of checking the left and right
356edges of the screen, you just <code>INC player_x</code> (or <code>DEC player_x</code>)
357every frame?  It’s simple enough that you could do it directly
358in the NMI handler, without even touching <code>update_player</code>.</li> <li>Add additional sprites and move them separately from the
359player ship sprite.</li>`,Kn,ut,co='To help you get started, you can download <a href="https://famicom.party/book/projects/14-spritemovement.zip">all of the code from this chapter</a>.',Un;return b=new le({props:{id:"cartridgerom",$$slots:{default:[Fo]},$$scope:{ctx:T}}}),R=new le({props:{id:"zeropagemode",$$slots:{default:[xo]},$$scope:{ctx:T}}}),j=new le({props:{id:"metatiles",$$slots:{default:[go]},$$scope:{ctx:T}}}),ce=new le({props:{id:"reservingmemory",$$slots:{default:[_o]},$$scope:{ctx:T}}}),de=new le({props:{id:"importzp",$$slots:{default:[$o]},$$scope:{ctx:T}}}),he=new le({props:{id:"stackoverflow",$$slots:{default:[Ao]},$$scope:{ctx:T}}}),ye=new le({props:{id:"whentosave",$$slots:{default:[ko]},$$scope:{ctx:T}}}),fe=new le({props:{id:"rts",$$slots:{default:[To]},$$scope:{ctx:T}}}),ve=new le({props:{id:"notedges",$$slots:{default:[Mo]},$$scope:{ctx:T}}}),it=new wo({props:{rom:"/roms/spritemovement.nes"}}),{c(){u=a("p"),u.textContent=c,E=h(),C=a("p"),d=p(`First, we can no longer hard-code the positions of our sprites
360in cartridge ROM.`),X(b.$$.fragment),F=p(` There are many choices for where we could put our
361sprite’s information, but the best location is “zero-page RAM”.`),m=h(),x=a("h2"),x.textContent=H,v=h(),L=a("p"),L.innerHTML=I,w=h(),M=a("p"),re=p(`What, then, is “zero-page RAM”? Page zero is the range of memory
362from `),O=a("code"),O.textContent=Zt,pe=p(" to "),z=a("code"),z.textContent=Qt,ie=p(`. What makes page zero useful for things
363like sprite positions is its speed. The 6502 processor has a
364special addressing mode for working with zero-page RAM, which
365makes operations on zero-page addresses much faster than the
366same operation on other memory addresses. To use zero-page
367addressing, use one byte instead of two when providing a memory
368address. Let’s look at an example:`),X(R.$$.fragment),we=h(),N=a("pre"),N.innerHTML=ee,Fe=h(),q=a("p"),W=p(`So, using zero-page addressing gives us very fast access to 256
369bytes of memory. Those 256 bytes are the ideal place to store
370values that your game will need to update or reference frequently,
371making them an ideal place to record things like the current score,
372the number of lives the player has, which stage or level the player
373is in, and the positions of the player, enemies, projectiles,
374etc.`),X(j.$$.fragment),ae=h(),D=a("p"),ht=p(`Let’s start using zero-page RAM in our code. Because only addresses from
375`),B=a("code"),B.textContent=f,$=p(` and up are ROM (i.e., part of your actual cartridge / code that
376you write), we can’t just write zero page values directly. Instead, we
377tell the assembler to `),yt=a("em"),yt.textContent=Is,Vn=p(` memory in page
378zero,`),X(ce.$$.fragment),es=p(" like this:"),Kt=h(),xe=a("pre"),xe.innerHTML=Ns,Ut=h(),ge=a("p"),ge.innerHTML=qs,Vt=h(),_e=a("p"),_e.innerHTML=Ws,en=h(),$e=a("pre"),$e.innerHTML=js,tn=h(),Ae=a("p"),Ae.innerHTML=Bs,nn=h(),ke=a("pre"),ke.innerHTML=Gs,sn=h(),Te=a("p"),Te.innerHTML=Js,an=h(),Me=a("pre"),Me.innerHTML=Ys,on=h(),G=a("p"),ts=p("Then, in "),mt=a("code"),mt.textContent=Xs,ns=p(", we can use an "),ft=a("code"),ft.textContent=Zs,ss=p(" directive:"),X(de.$$.fragment),ln=h(),Le=a("pre"),Le.innerHTML=Qs,rn=h(),De=a("p"),De.textContent=Ks,pn=h(),ue=a("h2"),ue.textContent=Us,cn=h(),Pe=a("p"),Pe.innerHTML=Vs,dn=h(),He=a("p"),He.innerHTML=ea,un=h(),Se=a("p"),Se.textContent=ta,hn=h(),Re=a("pre"),Re.innerHTML=na,yn=h(),Oe=a("p"),Oe.innerHTML=sa,mn=h(),P=a("p"),as=p(`On the 6502, the stack is 256 bytes in size and is located at
379`),Ct=a("code"),Ct.textContent=aa,os=p(" to "),bt=a("code"),bt.textContent=oa,ls=p(`. The 6502 uses a special register,
380the “stack pointer” (often abbreviated “S”), to indicate where the
381“top” of the stack is. When the system is first initialized, the
382value of the stack pointer is `),vt=a("code"),vt.textContent=la,rs=p(`. Every time something is stored
383on the stack, it is written to `),Et=a("code"),Et.textContent=ra,ps=p(` plus the address held in the stack pointer
384(e.g., the first write to the stack is stored at `),wt=a("code"),wt.textContent=pa,is=p(`), and
385then the stack pointer is decremented by one.`),X(he.$$.fragment),cs=p(` When a value is removed from the stack, the stack pointer
386is incremented by one.`),fn=h(),g=a("p"),ds=p("So, on line 2, the processor sees a "),Ft=a("code"),Ft.textContent=ia,us=p(` opcode and stores the current
387value of the program counter on the stack. Then, it takes the operand
388of the `),xt=a("code"),xt.textContent=ca,hs=p(` and puts that memory address into the program counter.
389Here, the processor skips from line 2 to line 6, and writes the literal
390value `),gt=a("code"),gt.textContent=da,ys=p(" to the accumulator. The next opcode is an "),_t=a("code"),_t.textContent=ua,ms=p(`. When the
3916502 sees an `),$t=a("code"),$t.textContent=ha,fs=p(`, it takes the “top” value from the stack (often referred
392to as “popping” and item off the stack) and puts it into the program
393counter. Given the way the stack works, this `),At=a("em"),At.textContent=ya,Cs=p(` be the address
394that was “pushed onto” the stack back when the processor saw a `),kt=a("code"),kt.textContent=ma,bs=p(`.
395This pulls us back to whatever code is immediately after the `),Tt=a("code"),Tt.textContent=fa,vs=p(`.
396Here, that means `),Mt=a("code"),Mt.textContent=Ca,Es=p(" - and the result will be writing "),Lt=a("code"),Lt.textContent=ba,ws=p(`
397to that memory address, not `),Dt=a("code"),Dt.textContent=va,Fs=p(`. Subroutines do not, by default, “save” the
398values of any registers either when they are called or when they return.
399In most higher-level programming languages, this is taken care of for you
400through concepts like “variable scope” or “lifetimes”. In assembly, though,
401you must handle saving and restoring the state of all registers (including
402the processor status register!) if you need those values to remain the
403same when returning from a subroutine.`),X(ye.$$.fragment),Cn=h(),me=a("h2"),me.textContent=Ea,bn=h(),ze=a("p"),ze.innerHTML=wa,vn=h(),Ie=a("p"),Ie.textContent=Fa,En=h(),Ne=a("pre"),Ne.innerHTML=xa,wn=h(),J=a("p"),xs=p(`When the NMI handler is called, the
404first six opcodes preserve the state of the registers on the stack
405before doing anything else. First, we push the value of the accumulator, and then transfer and
406push the values of the X and Y registers. With everything stored on
407the stack, we are free to use all of the 6502’s registers without
408worrying about what the code that was interrupted expects
409to find in them. Once the NMI handler is finished, we reverse
410all of the storing we did at the beginning. We restore everything in the
411opposite order of how we stored it, first pulling and transferring to
412the Y and X registers, then the accumulator. Finally, we end with `),Pt=a("code"),Pt.textContent=ga,gs=p(`, which returns program flow
413to the point where the NMI handler was called. For a subroutine, we
414would end with `),Ht=a("code"),Ht.textContent=_a,_s=p(" (Return from Subroutine) instead."),X(fe.$$.fragment),Fn=h(),Ce=a("h2"),Ce.textContent=$a,xn=h(),qe=a("p"),qe.innerHTML=Aa,gn=h(),We=a("pre"),We.innerHTML=ka,_n=h(),je=a("p"),je.innerHTML=Ta,$n=h(),Be=a("p"),Be.innerHTML=Ma,An=h(),Ge=a("p"),Ge.innerHTML=La,kn=h(),Je=a("p"),Je.textContent=Da,Tn=h(),Ye=a("pre"),Ye.innerHTML=Pa,Mn=h(),Xe=a("p"),Xe.innerHTML=Ha,Ln=h(),be=a("h2"),be.textContent=Sa,Dn=h(),Ze=a("p"),Ze.innerHTML=Ra,Pn=h(),Qe=a("pre"),Qe.innerHTML=Oa,Hn=h(),Ke=a("p"),Ke.innerHTML=za,Sn=h(),Ue=a("p"),Ue.innerHTML=Ia,Rn=h(),Ve=a("pre"),Ve.innerHTML=Na,On=h(),et=a("p"),et.innerHTML=qa,zn=h(),tt=a("pre"),tt.innerHTML=Wa,In=h(),nt=a("p"),nt.innerHTML=ja,Nn=h(),_=a("p"),$s=p("If the result of the first comparison was that "),St=a("code"),St.textContent=Ba,As=p(` is
415not near the right edge of the screen, it’s time to test if
416`),Rt=a("code"),Rt.textContent=Ga,ks=p(` is near the left edge of the screen. We compare
417`),Ot=a("code"),Ot.textContent=Ja,Ts=p(" with "),zt=a("code"),zt.textContent=Ya,Ms=p(", and this time we use "),It=a("code"),It.textContent=Xa,Ls=p(`.
418`),Nt=a("code"),Nt.textContent=Za,Ds=p(`, as explained above, will activate if the accumulator
419(`),qt=a("code"),qt.textContent=Qa,Ps=p(") was larger than the comparison value ("),Wt=a("code"),Wt.textContent=Ka,Hs=p(`).
420In that case, we are not near the left edge and can skip
421forward to actually updating `),jt=a("code"),jt.textContent=Ua,Ss=p(`. Otherwise, we need
422to update `),Bt=a("code"),Bt.textContent=Va,Rs=p(" to be "),Gt=a("code"),Gt.textContent=eo,Os=p(`, indicating “move
423right”.`),X(ve.$$.fragment),qn=h(),st=a("p"),st.innerHTML=to,Wn=h(),at=a("p"),at.textContent=no,jn=h(),ot=a("pre"),ot.innerHTML=so,Bn=h(),lt=a("p"),lt.textContent=ao,Gn=h(),rt=a("pre"),rt.innerHTML=oo,Jn=h(),pt=a("p"),pt.innerHTML=lo,Yn=h(),X(it.$$.fragment),Xn=h(),Ee=a("h2"),Ee.textContent=ro,Zn=
423h(),ct=a("p"),ct.textContent=po,Qn=h(),dt=a("ul"),dt.innerHTML=io,Kn=h(),ut=a("p"),ut.innerHTML=co,this.h()},l(e){u=o(e,"P",{"data-svelte-h":!0}),l(u)!=="svelte-7xy1f2"&&(u.textContent=c),E=y(e),C=o(e,"P",{});var s=oe(C);d=i(s,`First, we can no longer hard-code the positions of our sprites
424in cartridge ROM.`),Z(b.$$.fragment,s),F=i(s,` There are many choices for where we could put our
425sprite’s information, but the best location is “zero-page RAM”.`),s.forEach(t),m=y(e),x=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(x)!=="svelte-148x21h"&&(x.textContent=H),v=y(e),L=o(e,"P",{"data-svelte-h":!0}),l(L)!=="svelte-bm10p5"&&(L.innerHTML=I),w=y(e),M=o(e,"P",{});var te=oe(M);re=i(te,`What, then, is “zero-page RAM”? Page zero is the range of memory
426from `),O=o(te,"CODE",{"data-svelte-h":!0}),l(O)!=="svelte-9lgo22"&&(O.textContent=Zt),pe=i(te," to "),z=o(te,"CODE",{"data-svelte-h":!0}),l(z)!=="svelte-1vy0ex6"&&(z.textContent=Qt),ie=i(te,`. What makes page zero useful for things
427like sprite positions is its speed. The 6502 processor has a
428special addressing mode for working with zero-page RAM, which
429makes operations on zero-page addresses much faster than the
430same operation on other memory addresses. To use zero-page
431addressing, use one byte instead of two when providing a memory
432address. Let’s look at an example:`),Z(R.$$.fragment,te),te.forEach(t),we=y(e),N=o(e,"PRE",{"data-svelte-h":!0}),l(N)!=="svelte-1bsx30g"&&(N.innerHTML=ee),Fe=y(e),q=o(e,"P",{});var Jt=oe(q);W=i(Jt,`So, using zero-page addressing gives us very fast access to 256
433bytes of memory. Those 256 bytes are the ideal place to store
434values that your game will need to update or reference frequently,
435making them an ideal place to record things like the current score,
436the number of lives the player has, which stage or level the player
437is in, and the positions of the player, enemies, projectiles,
438etc.`),Z(j.$$.fragment,Jt),Jt.forEach(t),ae=y(e),D=o(e,"P",{});var Y=oe(D);ht=i(Y,`Let’s start using zero-page RAM in our code. Because only addresses from
439`),B=o(Y,"CODE",{"data-svelte-h":!0}),l(B)!=="svelte-jidb8y"&&(B.textContent=f),$=i(Y,` and up are ROM (i.e., part of your actual cartridge / code that
440you write), we can’t just write zero page values directly. Instead, we
441tell the assembler to `),yt=o(Y,"EM",{"data-svelte-h":!0}),l(yt)!=="svelte-ls71ye"&&(yt.textContent=Is),Vn=i(Y,` memory in page
442zero,`),Z(ce.$$.fragment,Y),es=i(Y," like this:"),Y.forEach(t),Kt=y(e),xe=o(e,"PRE",{"data-svelte-h":!0}),l(xe)!=="svelte-1qgrvkl"&&(xe.innerHTML=Ns),Ut=y(e),ge=o(e,"P",{"data-svelte-h":!0}),l(ge)!=="svelte-soesir"&&(ge.innerHTML=qs),Vt=y(e),_e=o(e,"P",{"data-svelte-h":!0}),l(_e)!=="svelte-6kz8a8"&&(_e.innerHTML=Ws),en=y(e),$e=o(e,"PRE",{"data-svelte-h":!0}),l($e)!=="svelte-m2tsta"&&($e.innerHTML=js),tn=y(e),Ae=o(e,"P",{"data-svelte-h":!0}),l(Ae)!=="svelte-1vkbv8z"&&(Ae.innerHTML=Bs),nn=y(e),ke=o(e,"PRE",{"data-svelte-h":!0}),l(ke)!=="svelte-1k1j4s5"&&(ke.innerHTML=Gs),sn=y(e),Te=o(e,"P",{"data-svelte-h":!0}),l(Te)!=="svelte-1iez9c9"&&(Te.innerHTML=Js),an=y(e),Me=o(e,"PRE",{"data-svelte-h":!0}),l(Me)!=="svelte-to9okm"&&(Me.innerHTML=Ys),on=y(e),G=o(e,"P",{});var ne=oe(G);ts=i(ne,"Then, in "),mt=o(ne,"CODE",{"data-svelte-h":!0}),l(mt)!=="svelte-24ob1s"&&(mt.textContent=Xs),ns=i(ne,", we can use an "),ft=o(ne,"CODE",{"data-svelte-h":!0}
442),l(ft)!=="svelte-mofkpx"&&(ft.textContent=Zs),ss=i(ne," directive:"),Z(de.$$.fragment,ne),ne.forEach(t),ln=y(e),Le=o(e,"PRE",{"data-svelte-h":!0}),l(Le)!=="svelte-445s1b"&&(Le.innerHTML=Qs),rn=y(e),De=o(e,"P",{"data-svelte-h":!0}),l(De)!=="svelte-1oy5bni"&&(De.textContent=Ks),pn=y(e),ue=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(ue)!=="svelte-y94tw"&&(ue.textContent=Us),cn=y(e),Pe=o(e,"P",{"data-svelte-h":!0}),l(Pe)!=="svelte-1bng3l7"&&(Pe.innerHTML=Vs),dn=y(e),He=o(e,"P",{"data-svelte-h":!0}),l(He)!=="svelte-lgf2ec"&&(He.innerHTML=ea),un=y(e),Se=o(e,"P",{"data-svelte-h":!0}),l(Se)!=="svelte-1wmj4w4"&&(Se.textContent=ta),hn=y(e),Re=o(e,"PRE",{"data-svelte-h":!0}),l(Re)!=="svelte-14wodl1"&&(Re.innerHTML=na),yn=y(e),Oe=o(e,"P",{"data-svelte-h":!0}),l(Oe)!=="svelte-dh4sku"&&(Oe.innerHTML=sa),mn=y(e),P=o(e,"P",{});var S=oe(P);as=i(S,`On the 6502, the stack is 256 bytes in size and is located at
443`),Ct=o(S,"CODE",{"data-svelte-h":!0}),l(Ct)!=="svelte-1tmvg93"&&(Ct.textContent=aa),os=i(S," to "),bt=o(S,"CODE",{"data-svelte-h":!0}),l(bt)!=="svelte-1gyb553"&&(bt.textContent=oa),ls=i(S,`. The 6502 uses a special register,
444the “stack pointer” (often abbreviated “S”), to indicate where the
445“top” of the stack is. When the system is first initialized, the
446value of the stack pointer is `),vt=o(S,"CODE",{"data-svelte-h":!0}),l(vt)!=="svelte-1prbrbe"&&(vt.textContent=la),rs=i(S,`. Every time something is stored
447on the stack, it is written to `),Et=o(S,"CODE",{"data-svelte-h":!0}),l(Et)!=="svelte-1tmvg93"&&(Et.textContent=ra),ps=i(S,` plus the address held in the stack pointer
448(e.g., the first write to the stack is stored at `),wt=o(S,"CODE",{"data-svelte-h":!0}),l(wt)!=="svelte-1gyb553"&&(wt.textContent=pa),is=i(S,`), and
449then the stack pointer is decremented by one.`),Z(he.$$.fragment,S),cs=i(S,` When a value is removed from the stack, the stack pointer
450is incremented by one.`),S.forEach(t),fn=y(e),g=o(e,"P",{});var A=oe(g);ds=i(A,"So, on line 2, the processor sees a "),Ft=o(A,"CODE",{"data-svelte-h":!0}),l(Ft)!=="svelte-ayk0pb"&&(Ft.textContent=ia),us=i(A,` opcode and stores the current
451value of the program counter on the stack. Then, it takes the operand
452of the `),xt=o(A,"CODE",{"data-svelte-h":!0}),l(xt)!=="svelte-ayk0pb"&&(xt.textContent=ca),hs=i(A,` and puts that memory address into the program counter.
453Here, the processor skips from line 2 to line 6, and writes the literal
454value `),gt=o(A,"CODE",{"data-svelte-h":!0}),l(gt)!=="svelte-dzm2s5"&&(gt.textContent=da),ys=i(A," to the accumulator. The next opcode is an "),_t=o(A,"CODE",{"data-svelte-h":!0}),l(_t)!=="svelte-145hg73"&&(_t.textContent=ua),ms=i(A,`. When the
4556502 sees an `),$t=o(A,"CODE",{"data-svelte-h":!0}),l($t)!=="svelte-145hg73"&&($t.textContent=ha),fs=i(A,`, it takes the “top” value from the stack (often referred
456to as “popping” and item off the stack) and puts it into the program
457counter. Given the way the stack works, this `),At=o(A,"EM",{"data-svelte-h":!0}),l(At)!=="svelte-19iyz7h"&&(At.textContent=ya),Cs=i(A,` be the address
458that was “pushed onto” the stack back when the processor saw a `),kt=o(A,"CODE",{"data-svelte-h":!0}),l(kt)!=="svelte-ayk0pb"&&(kt.textContent=ma),bs=i(A,`.
459This pulls us back to whatever code is immediately after the `),Tt=o(A,"CODE",{"data-svelte-h":!0}),l(Tt)!=="svelte-ayk0pb"&&(Tt.textContent=fa),vs=i(A,`.
460Here, that means `),Mt=o(A,"CODE",{"data-svelte-h":!0}),l(Mt)!=="svelte-cj4m7c"&&(Mt.textContent=Ca),Es=i(A," - and the result will be writing "),Lt=o(A,"CODE",{"data-svelte-h":!0}),l(Lt)!=="svelte-dzm2s5"&&(Lt.textContent=ba),ws=i(A,`
461to that memory address, not `),Dt=o(A,"CODE",{"data-svelte-h":!0}),l(Dt)!=="svelte-1g2rstu"&&(Dt.textContent=va),Fs=i(A,`. Subroutines do not, by default, “save” the
462values of any registers either when they are called or when they return.
463In most higher-level programming languages, this is taken care of for you
464through concepts like “variable scope” or “lifetimes”. In assembly, though,
465you must handle saving and restoring the state of all registers (including
466the processor status register!) if you need those values to remain the
467same when returning from a subroutine.`),Z(ye.$$.fragment,A),A.forEach(t),Cn=y(e),me=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(me)!=="svelte-1x5smz"&&(me.textContent=Ea),bn=y(e),ze=o(e,"P",{"data-svelte-h":!0}),l(ze)!=="svelte-1muw7kb"&&(ze.innerHTML=wa),vn=y(e),Ie=o(e,"P",{"data-svelte-h":!0}),l(Ie)!=="svelte-330crq"&&(Ie.textContent=Fa),En=y(e),Ne=o(e,"PRE",{"data-svelte-h":!0}),l(Ne)!=="svelte-vsc4ug"&&(Ne.innerHTML=xa),wn=y(e),J=o(e,"P",{});var se=oe(J);xs=i(se,`When the NMI handler is called, the
468first six opcodes preserve the state of the registers on the stack
469before doing anything else. First, we push the value of the accumulator, and then transfer and
470push the values of the X and Y registers. With everything stored on
471the stack, we are free to use all of the 6502’s registers without
472worrying about what the code that was interrupted expects
473to find in them. Once the NMI handler is finished, we reverse
474all of the storing we did at the beginning. We restore everything in the
475opposite order of how we stored it, first pulling and transferring to
476the Y and X registers, then the accumulator. Finally, we end with `),Pt=o(se,"CODE",{"data-svelte-h":!0}),l(Pt)!=="svelte-1x7z3xt"&&(Pt.textContent=ga),gs=i(se,`, which returns program flow
477to the point where the NMI handler was called. For a subroutine, we
478would end with `),Ht=o(se,"CODE",{"data-svelte-h":!0}),l(Ht)!=="svelte-145hg73"&&(Ht.textContent=_a),_s=i(se," (Return from Subroutine) instead."),Z(fe.$$.fragment,se),se.forEach(t),Fn=y(e),Ce=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(Ce)!=="svelte-11tph11"&&(Ce.textContent=$a),xn=y(e),qe=o(e,"P",{"data-svelte-h":!0}),l(qe)!=="svelte-1mq89qg"&&(qe.innerHTML=Aa),gn=y(e),We=o(e,"PRE",{"data-svelte-h":!0}),l(We)!=="svelte-9t1s0h"&&(We.innerHTML=ka),_n=y(e),je=o(e,"P",{"data-svelte-h":!0}),l(je)!=="svelte-18a5s56"&&(je.innerHTML=Ta),$n=y(e),Be=o(e,"P",{"data-svelte-h":!0}),l(Be)!=="svelte-jukpfg"&&(Be.innerHTML=Ma),An=y(e),Ge=o(e,"P",{"data-svelte-h":!0}),l(Ge)!=="svelte-mfekdv"&&(Ge.innerHTML=La),kn=y(e),Je=o(e,"P",{"data-svelte-h":!0}),l(Je)!=="svelte-16o99kw"&&(Je.textContent=Da),Tn=y(e),Ye=o(e,"PRE",{"data-svelte-h":!0}),l(Ye)!=="svelte-1uf5554"&&(Ye.innerHTML=Pa),Mn=y(e),Xe=o(e,"P",{"data-svelte-h":!0}),l(Xe)!=="svelte-1l9p2t0"&&(Xe.innerHTML=Ha),Ln=y(e),be=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(be)!=="svelte-t1rxnj"&&(be.textContent=Sa),Dn=y(e),Ze=o(e,"P",{"data-svelte-h":!0}),l(Ze)!=="svelte-111l9y0"&&(Ze.innerHTML=Ra),Pn=y(e),Qe=o(e,"PRE",{"data-svelte-h":!0}),l(Qe)!=="svelte-e6ysk9"&&(Qe.innerHTML=Oa),Hn=y(e),Ke=o(e,"P",{"data-svelte-h":!0}),l(Ke)!=="svelte-1ul37au"&&(Ke.innerHTML=za),Sn=y(e),Ue=o(e,"P",{"data-svelte-h":!0}),l(Ue)!=="svelte-4ke2ad"&&(Ue.innerHTML=Ia),Rn=y(e),Ve=o(e,"PRE",{"data-svelte-h":!0}),l(Ve)!=="svelte-15448o9"&&(Ve.innerHTML=Na),On=y(e),et=o(e,"P",{"data-svelte-h":!0}),l(et)!=="svelte-rhupcv"&&(et.innerHTML=qa),zn=y(e),tt=o(e,"PRE",{"data-svelte-h":!0}),l(tt)!=="svelte-il1l0m"&&(tt.innerHTML=Wa),In=y(e),nt=o(e,"P",{"data-svelte-h":!0}),l(nt)!=="svelte-m7fgya"&&(nt.innerHTML=ja),Nn=y(e),_=o(e,"P",{});var k=oe(_);$s=i(k,"If the result of the first comparison was that "),St=o(k,"CODE",{"data-svelte-h":!0}),l(St)!=="svelte-mq7vv6"&&(St.textContent=Ba),As=i(k,` is
479not near the right edge of the screen, it’s time to test if
480`),Rt=o(k,"CODE",{"data-svelte-h":!0}),l(Rt)!=="svelte-mq7vv6"&&(Rt.textContent=Ga),ks=i(k,` is near the left edge of the screen. We compare
481`),Ot=o(k,"CODE",{"data-svelte-h":!0}),l(Ot)!=="svelte-mq7vv6"&&(Ot.textContent=Ja),Ts=i(k," with "),zt=o(k,"CODE",{"data-svelte-h":!0}),l(zt)!=="svelte-fidkbx"&&(zt.textContent=Ya),Ms=i(k,", and this time we use "),It=o(k,"CODE",{"data-svelte-h":!0}),l(It)!=="svelte-1pzbclw"&&(It.textContent=Xa),Ls=i(k,`.
482`),Nt=o(k,"CODE",{"data-svelte-h":!0}),l(Nt)!=="svelte-1tq694y"&&(Nt.textContent=Za),Ds=i(k,`, as explained above, will activate if the accumulator
483(`),qt=o(k,"CODE",{"data-svelte-h":!0}),l(qt)!=="svelte-mq7vv6"&&(qt.textContent=Qa),Ps=i(k,") was larger than the comparison value ("),Wt=o(k,"CODE",{"data-svelte-h":!0}),l(Wt)!=="svelte-fidkbx"&&(Wt.textContent=Ka),Hs=i(k,`).
484In that case, we are not near the left edge and can skip
485forward to actually updating `),jt=o(k,"CODE",{"data-svelte-h":!0}),l(jt)!=="svelte-mq7vv6"&&(jt.textContent=Ua),Ss=i(k,`. Otherwise, we need
486to update `),Bt=o(k,"CODE",{"data-svelte-h":!0}),l(Bt)!=="svelte-mpju21"&&(Bt.textContent=Va),Rs=i(k," to be "),Gt=o(k,"CODE",{"data-svelte-h":!0}),l(Gt)!=="svelte-r65vuv"&&(Gt.textContent=eo),Os=i(k,`, indicating “move
487right”.`),Z(ve.$$.fragment,k),k.forEach(t),qn=y(e),st=o(e,"P",{"data-svelte-h":!0}),l(st)!=="svelte-1mqwamx"&&(st.innerHTML=to),Wn=y(e),at=o(e,"P",{"data-svelte-h":!0}),l(at)!=="svelte-1clxtb5"&&(at.textContent=no),jn=y(e),ot=o(e,"PRE",{"data-svelte-h":!0}),l(ot)!=="svelte-qe8cbz"&&(ot.innerHTML=so),Bn=y(e),lt=o(e,"P",{"data-svelte-h":!0}),l(lt)!=="svelte-8iy88c"&&(lt.textContent=ao),Gn=y(e),rt=o(e,"PRE",{"data-svelte-h":!0}),l(rt)!=="svelte-us02ek"&&(rt.innerHTML=oo),Jn=y(e),pt=o(e,"P",{"data-svelte-h":!0}),l(pt)!=="svelte-6v31hj"&&(pt.innerHTML=lo),Yn=y(e),Z(it.$$.fragment,e),Xn=y(e),Ee=o(e,"H2",{id:!0,"data-svelte-h":!0}),l(Ee)!=="svelte-1tyj4ti"&&(Ee.textContent=ro),Zn=y(e),ct=o(e,"P",{"data-svelte-h":!0}),l(ct)!=="svelte-17q908u"&&(ct.textContent=po),Qn=y(e),dt=o(e,"UL",{"data-svelte-h":!0}),l(dt)!=="svelte-1xlhjsu"&&(dt.innerHTML=io),Kn=y(e),ut=o(e,"P",{"data-svelte-h":!0}),l(ut)!=="svelte-52g1od"&&(ut.innerHTML=co),this.h()},h(){Yt(x,"id","zero-page-ram"),Yt(ue,"id","subroutines"),Yt(me,"id","register-management"),Yt(Ce,"id","your-first-subroutine-drawing-the-player"),Yt(be,"id","putting-it-all-together"),Yt(Ee,"id","homework")},m(e,s){n(e,u,s),n(e,E,s),n(e,C,s),r(C,d),Q(b,C,null),r(C,F),n(e,m,s),n(e,x,s),n(e,v,s),n(e,L,s),n(e,w,s),n(e,M,s),r(M,re),r(M,O),r(M,pe),r(M,z),r(M,ie),Q(R,M,null),n(e,we,s),n(e,N,s),n(e,Fe,s),n(e,q,s),r(q,W),Q(j,q,null),n(e,ae,s),n(e,D,s),r(D,ht),r(D,B),r(D,$),r(D,yt),r(D,Vn),Q(ce,D,null),r(D,es),n(e,Kt,s),n(e,xe,s),n(e,Ut,s),n(e,ge,s),n(e,Vt,s),n(e,_e,s),n(e,en,s),n(e,$e,s),n(e,tn,s),n(e,Ae,s),n(e,nn,s),n(e,ke,s),n(e,sn,s),n(e,Te,s),n(e,an,s),n(e,Me,s),n(e,on,s),n(e,G,s),r(G,ts),r(G,mt),r(G,ns),r(G,ft),r(G,ss),Q(de,G,null),n(e,ln,s),n(e,Le,s),n(e,rn,s),n(e,De,s),n(e,pn,s),n(e,ue,s),n(e,cn,s),n(e,Pe,s),n(e,dn,s),n(e,He,s),n(e,un,s),n(e,Se,s),n(e,hn,s),n(e,Re,s),n(e,yn,s),n(e,Oe,s),n(e,mn,s),n(e,P,s),r(P,as),r(P,Ct),r(P,os),r(P,bt),r(P,ls),r(P,vt),r(P,rs),r(P,Et),r(P,ps),r(P,wt),r(P,is),Q(he,P,null),r(P,cs),n(e,fn,s),n(e,g,s),r(g,ds),r(g,Ft),r(g,us),r(g,xt),r(g,hs),r(g,gt),r(g,ys),r(g,_t),r(g,ms),r(g,$t),r(g,fs),r(g,At),r(g,Cs),r(g,kt),r(g,bs),r(g,Tt),r(g,vs),r(g,Mt),r(g,Es),r(g,Lt),r(g,ws),r(g,Dt),r(g,Fs),Q(ye,g,null),n(e,Cn,s),n(e,me,s),n(e,bn,s),n(e,ze,s),n(e,vn,s),n(e,Ie,s),n(e,En,s),n(e,Ne,s),n(e,wn,s),n(e,J,s),r(J,xs),r(J,Pt),r(J,gs),r(J,Ht),r(J,_s),Q(fe,J,null),n(e,Fn,s),n(e,Ce,s),n(e,xn,s),n(e,qe,s),n(e,gn,s),n(e,We,s),n(e,_n,s),n(e,je,s),n(e,$n,s),n(e,Be,s),n(e,An,s),n(e,Ge,s),n(e,kn,s),n(e,Je,s),n(e,Tn,s),n(e,Ye,s),n(e,Mn,s),n(e,Xe,s),n(e,Ln,s),n(e,be,s),n(e,Dn,s),n(e,Ze,s),n(e,Pn,s),n(e,Qe,s),n(e,Hn,s),n(e,Ke,s),n(e,Sn,s),n(e,Ue,s),n(e,Rn,s),n(e,Ve,s),n(e,On,s),n(e,et,s),n(e,zn,s),n(e,tt,s),n(e,In,s),n(e,nt,s),n(e,Nn,s),n(e,_,s),r(_,$s),r(_,St),r(_,As),r(_,Rt),r(_,ks),r(_,Ot),r(_,Ts),r(_,zt),r(_,Ms),r(_,It),r(_,Ls),r(_,Nt),r(_,Ds),r(_,qt),r(_,Ps),r(_,Wt),r(_,Hs),r(_,jt),r(_,Ss),r(_,Bt),r(_,Rs),r(_,Gt),r(_,Os),Q(ve,_,null),n(e,qn,s),n(e,st,s),n(e,Wn,s),n(e,at,s),n(e,jn,s),n(e,ot,s),n(e,Bn,s),n(e,lt,s),n(e,Gn,s),n(e,rt,s),n(e,Jn,s),n(e,pt,s),n(e,Yn,s),Q(it,e,s),n(e,Xn,s),n(e,Ee,s),n(e,Zn,s),n(e,ct,s),n(e,Qn,s),n(e,dt,s),n(e,Kn,s),n(e,ut,s),Un=!0},p(e,s){const te={};s&2&&(te.$$scope={dirty:s,ctx:e}),b.$set(te);const Jt={};s&2&&(Jt.$$scope={dirty:s,ctx:e}),R.$set(Jt);const Y={};s&2&&(Y.$$scope={dirty:s,ctx:e}),j.$set(Y);const ne={};s&2&&(ne.$$scope={dirty:s,ctx:e}),ce.$set(ne);const S={};s&2&&(S.$$scope={dirty:s,ctx:e}),de.$set(S);const A={};s&2&&(A.$$scope={dirty:s,ctx:e}),he.$set(A);const se={};s&2&&(se.$$scope={dirty:s,ctx:e}),ye.$set(se);const k={};s&2&&(k.$$scope={dirty:s,ctx:e}),fe.$set(k);const uo={};s&2&&(uo.$$scope={dirty:s,ctx:e}),ve.$set(uo)},i(e){Un||(K(b.$$.fragment,e),K(R.$$.fragment,e),K(j.$$.fragment,e),K(ce.$$.fragment,e),K(de.$$.fragment,e),K(he.$$.fragment,e),K(ye.$$.fragment,e),K(fe.$$.fragment,e),K(ve.$$.fragment,e),K(it.$$.fragment,e),Un=!0)},o(e){U(b.$$.fragment,e),U(R.$$.fragment,e),U(j.$$.fragment,e),U(ce.$$.fragment,e),U(de.$$.fragment,e),U(he.$$.fragment,e),U(ye.$$.fragment,e),U(fe.$$.fragment,e),U(ve.$$.fragment,e),U(it.$$.fragment,e),Un=!1},d(e){e&&(t(u),t(E),t(C),t(m),t(x),t(v),t(L),t(w),t(M),t(we),t(N),t(Fe),t(q),t(ae),t(D),t(Kt),t(xe),t(Ut),t(ge),t(Vt),t(_e),t(en),t($e),t(tn),t(Ae),t(nn),t(ke),t(sn),t(Te),t(an),t(Me),t(on),t(G),t(ln),t(Le),t(rn),t(De),t(pn),t(ue),t(cn),t(Pe),t(dn),t(He),t(un),t(Se),t(hn),t(Re),t(yn),t(Oe),t(mn),t(P),t(fn),t(g),t(Cn),t(me),t(bn),t(ze),t(vn),t(Ie),t(En),t(Ne),t(wn),t(J),t(Fn),t(Ce),t(xn),t(qe),t(gn),t(We),t(_n),t(je),t($n),t(Be),t(An
487),t(Ge),t(kn),t(Je),t(Tn),t(Ye),t(Mn),t(Xe),t(Ln),t(be),t(Dn),t(Ze),t(Pn),t(Qe),t(Hn),t(Ke),t(Sn),t(Ue),t(Rn),t(Ve),t(On),t(et),t(zn),t(tt),t(In),t(nt),t(Nn),t(_),t(qn),t(st),t(Wn),t(at),t(jn),t(ot),t(Bn),t(lt),t(Gn),t(rt),t(Jn),t(pt),t(Yn),t(Xn),t(Ee),t(Zn),t(ct),t(Qn),t(dt),t(Kn),t(ut)),V(b),V(R),V(j),V(ce),V(de),V(he),V(ye),V(fe),V(ve),V(it,e)}}}function Do(T){let u,c;const E=[T[0],mo];let C={$$slots:{default:[Lo]},$$scope:{ctx:T}};for(let d=0;d<E.length;d+=1)C=zs(C,E[d]);return u=new vo({props:C}),{c(){X(u.$$.fragment)},l(d){Z(u.$$.fragment,d)},m(d,b){Q(u,d,b),c=!0},p(d,[b]){const F=b&1?Eo(E,[b&1&&yo(d[0]),b&0&&yo(mo)]):{};b&2&&(F.$$scope={dirty:b,ctx:d}),u.$set(F)},i(d){c||(K(u.$$.fragment,d),c=!0)},o(d){U(u.$$.fragment,d),c=!1},d(d){V(u,d)}}}const mo={title:"14. Sprite Movement",prev:{url:"13-backgroundgraphics",title:"13. Background Graphics"},next:{url:"15-scrolling",title:"15. Background Scrolling"}};function Po(T,u,c){return T.$$set=E=>{c(0,u=zs(zs({},u),ho(E)))},u=ho(u),[u]}class Io extends Co{constructor(u){super(),bo(this,u,Po,Do,fo,{})}}export{Io as component};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.