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">; "regular", 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">"ZEROPAGE"</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>"ZEROPAGE"</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">'player_y'</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">'player_x'</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">"ZEROPAGE"</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">"ZEROPAGE"</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">"ZEROPAGE"</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.