Coding NES Subroutines

  Рет қаралды 53,904

NesHacker

NesHacker

Күн бұрын

Learn all about programming subroutines in the 6502 assembly on the NES.
Support the channel on Patreon: / neshacker
Code Challenge:
Submissions will be chosen from the comments through 1/22/2023 and the winner selected and pinned on 2/1/2023.
Music:
Evgeny Bardyuzha - Speed Freak
2050 - Nova
Luke Melville - After Midnight
Alchemorph - Raintown (My Love fore You) - Instrumental Version
Chapters:
0:00 Introduction
0:28 Subroutines Explained
2:07 The Stack
5:08 Using Parameters
6:49 Coding Challenge

Пікірлер: 232
@aidangarvey7049
@aidangarvey7049 Жыл бұрын
Here's my submission for the challenge, it's my first time programming in 6502 so there might be mistakes (I'm more familiar with 68K) ; ============================================= ; pickup_refill ; --------------------------------------------- ; Refills player health or weapon from a pickup ; --------------------------------------------- ; Parameters: ; $00: pickup type (health = 0, weapon = 1) ; $01: pickup size (small = 0, large = 1) ; --------------------------------------------- ; Notes: ; - Player's health is stored at $0100 ; - Player's weapon charge is stored at $0101 ; ============================================= pickup_refill: ; get pickup type in X so desired player stat is at $0100,X ldx $00 ; load stat value into A lda $0100,X ; get pickup size, add appropriate amount to A ldy $01 beq small_pickup ; large pickup: grant 25 health/weapon adc #15 ; (intentional fall-through to add rest of value) small_pickup: ; small pickup: grant 10 health/weapon adc #10 ; if we went over 100 health/weapon, limit to 100 cmp #100 bmi save_value lda #100 save_value: ; store new health/weapon value sta $0100,X rts
@NesHacker
@NesHacker Жыл бұрын
Congrats! The patrons chose your code to get pinned! Shout out to the runners up: @dedgzus6808, @kentwidman, and @soulite2574 :D
@aidangarvey7049
@aidangarvey7049 Жыл бұрын
Thank you so much to everyone who voted for me!
@CallousCoder
@CallousCoder Жыл бұрын
That’ll do nicely for sure.
@EvilSandwich
@EvilSandwich Жыл бұрын
One tiny and easily fixable issue. It looks like you're storing the player's health and weapon charge on the Stack Page. Just swap out the $0100 and $0101 with $0300 and $0301 and you're perfect! :) Great job though!
@brighthades5968
@brighthades5968 Жыл бұрын
@@EvilSandwich Most games don't use the whole stack area so they can store other values there
@AndyScott
@AndyScott Жыл бұрын
I love watching these thinking "one day I'll do this" knowing full well I will not....yet I will watch this kind of magnificently crafted educational lesson all day long.
@zzeck431
@zzeck431 Жыл бұрын
There are online 6502 assemblers and emulators you can use to begin. I used skilldrick easy 6502, because I was too lazy to dig up my cc65 assembler setup.
@NesHacker
@NesHacker Жыл бұрын
Honestly I just think it’s cool that so many people like the things that I like too :)
@dedgzus6808
@dedgzus6808 Жыл бұрын
I always had the same thought to but then after this video I just opened notepad and wrote up some code. Give it a shot.
@InsaneFirebat
@InsaneFirebat Жыл бұрын
Programming has been an interest of mine since I was young, but it was super intimidating with no formal education. I started off making copy/paste edits in Super Metroid's speedrun practice hack source and eventually started looking up what the opcodes do. Once I started looking into addressing modes, the doors flew open and everything started to make sense. It's been very rewarding and I wish they'd taught me this stuff in elementary school. Hope you can dig in some day. The 65x processors are awesome.
@Cubearr
@Cubearr Жыл бұрын
Honestly and truly: Just start doing it. post about it on rhdn or anywhere else, ask questions, do research, thumb through sections of code and try to understand it. you can make it happen for you, it just takes some focus and a little bit of work. Doing it badly is fine, just doing it at all is fun and rewarding.
@guillermomoreno4287
@guillermomoreno4287 Жыл бұрын
The editing, information and quality are top notch
@NesHacker
@NesHacker Жыл бұрын
Thanks, I try my best :)
@MerrStudio
@MerrStudio Жыл бұрын
Holy crap this channel is underrated AF. Watched the video first, noticed the like count/views second. Both of these should be x100 at least! You just earned a sub sir.
@NesHacker
@NesHacker Жыл бұрын
Welp that’s how it goes, one sub at a time :)
@MatteoTarantino1979
@MatteoTarantino1979 Жыл бұрын
Agreed 100%
@scottwilliams895
@scottwilliams895 Жыл бұрын
First time watching your channel. Big ups to your style! This video is basically a course mini-lecture on teaching programming, while still being interesting to watch for those of us students who aren't doing the homework.
@NesHacker
@NesHacker Жыл бұрын
That’s the idea, at least. The hope is that the videos straddle the line between lecture and entertainment, and do it so everyone comes away with something 😀
@scottwilliams895
@scottwilliams895 Жыл бұрын
@@NesHacker You hit it just right! Half way thru, I was like "Yeah, I *should* learn to program in Assembly... for the NES!! "
@CallousCoder
@CallousCoder Жыл бұрын
Maybe you’ll like a lot of my content too. I have a rom of C64 and some Amiga now. And also ARM64 assembly on Linux. But also game hacking cracking which uses 6502, z80 and 68000
@MrBoogerblood
@MrBoogerblood Жыл бұрын
I’m addicted to these videos. I have way too many other things going on to ever hope to have time to mess with this too but you’re subject matter presentation is next level. So much info crammed into a 15-20 min video and it doesn’t feel overwhelming. Great job man.
@NesHacker
@NesHacker Жыл бұрын
Thanks, I put a lot into them so I am glad you like the videos so much 😀
@NesHacker
@NesHacker Жыл бұрын
Just an FYI: the finalists for the coding challenge have been selected and the poll is up on Patreon. Voting ends Monday (Feb 6th) at 11:59 PM EST, after which I'll pin the winning post here.
@dedgzus6808
@dedgzus6808 Жыл бұрын
I'd like to nominate my code for its simplicity and because it gets the job done in only 9 lines of code.
@NesHacker
@NesHacker Жыл бұрын
@@dedgzus6808 That was the very reason I chose you as one of the finalists. But now it's in the hands of the patrons ;D
@dedgzus6808
@dedgzus6808 Жыл бұрын
@@NesHacker Haha. Thanks. Also for your information, after I finally got myself around to writing those couple of lines of 6502asm it took hold of me and I've been working on getting a "game" working. Currently messing with getting scrolling working. Thanks for the videos.
@sanderbos4243
@sanderbos4243 8 ай бұрын
Found your channel yesterday while looking for 6502 documentation online, and your 6502 Assembly Crash Course playlist this is part of has been unimaginably helpful to me! I've also got VS Code set up with fceux64 using your tutorial, so it is time to crank out the classic Game of Life! :D
@jake967
@jake967 Жыл бұрын
Outstanding visuals!
@djrmarketing598
@djrmarketing598 Жыл бұрын
Funny when you say 6502 assembly the first thing that comes to mind is Commodore 64 programming, but that was 10 year old me back in the day having no idea that 6502's were in just about everything by 1988. Had I been 10 years older I probably could have put all that learning to use professionally, but alas it was my gateway to x86 assembly language. I made so many inline assembly routines inside C and Pascal programs back then, back when every cycle mattered.
@akkoestranha4323
@akkoestranha4323 Жыл бұрын
I was waiting this so much! Love your videos!
@NesHacker
@NesHacker Жыл бұрын
Thanks, I’m happy to oblige :)
@JustixLoL
@JustixLoL Жыл бұрын
Omfg, last month everything I've been doing is digging info about old consoles, especially the NES and programming 6502 cpu. Planned to develop a small NES game to touch it myself for better understanding and HERE YOU ARE - THE HERO! Right in time! Many thanks for you exceptionally helpful material! Please, keep going
@NesHacker
@NesHacker Жыл бұрын
The hero, huh? Haha, well I don't know about that, but I am glad I can help!
@3DSage
@3DSage Жыл бұрын
You make me want to program a NES game! Really great and clear explanation so thank you!
@Cr_nch
@Cr_nch Жыл бұрын
-3d on nes-
@NesHacker
@NesHacker Жыл бұрын
Nice! It’s definitely work but it is totally doable, just start small and build up from there :)
@maverick_loneshark
@maverick_loneshark Жыл бұрын
あけましておめでとうございます、 NESHacker! Kind of tied up with attempts at modern, wannabe-retro game dev right now (trying to write a better shader for simulating a high end CRT), but you have me inching closer and closer to doing a NES homebrew game jam. Thank you for all of the valuable NES dev info!
@NesHacker
@NesHacker Жыл бұрын
You’re more than welcome, and happy new year to you too, Maverick!
@jimmyraconteur2522
@jimmyraconteur2522 Жыл бұрын
LOL I love your handle! It reminds me of a character from a Yakuza game!
@maverick_loneshark
@maverick_loneshark Жыл бұрын
@@jimmyraconteur2522 for all we know, *this* IS a game...
@ebs777
@ebs777 Жыл бұрын
I been working on super mario bros hacks on and off for a couple years and even knowing the asm i do now your videos always teach me something new. Thank you so much
@NesHacker
@NesHacker Жыл бұрын
You’re very welcome, I’m glad to help :)
@ajhieb
@ajhieb Жыл бұрын
What a great start to the year! NesHacker and Retro Game Mechanics Explained posting new videos on the same day!
@NesHacker
@NesHacker Жыл бұрын
I considered releasing it yesterday… but I was worried people would be too tired to digest 6502 assembly xD
@tmanley1985
@tmanley1985 Жыл бұрын
I never subscribed so fast in my life. This is incredibly well done.
@NesHacker
@NesHacker Жыл бұрын
Nice! This was probably my best editing job thus far, so I hope you like my other videos too.
@Raubritterr222
@Raubritterr222 Жыл бұрын
I love your NES videos so MUCH! Thank you! 🎮
@NesHacker
@NesHacker Жыл бұрын
You’re very welcome :)
@gadgetdeez7069
@gadgetdeez7069 4 ай бұрын
I know this is an old video but i really like the format. Making the viewer do a little homework for a contest is legit awesome too. Love seeing atuff like this. Only gripe is i feel the vids are a little on the short side. Right when the itch is a out satisfied you pull the plug. Darnit. Lol
@Ribiveer
@Ribiveer Жыл бұрын
I haven't got a lot of experience writing assembly code from scratch, mainly having edited assembly from Super Mario Bros., so this is good exercise for me! Though that Super Mario Bros. is my only real experience with assembly might show a little... ; First, let's define RAM values. Starting at $0300 since you did in the video as well. ; Though I wonder, why not $0200? The stack ends at $01FF, and I can't find anything about $0200 - $02FF being used for anything. I do $0300 just to be safe, though. Bars = $0300 ; This is where the "list" of bars starts. Since it starts at the Health Bar, it's got the same value as it. HealthBar = $0300 WeaponBar = $0301 ; Somewhere else, we have some values for the amounts to add. These contain values of 10, 20 and 50. CapsuleValues: .db $0a, $14, $32 ; This is how this method would be called: ldy #$01 ; We load the type of bar to refill. In this case, the weapon bar. Storing it in Y will be useful for our trick coming up. ldx #$02 ; We load the amount to refill. In this case, 50. Storing it in X will be useful for our trick coming up jsr HandleCapsule ; Onto our subroutine! ; Somewhere else... HandleCapsule: lda Bars,y ; The Y register means that it gets added to the address, so we load the value at $0300 + $01 = $0301, the Weapon Bar, into the accumulator. clc ; Prepare for adding by clearing the carry. adc CapsuleValues,x ; We do the same trick here: add X to the address of our starting value. In this case, we add 2, so we get the third value from CapsuleValues: $32 cmp #$65 ; We compare the resulting value with 101 bcc ExitHandleCapsule ; If A < 101, we're good! We can exit the subroutine. lda #$64 ; Otherwise, we're gonna take the value of 100 instead ExitHandleCapsule: sta Bars,y ; Finally we store our value, be it 100 or something below it, into our designated Bar. rts ; We can go back to the previous part in the code, now!
@dedgzus6808
@dedgzus6808 Жыл бұрын
Very similar to my method expect you never push values onto the stack to be sure the registers don't get corrupted. also you used a more rigid amount method.
@ClassicTVMan1981X
@ClassicTVMan1981X Жыл бұрын
In Super Mario All-Stars (for the Super NES), the lives code for both Super Mario Bros. and Super Mario Bros.: The Lost Levels went like this: lda NumberofLives ; load the current player's lives counter inc NumberofLives ; increase the lives counter by one if Mario/Luigi collects a 1-UP Mushroom, 100 coins, knocks down eight or more enemies in a row with a Koopa shell or Buzzy Beetle, or stomps on a Koopa shell or Buzzy Beetle at least eight times on a stairstep. cmp #$80 ; compare resulting value with 128 bcc EndCheckL ; if A less than 128, we're fine and we can leave the subroutine! lda #$7f ; otherwise, set this value to 127 instead sta NumberofLives ; store whatever number we have, be it 127 or lower, into $075A, EndCheckL: rtl ; and leave! (the RTL at the end means "return from subroutine, long" which indicates we can use this subroutine in other program banks; for example, since the code above is originally in bank 4 at address 0x8596, if we want to jump to it in other program banks we use these four bytes: 22 96 85 04, the leading 22 pointing to JSL, or "jump to subroutine, long")
@Nat-qm5vb
@Nat-qm5vb 7 ай бұрын
To answer your question way after you asked it, by convention the $0200-$02FF space in RAM is used for sprite data, which gets written directly to the OAM DMA register on the PPU during VBLANK.
@Ribiveer
@Ribiveer 7 ай бұрын
@@Nat-qm5vb Ah, I see. Thank you for answering!
@8_BitKing
@8_BitKing Жыл бұрын
really nice videos and great animations!
@NesHacker
@NesHacker Жыл бұрын
Thanks!
@orti1283
@orti1283 Жыл бұрын
Thank you so much for such magnificent content!
@NesHacker
@NesHacker Жыл бұрын
Haha, "magnificent" is quite the compliment. Thank you!
@seanrobertson7122
@seanrobertson7122 Жыл бұрын
I think you're reaching a good pace/level of explanation with these last few videos... tbh I was a bit worried when inx/dex took up 3 minutes in the first one haha. Great to see the very practical example of using parameters especially.
@NesHacker
@NesHacker Жыл бұрын
Haha, yeah… Now that I’ve covered a lot of the basics I feel I can go more briskly and use broader strokes without getting bogged down in the details too much.
@calebyates6161
@calebyates6161 Жыл бұрын
Video is very well put together
@NesHacker
@NesHacker Жыл бұрын
Thanks Caleb!
@trapr00t
@trapr00t Жыл бұрын
Just love explanation clarity, EXCELLENT VIDEO, can't wait for more! (I eddited and removed INCORRECT stuff about pushing ppu status to the stack, that I writen before to awoid confusion)
@michaelbarry8005
@michaelbarry8005 Жыл бұрын
In my version of reality *BRK* , *IRQ* and *NMI* push the processor status register after pushing the return address (three bytes total), but *JSR* stacks only the return address - 1 (two bytes total).
@NesHacker
@NesHacker Жыл бұрын
Yeah I am pretty sure JSR doesn't push the processor status. At least according to my 1976 MOS Microcomputers Programming Manual, it doesn't :D
@trapr00t
@trapr00t Жыл бұрын
@@NesHacker ah, I'm so sorry for the missinformation, I checked it to, and it appears that I truly confused it with NMI I feel embarrassed, for my irresponsible comment before 😳
@brandongunnarson7483
@brandongunnarson7483 Жыл бұрын
I wish I knew the first thing about assembly but this is awesome!
@NesHacker
@NesHacker Жыл бұрын
Thanks :D, I’m glad you watched the episode anyway, haha
@Chad_Thundercock
@Chad_Thundercock Жыл бұрын
4:55 What, no man - Stack Overflow is always my first go to when I need something obscure sorted out.
@NesHacker
@NesHacker Жыл бұрын
😝
@menitoon8759
@menitoon8759 15 күн бұрын
When will the next episode be released ? I want to actually make a NES game ! But I really love your videos, they're so helpful !
@jimmyraconteur2522
@jimmyraconteur2522 Жыл бұрын
Your videos are excellent!
@NesHacker
@NesHacker Жыл бұрын
Thank you, I appreciate that :D
@keytronic5631
@keytronic5631 Жыл бұрын
Great to hear that you will do this full time. Lovely animations. How are you doing these? What software are you using? manim? Also what is your profession before you went all in on this channel? Cheers,
@NesHacker
@NesHacker Жыл бұрын
I use After Effects for the animations along with Photoshop and Illustrator to create most of the graphics. As far as what I did before the channel? It’s a shocker: I was a software engineer xD
@kyoobqa
@kyoobqa Жыл бұрын
For such quality, you are criminally underrated.
@NesHacker
@NesHacker Жыл бұрын
I guess that’s a lot better than being overrated xD
@consis
@consis Жыл бұрын
beautiful vid
@NesHacker
@NesHacker Жыл бұрын
Thanks!
@repeaterlanes8024
@repeaterlanes8024 Жыл бұрын
Health: $00FF Energy: $00FE 32 bytes in the zero page for subroutine parameters like you would do. 1 byte ($0000) actually used for this function. the High nybble (Bits 4 - 7) will be type, the Low nybble (Bits 0 - 3) will be the amount. This method would allow 16 types and 16 amounts in case it will be used elsewhere, however in this case it will be optimised for this challenge refill: lda #$F0 and $00 //Obtain the high nybble to dictate what type to add to lsr lsr lsr lsr tax lda #$19 //Load 25 into Accumulator. This is the small amount pha lda #$0F and $00 //Obtain the low nybble to dictate what amount to add to the variable beq skip_big_refill //If 0, then it is the small amount, otherwise add 25 to the value to get the medium amt pla adc #$19 //Add 25 to Accumulator, making the amount from earlier to the medium amount, 50 pha skip_big_refill: pla clc adc $FE, x //Add the corresponding variable (Health or Energy) to Accumulator cmp #$64 // check if result is more than 100. if so, set the Accumulator to 100 bpl skip_clamp lda #$64 skip_clamp: sta $FE, x //finally, store the accumulator to the variable rts (Fair note, its been a while since ive coded 6502 asm, so my syntax might be off. dont really have a way to verify it admittedly but i hope it works) (Edit: Forgot to shift the upper nibble parameter 4 times to the left)
@soulite2574
@soulite2574 Жыл бұрын
My code for the refill subroutine (expanded to avoid people spoiling themselves, ca65 syntax because that's what I'm used to) ("params" is a 32 byte variable in the zeropage, +0 +1 etc, are offsets) PlayerRefill: ;PLAYER REFILL SUBROUTINE ; (params+0: type) - if refill is for health or energy ; (params+1: amount) - how much health/energy to refill LDA params+0 CMP #$01 ;Switch on type (0-Energy Refill, 1-Health Refill) BNE :+ JMP PlayerRefillHealth : PlayerRefillEnergy: ;Add refill to energy LDA params+1 CLC ADC playerEnergy ;A = playerEnergy + ammount ;IF the result exceeds max energy, set to max energy CMP #100 BCC :+ LDA #100 : STA playerEnergy JMP PlayerRefillEnd PlayerRefillHealth: ;Add refill to health LDA params+1 CLC ADC playerHealth ;A = playerHealth + ammount ;IF the result exceeds max energy, set to max energy CMP #100 BCC :+ LDA #100 : STA playerHealth PlayerRefillEnd: RTS
@vakulasan4613
@vakulasan4613 Жыл бұрын
Amazing illustrations, great video editing and main - you can see it on "one breath" because every detail is explained. Keep doing so. Good luck. From me like 👍 and subscription🔔)
@NesHacker
@NesHacker Жыл бұрын
The plan is to keep going as long as I can ☺️
@thedrunkmonkshow
@thedrunkmonkshow Жыл бұрын
Thanks so much and now I better understand how this works in Assembly. As someone who's only dabbled with high level languages, I never understood how to replicate variables, Sub Routines and Functions in Assembly. I only knew the JMP command and not the JSR and RTS and i also didn't understand how to pass arguments to and from. There's an online Javascript 6502 emulator so yeah..lemme try building my own like a pixel plotting routine to put this new knowledge into action. 😄
@NesHacker
@NesHacker Жыл бұрын
You’re welcome, sounds like you’re in for a world of new fun :)
@jumanji4037
@jumanji4037 Жыл бұрын
Really nice video and well explained! I’ve been looking for some courses and tutorials for making NES games and your videos have really helped explain the basics. Which resources or websites would you recommend for learning more? Thanks and looking forward to your future videos!
@NesHacker
@NesHacker Жыл бұрын
www.nesdev.org/wiki/Nesdev_Wiki - This has a ton of information on programming the NES, but it can be a little hard to get through at times. I don't have any books in particular to share, sorry.
@jumanji4037
@jumanji4037 Жыл бұрын
Thanks! I’ll have a look to it.
@oleschoolgamers
@oleschoolgamers Жыл бұрын
Crazy editing skills, I think you're videos are as good as your NES explanations haha. What do you use for video editing anyway?
@NesHacker
@NesHacker Жыл бұрын
Thanks! I use Final Cut Pro to edit. After Effects, Illustrator, & Photoshop for graphics.
@marcus9374
@marcus9374 Жыл бұрын
Your videos are great!! Confrats for your work! One question I always have is how do things like events are coded using assembly. Examples like “when character touches an enemy, X happens”. The other one would be around types and hierarchy. Are analogies around objetc oriented programming observed somehow in these games code? If not, what are the constructs developers use to represente those concepts? Those would be great topics for a future video!
@NesHacker
@NesHacker Жыл бұрын
It's all done as part of the game loop. An event messaging system would be way to heavyweight to implement with such limited system resources. So you would simply do the checks for everything that "can" happen as part of the main game loop logic. Old-school game programming is quite a bit different than modern game engines.
@razorbackroar
@razorbackroar Жыл бұрын
Fav channel
@NesHacker
@NesHacker Жыл бұрын
Thanks choom 😉
@alexeisenhart
@alexeisenhart Жыл бұрын
This is a great video! What software do you use for your code animations?
@NesHacker
@NesHacker Жыл бұрын
I mostly use After Effects.
@BainesMkII
@BainesMkII Жыл бұрын
While I understand wanting to stick to a single concept, it feels like you should have mentioned manually saving and restoring register values with the stack (when necessary) when entering and exiting subroutines.
@NesHacker
@NesHacker Жыл бұрын
Yeah for sure, it’s always a challenge to figure out what to include and what not to. That’s a super valid and common use for the stack so I should have probably included it!
@exxor9108
@exxor9108 10 ай бұрын
The way that you speak and explain how subroutines work, I'd love to hear you explain the note block crash glitch in Super Mario Bros. 3. The one that speedrunners use to jump from world 7-1 to the chamber Princess Toadstool is held in. I say Toadstool because she wasn't named Peach in the US until after Super Mario 64.
@NesHacker
@NesHacker 10 ай бұрын
Oh interesting, yeah that's a pretty good idea. I'd have to do the research first, of course (and be able to pull it off myself so I can get a feel for it xD).
@spearPYN
@spearPYN Жыл бұрын
I am Atari 8-bit programmer but the 6502 assembly explanations are top notch.
@NesHacker
@NesHacker Жыл бұрын
Atari, C64, and NES programmers are all like cousins. Our choice in console is different, but we all love hacking some 6502 😆
@BillAnt
@BillAnt 8 ай бұрын
So what happens if a subroutine pushes more data onto the stack without popping it off before reaching the RTS? Would that mess up the RTS address? Gotta love a StackOverflow.... the programmer's website that is. ;)
@ChrisBouchard
@ChrisBouchard Жыл бұрын
I know in some architectures it's common to pass parameters and return values on the stack. E.g., push on the arguments before the JSR, and then write in the return value before the RTS. This has the benefit that subroutines are reentrant, but does eat up more stack space. Is this style used at all in NES programming?
@dedgzus6808
@dedgzus6808 Жыл бұрын
When JSR is called it pushes the address for the RTS onto the stack so you would have to pull that address off of the stack, store it, pull your parameters, store them, run your subroutine, push the return onto the stack and then load your return address, push it onto the stack and then call RTS. I don't know why anyone would do it that way but I am no expert.
@ChrisBouchard
@ChrisBouchard Жыл бұрын
@@dedgzus6808 In that calling convention, you would push your arguments before the JSR, and then read them by offset relative to the stack pointer inside the subroutine. (Though as I write this I'm not actually sure if the 6502 has stack-relative addressing. Without that, this would be painful, as you say.)
@ChrisBouchard
@ChrisBouchard Жыл бұрын
Reading more, I see that 6502 doesn't have native stack-relative addressing - so yeah, maybe this calling convention wouldn't be very popular for NES programing. I guess in theory you could move the stack pointer into the X register and use it to do indirect addressing. So you could do something like TSX ; Copy stack pointer into X. (I'm assuming that it points to the top of the stack -- if it points to the next free location, we need an extra INX.) INX ; Point one byte below stack pointer, first argument LDA $100,X ; Load argument INX ; Move pointer to next argument CLC ADC $100,X ; Add it to the second argument I suppose it would be easier to achieve reentrancy by passing arguments by known address and having the convention that the caller must preserve and restore those memory locations.
@ric8248
@ric8248 Жыл бұрын
This tutorials are absolutely awesome, made me instantly like and subscribe. Thank you very much for uploading. And ughh I hate to say this, but for some reason it bothers me to no end how the elements on the screen feel the need to jump whenever they are mentioned! It makes waaay more harm than good. So there you go, sorry for this unsolicited feedback, but it's been killing me lol.
@NesHacker
@NesHacker Жыл бұрын
So I spend a *lot* of time working on the animations for these videos, usually it is the majority of the work. In some sections I don't want to make things too complicated so the viewer can focus on what I'm saying while using the visual reference to help guide their understanding. That said, leaving still graphics up for too long can make things kinda boring, so I use the jump and camera zooms to keep a sense of motion while focusing on a single shot. If I find a better way to do this in the future, I'll certainly use the bounce less and and less :D
@ric8248
@ric8248 Жыл бұрын
@@NesHacker maybe it's my fault for binge watching all the videos since l discovered your channel yesterday
@NesHacker
@NesHacker Жыл бұрын
@@ric8248 Haha I find ZERO fault with you binge watching all of my videos 🤣
@NullUndefined1337
@NullUndefined1337 Жыл бұрын
😉 thanks XD nice video perfekt sound ^^
@NesHacker
@NesHacker Жыл бұрын
Yeah I was pretty happy with the sound design on this one. Glad you liked it! :D
@vuurniacsquarewave5091
@vuurniacsquarewave5091 Жыл бұрын
I think some context is needed to understand how I'd do this. I have a fixed size array of existing objects on the screen. Let's say the game can handle up to 16 of such. So the 16 bytes represent the object ID of the active object. A value of $FF represents that there is nothing in that slot and the game is free to use it for spawning a new object. This could be a bullet, a pickup, or the stage might want to spawn something, whatever the case may be. Every frame there is a subroutine called "ObjectHandler" that looks through the 16 ID slots and if the value is $FF it skips to the next one, otherwise it will load a 16-bit pointer with the object ID as the index into the pointer tables (one for the high byte, and one for the low byte) and then jump to that pointer. So now each object can have its behavior defined, but of course I could have the same pointer included in the tables more than once for common stuff. Let's say we're in the "obj_Capsule" routine from either of the four capsule items' object IDs. Now as you'll see this code makes a few assumptions and restricts you to the following rules to work properly: - The capsule object IDs MUST be arranged in order and their lowest two bits must be 00, 01, 10, 11 in that order. - The player's hp and weapon energy must be in two neighboring RAM addresses because we will add the capsules' refill amount to them in an indexed way. Starting state of the CPU registers: A - undefined, still holds part of the address we loaded X - Object ID we currently looked up and jumped to Y - undefined obj_Capsule: txa and #%00000011 ; use the low two bits of the object ID as a new index to grab the refill amount tay and #%00000001 ; create an index to decide if it's hp or weapon energy tax lda obj_Player_hp,x clc adc arr_obj_Capsule_refill,y ldx @zplocal_currentobjslot ; this is a temporary ZP variable the ObjectHandler uses to know which of the 16 slots it's processing right now, gets incremented after every slot lda #$FF sta obj_slot,x ; the object 'removes itself from the list of existing objects' ; here you could call an init subroutine to start a sound effect of the capsule being picked up rts ; goes to the common end point where processing one obj_slot ends arr_obj_Capsule_refill: .db $02,$04,$02,$04 ; we could have all four capsules have any arbitrary amount that they refill.
@luxuryhomes8889
@luxuryhomes8889 Жыл бұрын
so if the control flow has a routine and savor tine executing the task for the 16-bit on the stack??? i think im getting it
@grendell
@grendell Жыл бұрын
Any guidance for when to use a subroutine/.proc and when to use a macro? Am I correct in guessing that macros function similarly to C, with simple text replacement?
@NesHacker
@NesHacker Жыл бұрын
Macros can get really *really* tricky if you use them too much… I plan on doing an episode about my take on them, but here’s the TL;DR: if it’s something where you’d have to write out all the code anyway (e.g. setting parameters for a routine, etc.) then use a macro. If you absolutely have to save the cycles it would cost to perform the JSR and RTS *and* you can significantly improve the readability of your code then use a macro. Otherwise, stick with subroutines.
@michaelbarry8005
@michaelbarry8005 Жыл бұрын
Nicely done. At 3:30 you show the low byte of the return address being pushed first, which is incorrect, but only significant if you are doing low-level stack manipulation or manually constructing and pushing your own "return addresses" like Woz did in Sweet-16 and the Apple ][ monitor ROM.
@NesHacker
@NesHacker Жыл бұрын
Oops, yeah it's high-byte then low-byte of return address, right?
@MattHughson
@MattHughson Жыл бұрын
You mentioned coding your own games in this video a few times. Are there any NES homebrew you've worked on? Or do you do hacks?
@NesHacker
@NesHacker Жыл бұрын
I’ve done some really small game projects in the past and have been chipping away at a bigger project for a while now, though progress is slow since I started the channel 😂
@MattHughson
@MattHughson Жыл бұрын
@@NesHacker Awesome! I can't wait. Do you post dev updates on the project anywhere that I could follow (twitter, etc)?
@soulite2574
@soulite2574 Жыл бұрын
When I'm in an underrated channel challenge and my opponent is NesHacker (insert Squidward glass braking gif)
@NesHacker
@NesHacker Жыл бұрын
Not gonna lie, it’s unreasonable how happy your comment made me xD
@cron93
@cron93 Жыл бұрын
I do web programming, but if I wanted to get into this, is there a way to get the old source code for NES games and run them on a local computer?
@meepk633
@meepk633 Жыл бұрын
Great animations. What do you use?
@NesHacker
@NesHacker Жыл бұрын
I use After Effects mostly
@Diablokiller999
@Diablokiller999 Жыл бұрын
Maybe you should've said something about saving registers before entering a subroutine? Otherwise the subroutine could overwrite stuff you are currently calculating/using :D Also you can use the stack to transfer parameters or return values fast, since it uses only one clock cycle on most architectures.
@mykalimba
@mykalimba Жыл бұрын
If your subroutine is simple/straightforward enough, you can often pass arguments in registers!
@NesHacker
@NesHacker Жыл бұрын
True, and super useful sometimes!
@majinnaibu
@majinnaibu Жыл бұрын
Why don't you use the stack for parameters/return values/local vars? Is there some larger problem with recursion on the NES that makes it not matter? Or maybe a lack of a good way to address the memory relative to the stack pointer? Cool tutorials by the way. I haven't touched asm in like 20 years.
@NesHacker
@NesHacker Жыл бұрын
You can use the stack to hold params, but it's kinda annoying since the jsr instruction pushes the return to the stack. So best case scenario you'd be pulling the stack pointer into the X register and doing some weird offset loads and then finally having to pop them off at the end. Not too bad, but if you're doing something where cycles count (like rendering during a PPU vblank) then it might bite you.
@mikethered123
@mikethered123 Жыл бұрын
Any tips for knowing “where” you are without knowing the memlocs/memory map? How does it know when to “interrupt” “normal” routines and do graphics? What about slow down?
@NesHacker
@NesHacker Жыл бұрын
Kinda, so the return values for each routine call will be pushed to the stack and the vectors that define the entry points for interrupt handlers are always located in the same spot of the ROM ($FFFA-$FFFF). It’s a little complicated but if you pause a program at any point you can work out if you’re in the “main” thread or an interrupt handler by working backwards through the call stack until you get either to the main loop or a handler. Though it’s possible to write code that obfuscates this by jumping into an interrupt handler and jumping out before the RTI.
@Kaijuking84
@Kaijuking84 Жыл бұрын
First of all what an Awesome channel. And secondly, I'm just gonna throw this out here I'm in school for computer programming and working full time with a family to support. Does anyone know of any resources I could use to help with my studies, I'm not a slow learner, but working full time trying to support my family kinda puts my brain on the fryer, some I'm looking for any resources I can find audiobooks, anything, something I can multi-task with while I'm working.
@thanhvinhle2893
@thanhvinhle2893 Жыл бұрын
struct capsule{ uint8_t type:1; uint8_t amount:7; } And then a function with parameter is that struct... Oops, sorry wrong language 😅
@johnmills3864
@johnmills3864 Жыл бұрын
Whooo !
@mykalimba
@mykalimba Жыл бұрын
For me, and possibly many other "old school" coders who got started on 8-bit home computers, calling too many subroutines in assembly language will always be the first thing that comes to mind when I hear the term "stack overflow". These days, most coders know "stack overflow" only to mean that website you go to when you don't know how to solve a coding problem and you need someone else to do it for you. :D
@NesHacker
@NesHacker Жыл бұрын
Mhm, I figured some of the newer folks wouldn’t know the term’s origin. So it was a fun thing to throw in there :)
@yod1213
@yod1213 Жыл бұрын
@NesHacker Can you do some SNES videos? Im especially interested in the SNES's sprite handling capabilities, because I always though that it was rather weak showing considering its specs.
@NesHacker
@NesHacker Жыл бұрын
I’m hoping to dip into some 16-bit content in the future, I’ll keep you and your wanting to see how sprites work in mind when I do
@scottwilliams895
@scottwilliams895 Жыл бұрын
Your content & production quality far exceeds your current # of Subscribers. 2023-01-29: 20.8K I expect that number will grow very quickly.
@NesHacker
@NesHacker Жыл бұрын
I think you might be right... 2023-01-31: 21.2K
@DobinSergei
@DobinSergei 9 ай бұрын
You didn't cover here saving and restoring registers values before and after subroutines. Without that, people get stuck in simplest task. For ex. if you use registers X or Y as a counter in loop, then JSR, where you definitely will change them, it will break everything.
@LBXZero
@LBXZero Жыл бұрын
From memory of my assembly language class, shouldn't there be other stack related instructions to store register values to the stack? One of the issues of jumping around to functions and subroutines is your subroutine interruption may involve using a register that already holds data that needs to be restored when jumping back to the parent loop. Of course, we can say that not saving important register outputs to memory in a timely manner is a bad thing as well as your parameter could be a value stored in a register for immediate access. But I will say when you jump around to subroutines, knowing the instructions to push register values on the stack and popping back into place is important.
@NesHacker
@NesHacker Жыл бұрын
It’s a good point, I considered going in-depth on the stack related registers but I felt it would drag the video a little off topic. That said, no reason I couldn’t do a follow up to give the stack a little more love :)
@LBXZero
@LBXZero Жыл бұрын
@@NesHacker I figure you will have a whole video in regards to the stack and all that fun.
@ssygon2
@ssygon2 Жыл бұрын
4:38 JSR many times without returning = stack buffer overflow 😂
@NesHacker
@NesHacker Жыл бұрын
Just write a recursive routine without a base case 😛
@lapalourde75
@lapalourde75 Жыл бұрын
👍 You use nesasm3 like compiler? Thanks
@RandyFortier
@RandyFortier Жыл бұрын
He posted a video which walks you through the environment setup. I recommend checking that out.
@NesHacker
@NesHacker Жыл бұрын
I use ca65 which is part of the cc65 suite. Like Randy said, check out my “NES Development Environment” video and I show the tools I use (for the most part, I mostly use Mesen now over FCEUX).
@lapalourde75
@lapalourde75 Жыл бұрын
@@NesHacker 👍😃
@JarppaGuru
@JarppaGuru 3 ай бұрын
6:58 i have know idea. im here learn LOL load value jump routine that do something with it- mean load 2 value(parameter) do something in subroutine based on parameter. thats that? i passed without coding
@nasrimarc7050
@nasrimarc7050 Жыл бұрын
You can imagine that, this game was coded in assembler language by the 90's dev team
@NesHacker
@NesHacker Жыл бұрын
Mind-blowing, right?
@Archeious
@Archeious Жыл бұрын
When passing the parameters why does you just push the parameters onto the stack? That is what we would do on old school x86 processors (and I think happens on current processors). I am not familiar is 6502.
@NesHacker
@NesHacker Жыл бұрын
Well you could, but there’s the issue that they’d be pushed prior to the JSR, so you’d have to do some bespoke stack handling to manage them along with the return address. The approach works fine, but it’s a lot easier to handle parameters in the zero page, especially if you don’t need a generalized and flexible approach (which is usually the case when writing 6502 assembly by hand).
@renecura
@renecura Жыл бұрын
I understand that you put the parameters in ram for clarity, so this comment is just to add a bit of info. In general, the parameters goes to the stack to be in some way just for the subroutine. And more, you can make recursive subroutines.
@NesHacker
@NesHacker Жыл бұрын
No, I put them in the RAM because this is how it is usually done when writing 6502 by hand. If you're working on compiler for a higher level language, this would probably be the way to handle them, but when programming in assembly this would rarely, if ever, be done.
@renecura
@renecura Жыл бұрын
@@NesHacker indeed, that is what a compiler does in general. I wonder why is this strategy not preferred when writing asm by hand.
@NesHacker
@NesHacker Жыл бұрын
@@renecura Mostly because of cycle overhead. Using stack manipulation instructions to manage the parameters on the stack adds a lot of cycles. The 2A03 (modified 6502) on the NES clocks in at 1.79 MHz on NTSC, which is really slow. Considering some operations, like VRAM updates, need to be done in roughly 2500 cycles and every little bit of optimization counts. Further, I think doing it that way causes your code to become *less* readable. Since you don't often need recursion, and most subroutines are *not* general purpose. It's best to simply map out the parameters to RAM for the application in most cases, as opposed to using a general purpose approach.
@renecura
@renecura Жыл бұрын
@@NesHacker great! Ty for the explaination!
@saltymashedpotatoes
@saltymashedpotatoes Жыл бұрын
Piece of cake.
@NesHacker
@NesHacker Жыл бұрын
I love cake :)
@o1phoenix79
@o1phoenix79 Жыл бұрын
The cake is a lie 😜😆
@kayakexcursions5570
@kayakexcursions5570 Жыл бұрын
;6502 asm: ;refill(x=type, c=amount) ;health type x=0 ;weapon type x=1 ;c = large amount (64) ;nc = small amount (32) healthVal = $00 ;players health value weaponVal = $01 ;players weapon value Refill: lda #32 ;set a as small amount bcc Small ;branch if small required lda #64 ;set a as large amount Small: clc ;clear carry for addition adc healthVal,x ;add a and value sta healthVal,x ;store new value cmp #101 ;check for overflow bcs Max ;branch if over 100 rts ;return Max: lda #100 ;set a as max value sta healthVal,x ;store max value rts ;return ;z80 asm: ;refill(z flag = type, c flag = amount) ;z = weapon type ;nz = health type ;c = large (64) ;nc = small (32) healthVal = $0000 weaponVal = $0001 Refill: ld a,32 ;set a as small amount jp nc,Small ;skip multiply if small selected rla ;set a as large amount Small: ld hl,healthVal ;point to health value jp nz,Health ;skip increment if health selected inc hl ;point to weapon value Health: add a,(hl) ;add amount to value cp 101 ;check for overflow ld (hl),a ;store new amount ret nc ;return if no overflow ld (hl),100 ;set value to max ret ;return with max value
@kayakexcursions5570
@kayakexcursions5570 Жыл бұрын
I know I said I was going to make an NES game in a previous comment, but unfortunately I haven't had time. That's going to be my new years resolution I guess, to make an NES game! Currently I only know z80 so I started off with that. I left the z80 in the comment and tried to convert it to 6502 as close as possible. Its my first time using 6502 and I realized using only flags as an input wasn't going to work. Lda modifies the z flag and rol a modifies both the z and c flag. I swapped rol a for lda so I could at least save the carry flag. z80 and 6502 are very similar, just have to forget about the extra registers.
@NesHacker
@NesHacker Жыл бұрын
Hey it’s no rush, just start small and chip away at it… But most of all, have fun learning and playing around. Hopefully my videos will help along the way, and know that I’m rooting for ya! :)
@soulite2574
@soulite2574 Жыл бұрын
dude really went above and beyond with the Z80 code, respect
@tr1p1ea
@tr1p1ea Жыл бұрын
Z80, nice 😀
@kayakexcursions5570
@kayakexcursions5570 Жыл бұрын
@@tr1p1ea Haha, I know you trip, Im the assembly bandit.
@Cyberfoxxy
@Cyberfoxxy Жыл бұрын
So you'd need to write a parameter stack too to use nested subroutines.
@NesHacker
@NesHacker Жыл бұрын
If you wanted a generalized approach, like an ABI for use by a compiler, you’d basically have to do that. A simple solution would be to have stack frames based on lexical levels to keep track of all the variables in a systematic way based on call. In practice when writing programs at the assembly level you don’t often need to go that deep. For instance, you can store variables elsewhere temporarily when you need to free up the parameter space.
@akko8210
@akko8210 Жыл бұрын
Hey! I got a Quick question in 1:19 in one of the lines of the code shows this: bpl :+ .What is this about?
@grendell
@grendell Жыл бұрын
bpl is "branch on plus" or "branch on positive", and ":+" refers to the next label in the code, so that bpl :+ looks at the result of the sbc, cmp's it to the value at $301, and skips the lda #0 if it is greater, presumably to avoid health going negative/underflowing. Hope that helps!
@akko8210
@akko8210 Жыл бұрын
@@grendell Thx man
@NesHacker
@NesHacker Жыл бұрын
You’re great @grendell, I’ve been shooting video all day and was finally taking a moment to come answer this and boom! You had me covered :)
@DarkKodKod
@DarkKodKod Жыл бұрын
Just to add to this answer. :+ refers to the next label. :++ is for the second next label, :- is to go back to the previous label. Usually you use unnamed labels to avoid collisions for some trivial code flow. Like a loop or just whatever you want that you think you don't need to name the label for whatever reason.
@darkseid2584
@darkseid2584 Жыл бұрын
I almost clicked on the back btn after hearing this 00:27
@ClergetMusic
@ClergetMusic Жыл бұрын
What is the synth piece playing ca. 5:45?
@NesHacker
@NesHacker Жыл бұрын
I think that’s “After Midnight” by Luke Melville. Just so you know, I usually put new songs I use in videos in the description for the video, ordered by when they’re played in the video :)
@Lilithe
@Lilithe Жыл бұрын
Solution: - 0 page has a table of value, 1-byte address (within 0 page) - routine takes a single byte, split into bits, each bit representing one of 8 stats to effect - routine starts by multiplying the active bit in the input byte by 2 byte address spaces within the table (each table entry has 2 bytes, a value and an address) - routine loads the target byte within the 0 page, based on the target address from the table, with the value from the table - return Does that work?
@kez963
@kez963 Жыл бұрын
Can I program nes using apple iic? 😅
@RetroCheats
@RetroCheats Жыл бұрын
I usually write game genie codes.
@NesHacker
@NesHacker Жыл бұрын
That makes sense, you know… considering 😂
@leandrormor
@leandrormor Жыл бұрын
I'm trying to paste either my code or my link but they are not showing up =|
@NesHacker
@NesHacker Жыл бұрын
Hmm… not sure what could be happening. Others have been able to post their code 🤔
@leandrormor
@leandrormor Жыл бұрын
@@NesHacker I got it, yt was filtering out if my code contains a link to .asm file
@technomicah
@technomicah Жыл бұрын
;I'm new at 6502 assembly, but I think I know a simple method for health/weapon refill subroutine currentHealth = $0300 ;current health value currentWeapon = $0301 ;current health value refillType = $0444 ;Refill type parameter. 0 is health and 1 is weapon refill refillAmount = $0445 ;Refill type parameter, small is 16 and large is 32 capsule: ldx refillType ;load refill type to X, making it the health/weapon modifyer lda currentHealth,x ;load current health/weapon to A clc adc refillAmount ;add refill amount to current health/weapon value cmp #$64 ;new value vs max value, max is 100 or 0x64 bcc :+ ;more than max? From the NES loops video lda #$64 ;we've exceeded max, load max value of 100 instead :sta currentHealth,x ;store new health/weapon level to RAM rts ;I've edited it a couple times as my understanding for 6502 gets clearer Prior to watching your videos I really had no idea on how 6502 assembly code worked. I've learned alot from watching your videos. This last video really challenged me to actually apply what I've learned. I'm amazed that I was able to come up with a solution that seems to make sense to me... Hope it makes sense. Thank you for your amazing videos!!! They've really satisfied a 30+ year desire to know how those old games worked. Looking forward to more. I'd like to some day edit the famicom game Convoy No Nazo to actually be playable
@technomicah
@technomicah Жыл бұрын
;After thinking about this for a couple of days, I think this routine should handle all the power-up items. ;I'd like to clean this up while its on my mind ;I'll store the current power-up item info in one masked byte @$0444 ;Edit, I forgot the Etanks currentHealth = $0300 ;current health level currentWeapon = $0301 ;current weapon level currentLives = $0302 ;current number of lives left currentEtanks = $0303 ;current number of etanks left collectedLetters = $0304 ;One byte that has the high 4 bits for the Beat letters collected and we can use the remaining 4 bits for something like the power balancer from MM6 powerUp = $0444 ;power-up ;Weapon/health-up when bit1 is set, bit0=weapon/health modifier (0 is health and 1 is weapon) and bit4/5 determine if its +16 or +32 weapon/health-up ;1-Up/Etank when bit2 is set, bit0 1=Etank, 0=1-Up, the other 6 bits arnt used in this case ;Beat letter (or power balancer) when bit3 is set, bit7=B, bit6=E, bit5=A, bit4=T, bit0=Power Balancer power-up: lda powerUp ; load powerUp byte to A and #$02 ; begin checking if its a health/weapon-up by looking at bit1 beq :Other Item ; if A is 0, branch to then check what kind of item it is lda powerUp ; load powerUp byte to A again and #$01 ; determine if its a health/weapon-up by looking at bit0 tax ; store result of A in X as our health/weapon modifier lda powerUp ; load powerUp byte to A for a 3rd time and #$30 ; so we get only the increase value of +16 or +32 clc adc currentHealth,x ; refill current health/weapon, offset by X cmp #$64 ; is the new value more than 100? bcc:+ ; branch over the next line if the carry is clear, meaning that adding the refill didnt exceed 100 lda #$64 ; load 100 (max refill) to A, we wont run this line unless we've met or exceeded max refill of 100 :sta currentHealth,x ; store new health/weapon amount after adding refill jmp End Sub-routine: ; jump to the end of the sub-routine Other Item: lda powerUp ; load powerUp byte to A, again and #$08 ; begin checking if its a BEAT letter or Power Balancer by looking at bit3 beq :Add 1-Up ; if A is 0, then item must be a 1-Up/Etank by process of elimination, jump to that code to finish it up lda powerUp ; load powerUp byte to A for the third time (didn't I say that already?) eor #$08 ; Exclusive Or out the bit that identifies it being a Beat/power balance item clc adc collectedLetters ; the location in RAM would have the same bit mask BEAT---(PowerBalancer), so I think adding it is okay, non? jmp End Sub-routine: ; jump to the end of the sub-routine Add 1-Up: lda powerUp ; load powerUp byte to A, again and #$01 ; check if its a 1-up/Etank by looking at bit0 tax ; store result of A in X as our 1-Up/Etank modifier inc currentLives, X ;increment lives or Etanks if X is 1 End Sub-routine: rts ; return from sub-routine ; I think that should do it. This time took me less time than the first
@2lt.hyakutaro382
@2lt.hyakutaro382 Жыл бұрын
My solution (although late for the challenge) I use the following memory locations: ; $00: character's health ; $01: character's energy ; $02: type param (=0 for health, =1 for weapon) ; $03: big/small param (=0 for small capsule, =1 for big capsule) capsule_values: .byte 20, 50, 30, 60 ; small health, big health, small energy, big energy refill: lda $02 asl adc $03 tax ldy $02 lda $00, y adc capsule_values, x cmp #100 bcc :+ ; if health(or energy) >= 100 lda #100 : sta $00, y rts
@dedgzus6808
@dedgzus6808 Жыл бұрын
I've never written any 6502 asm before but here ya go. Sorry if there are syntax errors and I tried to comment so you'd understand the addresses apply_item: ldx $01 ; $0001 is 0 for health, 1 for weapon lda $0300,x ; $0300 is address for health, $0301 for weapon clc adc $02 ; $0002 is amount cmp #100 ; check if it's over 100 bcc :+ lda #100 ; if so set to 100 : sta $0300,x ; store the result rts edit: removed pushing and pulling from stack as it is not assumed that it is done
@dedgzus6808
@dedgzus6808 Жыл бұрын
Any and all feedback would be welcome.
@xs6819
@xs6819 Жыл бұрын
You still write code for that old stuff!!!!!
@NesHacker
@NesHacker Жыл бұрын
Yeah it’s fun, there’s a whole hobby community of folks that do 😁
@SuperNickid
@SuperNickid 2 ай бұрын
@NESHacker: Could you explain the reason why sometimes because of a glitch in the game, the game can execute the X-cordonate of sprite as program code. kzbin.info/www/bejne/ol7Shpx9aN59e5o The stack did over flow into my capture card that is what cause the excessive corrupt graphic, the excessive corrupt graphic where not part of the game. My capture card is fine, it did not break it, and my capture card is still working properly. The JSR instruction place with the shell is JSR $8F$E3 Since the X of sprite start on $0090 that is mario X postion, $0091 X postion of the last enemies that spond if the other 4 are full. So the $0093 sprite cordinate de-spond at X coordinated $20, the $0094 at X coordinated $E3 and then $0095 at X coordinated $8F.
@sunxnes
@sunxnes Жыл бұрын
print "Hello World!"
@NesHacker
@NesHacker Жыл бұрын
I’m afraid that’s gonna cause a buffer overflow, you forgot the null character at the end! ;D
@zzeck431
@zzeck431 Жыл бұрын
I used skilldrick's easy 6502 define SMALL 2 define LARGE 10 define HEALTH 0 define ENERGY 1 define HEALTH_ADDR 2 define ENERGY_ADDR 3 LDA #HEALTH_ADDR STA 0 LDA #0 STA 1 LDA #100 STA HEALTH_ADDR LDA #1 STA ENERGY_ADDR LDA #LARGE LDY #ENERGY JSR meters ;for checking result in debugger registry dump LDA ENERGY_ADDR BRK ;A passes container size, SMALL or LARGE ;Y passes container type, HEALTH or ENERGY meters: CLC ADC (0), Y CMP #100 BCC less_max LDA #100 less_max: STA (0), Y RTS
@Dreddwinner
@Dreddwinner Жыл бұрын
💚🖤🖤🤎❤️💙💙💜😆
@NesHacker
@NesHacker Жыл бұрын
🥺
@ashlandwithouttheshd
@ashlandwithouttheshd Жыл бұрын
Stacks are FIFO not FILO
@NesHacker
@NesHacker Жыл бұрын
Queues are FIFO (First-In First Out). Stacks are very much FILO or LIFO (First-In Last-Out, or Last-In First-Out).
@ashlandwithouttheshd
@ashlandwithouttheshd Жыл бұрын
@@NesHacker you’re right. Looking at this again idk what I was thinking when I posted that
@hugeuglygorillaz9599
@hugeuglygorillaz9599 Жыл бұрын
Well, dammit... I get why the website is called "Stack Overflow" now. Nerds are weird. Lol
@joevaghn457
@joevaghn457 Жыл бұрын
Why the f*ck do you sound so much like swankybox XDDDD
@NesHacker
@NesHacker Жыл бұрын
I don't know who that is 🤔
@kentwidman
@kentwidman Жыл бұрын
It was fun messing around with how to structure the refill code and subroutines. This is what I came up with using your starting template: .export Main .segment "CODE" .proc Main ; Current healthbar value ldx #10 stx $0300 ; Current weaponbar value ldx #50 stx $0301 ; Call health/weapon refill subroutines. jsr small_health_refill ; after routine: healthbar = 18, weaponbar = 50 jsr large_health_refill ; after routine: healthbar = 48, weaponbar = 50 jsr large_health_refill ; after routine: healthbar = 78, weaponbar = 50 jsr small_health_refill ; after routine: healthbar = 86, weaponbar = 50 jsr small_weapon_refill ; after routine: healthbar = 86, weaponbar = 58 jsr large_weapon_refill ; after routine: healthbar = 86, weaponbar = 88 jsr large_health_refill ; after routine: healthbar = 100, weaponbar = 88 jsr large_health_refill ; after routine: healthbar = 100, weaponbar = 88 jsr small_health_refill ; after routine: healthbar = 100, weaponbar = 88 jsr small_weapon_refill ; after routine: healthbar = 100, weaponbar = 96 jsr large_weapon_refill ; after routine: healthbar = 100, weaponbar = 100 rts ; End of Main small_health_refill: ; load parameters for refill subroutine ldx #0 ; type = health stx $00 ldx #8 ; amount = 8 stx $01 jsr refill rts ; End of small_health_refill large_health_refill: ; load parameters for refill subroutine ldx #0 ; type = health stx $00 ldx #30 ; amount = 30 stx $01 jsr refill rts ; End of large_health_refill small_weapon_refill: ; load parameters for refill subroutine ldx #1 ; type = weapon stx $00 ldx #8 ; amount = 8 stx $01 jsr refill rts ; End of small_weapon_refill large_weapon_refill: ; load parameters for refill subroutine ldx #1 ; type = weapon stx $00 ldx #30 ; amount = 30 stx $01 jsr refill rts ; End of large_weapon_refill ; refills heathbar or weaponbar located at $0300 or $0301 ; params (type $00, amount $01) ; type == 0, setting heathbar ; type == 1, setting weaponbar refill: ldx $00 ; x is use as an offset for heathbar or weaponbar. lda $0300, X ; load heathbar or weaponbar clc adc $01 ; Add refill amount cmp #100 ; make sure new health/weapon value is not over 100 bcc skip_refill_limit lda #100 ; set health/weapon value to 100 skip_refill_limit: sta $0300, X ; set final amount for health or weapon bar. rts ; End of refill .endproc
@strayling1
@strayling1 Жыл бұрын
Looks good to me. This should be pinned.
@Octal_Covers
@Octal_Covers Жыл бұрын
; Here's the code I came up with ; Note: I'm a bit rusty with 6502 assembly, as the last time I did it was in 2019 ; How did I do? ; A: xxxxxxyy ; most sig y: type (0 -> health, 1 -> power) ; least sig y: value (0 -> small [5], 1 -> big [10]) refill: ; Push A to stack to store value pha ; Check size bit and $01 cmp $01 bne reAmEl ; Big ldx #0A jmp reAmEn ; Refill Amount Else reAmEl: ; Small ldx #05 ; Refill Amount End reAmEn: ; Pull A from stack to get value pla ; Check type bit and $02 cmp $02 bne reTyEl ; Energy stx $01 jmp ReTyEn ; Refill Type Else reTyEl: ; Health stx $00 ; Refill Type End reTyEn: rts
@iDontProgramInCpp
@iDontProgramInCpp Жыл бұрын
This should work.. ; refill(type, amount): ; How to call: ; pha
@matsbjnnes366
@matsbjnnes366 Жыл бұрын
Far from optimal, but after lots of debugging it seems to work as intended! The pickup data is controlled by the byte $00. The LSF controls the pickup size (0 means small, 1 is big) and the one to the left controls pickup type (0 is energy, 1 is health) ``` ; Memory Map ; ; Zero Page: ; $00 -> $1F - Parameters ; $20 -> $2F - Player Data .export Main .segment "CODE" .proc Main ; Player Health - Address $20 lda #50 sta $20 ; Player Energy - Address $21 lda #50 sta $21 ; Pickup small health orb lda #%00000010 sta $00 jsr Pickup rts .endproc ; Refill pickup - params in zero page $00 Pickup: ; Mask lsb - Pickup Size lda $00 and #%00000001 ; Test bit - 1 means big cmp #1 beq big bne small big: clc ; Mask second bit - Pickup Type lda $00 and #%00000010 ; Test bit - true means health cmp #2 bne :+ ; Health Pickup lda #30 adc $20 sta $20 rts ; Energy Pickup :lda #30 adc $21 sta $21 rts small: clc ; Mask second bit - Pickup Type lda $00 and #%00000010 ; Test bit - true means health cmp #2 bne :+ ; Health Pickup lda #15 adc $20 sta $20 rts ; Energy Pickup :lda #15 adc $21 sta $21 rts ```
@malsdenmd
@malsdenmd Жыл бұрын
M68K and pretty simplistic. Never wrote health code before, so I'm kind of just going on a whim Should be easy enough to port onto the 6502, it's just not my specialty ; --------------------------------------------------------------------------- ; Needs ; a0 = player, includes word-based pointers to RAM address for ease of alteration (multiple weapons, for instance) ; d0.bitfield = health type ; b0 = small/big ; b1 = health/weapon ; Uses ; d1 = misc ; a1 = misc ; --------------------------------------------------------------------------- BasicHealRoutine: moveq #8,d1 ; small increase btst #0,d0 ; if small, branch beq.s + moveq #32,d1 ; big increase + BasicHealRoutine_CustomHealth: movea.w playerhealthaddr(a0),a1 ; copy player health address btst #1,d0 ; if healing weapon, branch beq.s + movea.w playerweaponaddr(a0),a1 ; copy player weapon address + add.w d1,(a1) ; add health increase cmpi.w #100,(a1) ; has it overflowed? bls.s .rts ; if not, branch ; (bls: if this number or lower) move.w #100,(a1) ; manually set it to 100, fixing overflow .rts: rts
NES Graphics Explained
17:23
NesHacker
Рет қаралды 221 М.
Computing Pi on the NES
9:43
NesHacker
Рет қаралды 164 М.
小路飞的假舌头#海贼王  #路飞
00:15
路飞与唐舞桐
Рет қаралды 3,8 МЛН
Айттыңба - істе ! | Synyptas 3 | 7 серия
21:55
kak budto
Рет қаралды 1,5 МЛН
[실시간] 전철에서 찍힌 기생생물 감염 장면 | 기생수: 더 그레이
00:15
Netflix Korea 넷플릭스 코리아
Рет қаралды 38 МЛН
The World's Fastest Cleaners
00:35
MrBeast
Рет қаралды 109 МЛН
I Designed My Own 16-bit CPU
15:46
AstroSam
Рет қаралды 1,8 МЛН
Why Building a C++ Component in Unreal Engine is Easier Than You Think!
12:24
Assembly Language Snow Day!  Learn ASM Now!
32:13
Dave's Garage
Рет қаралды 101 М.
A closer look at the Super NES DOOM Source Code Release | MVG
13:49
Modern Vintage Gamer
Рет қаралды 723 М.
I made the same game in Assembly, C and C++
4:20
Nathan Baggs
Рет қаралды 619 М.
Does the NES Have a Secret Master System Port? | Nostalgia Nerd
12:30
Nostalgia Nerd
Рет қаралды 2 МЛН
Emulating a CPU in C++ (6502)
52:28
Dave Poo
Рет қаралды 943 М.
Basics - 6502 Assembly Crash Course 01
12:49
NesHacker
Рет қаралды 105 М.
Why it Took Tetris Pros 33 Years to Reach This Screen
14:07
okCobalt
Рет қаралды 1,1 МЛН
Теперь это его телефон
0:21
Хорошие Новости
Рет қаралды 138 М.
🤏 САМЫЙ ТОНКИЙ гаджет #Apple! 🍏
0:29
Яблочный Маньяк
Рет қаралды 477 М.