# How Wozniak’s code for the Apple 1 works

## Метаданные

- **Канал:** Ben Eater
- **YouTube:** https://www.youtube.com/watch?v=SpG8rgI7Hec
- **Просмотры:** 371,445
- **Источник:** https://ekstraktznaniy.ru/video/20732

## Описание

More 6502 stuff: https://eater.net/6502

Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support.

0:00 Variables
2:16 Hardware initialization
2:54 Reading input from the keyboard
10:18 Parsing the command
13:45 Parsing a hex value
21:29 Examine mode
28:28 Block examine mode
31:16 Store mode
34:28 Print routines

------------------

Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater

Special thanks to these supporters for making this video possible:
Adrien Friggeri, Aleksey Smolenchuk, An Dương, Anthony Weems, anula, Ben, Ben Cochran, Ben Williams, Bill Cooksey, Bill Watkins, Binh Tran, Богдан Федоров, Bradley Stach, Brian Haug, Burt Humburg, Carl Fooks, Carsten Schwender, Chai, Chaitanya Bhatt, Chris Anders, Chris Lajoie, Chris Sachs, criis, Cristi Cobzarenco, Daniel Pink, Daniel Tang, Daniel Zimmer, Dave W

## Транскрипт

### Variables []

I've got wasman the ROM monitor code from the original Apple one computer written by Steve Wozniak running on my 6502 breadboard computer and I've got a previous video that talks about what it can do but a number of people are interested in more details about how it works and so here's a copy of the original Apple or original instruction manual that came with the apple one and it includes the code for wasmon so that's where we'll start I've got that original code typed in here and you can see there's some identifier names like uh you know display keyboard control register display control register and these refer to addresses in memory either for variables or Hardware i o so if we look here you can see there's a list of variables that they've got here so the page 0 variables are stored in memory at the beginning so 2 4 refers to memory address zero two four but defining it as just two four has a couple advantages so you know these variables are replaced in the code when it's assembled so for example you know here we've got store y display Di SP and that gets assembled into the op code for store y or HC and then the address for display which is d012 it's in a different order there but that's how it assembles and so d012 is just the address for display so that's gets assembled into uh three bytes that one instruction and you know that has to be that way because the display is Hardware mapped to that address but if you just want to store a value in memory you can use a page zero variable or a page zero address which is just one byte for the you know the store instruction and then one byte for the address you know so for example here you know we have store x h so H is the variable so store X is eight six and then H is just 2 9 right so 2 9 is the H variable and so that makes your program smaller and you know remember all of wasmon is crammed into just 248 bytes of code so that's kind of a big deal but it also makes it faster by one instruction cycle so you know in General on the 6502 you know you want to have your most used variables in page 0 like this and so I've got all those variables defined up here like this and these are just substituted when the program's assembled for these numbers and then all the code is meant to be in raw MID address ff00 so I'll Define the start here at ff00 like that now when the 6502

### Hardware initialization [2:16]

is reset it starts executing at whatever address is in the reset Vector at fffc and so in this case at fffc now these bytes are in opposite order again but it's ff00 is where it starts executing and so that's the beginning of the code here this reset and in fact this first section here is only run when the computer is reset and it basically just sets up the display and keyboard loading a value into the Y register writing it to the display loading a value in the a register and writing it to the keyboard and display control registers to get the hardware set up now we don't have the same display and keyboard so you know we'll need to change all the setup code to get it to work on my computer

### Reading input from the keyboard [2:54]

but after the setup code this next section is the code that lets the user input a command now it's a little bit funky how we get into this but I think to understand it let's start down here where it's waiting for a key press so right here we'll talk about later how we get here but right here it's checking the keyboard control register and then Branch if positive back to NextCare so it just sits in a loop here until bit 7 of the keyboard control register flips which indicates that a key was pressed and then if it drops down to here where the key is loaded into the a register so once we've got a new key press in the a register it gets added to a text buffer that contains everything that the user has typed so far so the key press is stored at n plus y and N is you know address zero two zero and then the Y register is an offset so for example if we type ff00 dot ff0f you know until you hit enter it's putting each of these characters in into memory at you know zero two zero zero two zero one zero two and so on and then when we hit enter that's when it'll figure out what to do and you can see here n is you know zero two zero but really it has this whole range allocated for the input buffer so for now it's just storing each character in memory address zero two zero plus this offset Y which you'll see get incremented after each character then it jumps to a subroutine echo which will Echo the character back to the user so you can see what you're typing and then it checks to see if the key you hit was enter or carriage return and if not it Loops back to the top up here you know something to note is that on the Apple One all of the characters coming from the keyboard had a bit seven set so this 8D is kind of a strange representation for carriage return if you look at a normal ASCII table carriage return would be a zero D but here it has to check for 8D because that bit 7 is already set but anyhow if it's not a character turn then it Loops all the way back up to the top here we're checking to see if you hit a couple special keys so if you press backspace then it'll jump down here to this backspace routine if you press the Escape key then it'll jump down here to escape otherwise it increments Y and then jumps down back here to next character where it will read from the keyboard again you know so the normal path here is to you know read a key put it in the buffer Echo it and then jump back up to the top increment Y come back down here read the next key and so on but let's say you did hit backspace so you get up here and you detect ah we hit the backspace key which on the apple one was a DF you know first it'll Echo the backspace key which will move the cursor backwards it's not carriage return comes up here detects yes we hit backspace now it'll Branch down here to backspace where it will decrement Y and so that moves us backwards in our text buffer so that the next character typed will overwrite the previous character typed but then there's a check here to see if we backspaced beyond the start of the line and so this is kind of nice you can see here if I type ABC and then I press backspace backspace it just drops down to a new line so I can start over and so that's what this does if we decrement Y and then it wraps around and becomes negative branch of minus then we just jump up here where we load a carriage return Echo and then load a 1 into the Y register and the reason it initializes y to one instead of zero is because right after it does that we hit the decrement Y for backspace and then of course it's not minus anymore it's zero and we're right back here waiting for the next character now if we go back here if we hit Escape that prints that initial backspl backslash prompt and resets everything and you can see here how that works so if we come through here we've detected an escape then it branches here to escape it loads the character for backslash it echoes it then a carriage return and it echoes that sets y to Zero by setting it to one and decrementing it and then waits for the first key press that leaves an interesting question you know we talked about this reset code up here so when the computer is first reset it runs this code to initialize the hardware but then it just falls into this code here so you know what happens well the trick is that the display register for the hardware needs to be set to 7f and the code uses the Y register to do that and so then when the reset is finished and we fall down into this code here the Y register is set to 7f also the a register happens to have A7 in it so that doesn't match a backspace it doesn't match Escape but when we get here to increment y because y had a 7f in it it's now incremented to 8 0 which has that top bit set indicating that it's negative now BPL means Branch if positive that is if the top bit isn't set but since now it is we drop into this Escape routine and so that prints the backslash prints the carriage return initializes y to zero B4 ultimately ending up down here waiting for the first character now if you're a 21st century software developer you're probably a bit uncomfortable with all the weird dependencies in here you know like initializing y to one instead of zero and then depending on the backspace routine of all things to decrement it so it actually ends up to zero that might feel weird to you know or relying on this Hardware initialization code up here that has nothing to do with reading a character to leave this buffer index the Y variable or the Y register which ends up being the buffer index set to a particular value that will just happen to wrap around and overflow in a way and then relying on that to actually initialize it you know leaky abstraction doesn't really begin to describe this but that's what makes this code so efficient you know that's how Wozniak was able to pack so much functionality into just 248 bytes of code you know conversely if you think modern software has gone downhill and become bloated and inefficient and so on well maybe some of it is but modern software is a lot more complex than this because we demand a lot more from it you know if you try to do this level of optimization where you didn't care about abstraction at all on Modern software you know the interdependencies would create so much complexity that it would be you know virtually impossible to reason about yeah I think it's kind of what makes biological systems difficult to understand you know not only is biology complex but everything is sort of dependent on everything else in subtle ways kind of like this in a way and I don't know maybe that's the future of software systems is to use AI to evolve them into something more akin to biological systems who knows anyway I'm getting a little bit philosophical here but anyway the point is that by the time we get down to here whatever we typed is in memory at address zero two zero through zero two seven F if we inspect that address we can see uh 3 0 which is ASCII for the zero character that we typed 3 2 is ASCII for the two character we typed then zero 2E corresponds to the DOT and then 0 to 7 and then 4 6 corresponds to the f and then 0 D is the carriage return that we entered so sure enough what we typed is in memory here

### Parsing the command [10:18]

and then this next bit of code goes through that parses it and does whatever the command tells it to do so to parse the line Y is initialized to zero well it's initialized to FF and then incremented down here where it wraps around to zero then the a register and X register are also initialized to zero then for now since you know a is zero this arithmetic shift left doesn't do anything to the a register and so we store a or zero into the mode variable and mode is going to keep track of which type of command we're dealing with so 0 is examined so that's the case where we type in a single address to examine what's in it and 7B is store that's where we give an address and a value to store there so if we look at zero three zero now it's got a b e in it because that's what we stored there and then AE is block examine and that's where we want to examine a block of addresses so here we start going through the input character by character you know Y starts at zero so we get the first character from the input buffer and if we get a carriage return then we're done we jump back up to get line which is above to get the next command next it Compares with a DOT a e is a DOT is the comment indicates and the way compare works is that if the character is greater than dot it'll set the carry flag so this Branch carry clear will get taken for any character value that's less than a DOT so a comma or a space or you know really any of these characters that are you know less than dot so not numbers and letters that sort of thing and that just jumps up here to blank skip which increments Y and moves on to the next character and that's part of what lets you enter multiple commands like this if you want to examine zero two zero zero two zero one and zero two the parser just you know skips over the commas and spaces and such while just looking for the next command but if it's equal to the dot that we compared to up here then that suggests that we're dealing with something like this block examine mode so here where we did zero two zero dot that dot signifies hey we're doing a block examine and so if we jump up to set mode up here it stores the dot which on the apple one is a e hex so that's why AE represents block examine in our mode variable on the other hand if we encounter a colon which on the Apple is ba hex the colon means we want to store you know this value at that address so if we encounter a colon we jump up to set store and this does something a little bit odd it does an arithmetic shift left before setting the mode so instead of the colon which is you know this ba is the colon instead of just setting that as mode and using you know ba for store this shift turns ba into 7B by you know shifting all the bits to the left and then it just ends up using 7B as the mode for store now why does it do that we'll get to that in a minute but the result is that the mode variable gets set just like this comment suggests so zero means in exam mode 7B is for storing and AE is for Block exam mode and then finally it checks to see if we got a capital R and in that case it will jump to the last address that was examined and that's what the Run code does which we'll look at later on but

### Parsing a hex value [13:45]

once we're done parsing any of that stuff if there was any we end up in this next section of code where it tries to parse a hex value I'll scroll down here a little bit and so we're starting out here the X register will be zero here so we're initializing the l and H variables to zero and then we save the current value of the Y register into this y save variable and so remember the Y register is tracking the index of which character and the input that we're currently parsing and then l and H are going to end up with the low and high byte of whatever hex value we're about to parse and so here it grabs the current character that we're parsing and it's going to convert that character to a hex digit so to understand what it does here's an example of a numerical digit in this case a 3 and a hex letter digit I guess it's a hexit not a digit but whatever um B and on the Apple One the keyboard gives you ASCII with the top bit set so three is hex B3 is the Apple ones version of ASCII for that and then a b is hex C2 and there's the binary for each of those and I guess something else to note is that wasmon only works with capital letters so as you'll see this code kind of depends on this being a capital B but in either of these cases the first thing that the code does is xor with b0 hex so here's b0 and for the number that just flips all of these uh first bits to zeros so you end up you know we started with a three character and now we just have a three so you can see in the code here's the xor b0 and then it checks to see if it's less than zero a so in other words 0 through 9. if so we jump down here to digit otherwise we do some other stuff and so the other stuff applies just if we have something that's not a digit and the first thing we do is add with carry eight and because we just did this test the carry bit's always going to be set in this case so really we're adding eight nine is what that ultimately ends up being and that gives us this if we just add those which is FB in HEX it's what this process does is effectively map the characters a through F into the hex F A through FF so we started with a b and we end up with FB so here's the code we do the add with carry 88 and then it compares to see if it's less than F A so if it was a digit 0 through 9 then we're already down here in this digit code here but now if it's less than F A then that means it's not F A FB of C through FF so that means that the character is not zero through nine and it's not a through F so we've got a non-hex character so that could be a carriage return or who knows but we're done parsing the hex number and so we jump down to not hex which we'll get to in a minute otherwise we do four arithmetic shift lefts and what that does is it shifts the four bits of the digit over to the left so if we type to 3 we now have 3 0 if we type to B we now have b0 next we'll want to shift that into the h l bytes in memory where we'll be accumulating the 16-bit hex number that's being typed and so the way that'll work is let's say we typed a b like this so after this whole process we'll have b0 in the a register which in binary looks like this and basically what we want to do is shift those four bits into l or the low byte here so what we can do is we can do an arithmetic shift left on the a register which will shift all of this to the left and then this bit will fall out and go into the carry flag and then we could do a rotate left of L and rotate left is a little bit different than shift left because when we rotate left well when we shift left 0 would come into this empty bit over here on the right but when we rotate left whatever's in the carry flag gets rotated into the right here and then whatever came out the left this zero in this case goes into the carry flag so we shifted this left to get that one into the carry flag and then we rotated this left to get that one into the L or low byte variable then we could do the same thing we can rotate left h and that'll put this zero that came out of the left of the low byte into the right side of the high byte like that into that shift left rotate left has the effect of just moving all of this to the left by one bit we could just do that four times and then the result will be that after typing that b the 16-bit value represented by H and L is going to be equal to B then if we were to type a 3 for example we'd have you know three zero in the a register and we shift that in the B would move over and this 16-bit value would be zero B3 zero B3 if we then typed in e we would have zero B three e and so on so back to the code here's the arithmetic shift left for the a register then rotate left L rotate left H and all of this is in a loop where X is initialized to four and we decrement X each time and Branch back up to hex shift here so it goes through this Loop four times until X gets to zero and then it drops out and so once it shifts those four bits it increments y to move to the next key that was typed and Loops back up to process the next hex digit and you know something else of note here is that this Loop is using Branch not equal which will Branch up to next hex which is just up here that's it's the beginning of where we parse the next hex digit but Branch not equal we'll Branch as long as the result of this increment of Y is not zero but Y is never going to be zero here because we just incremented it so you know as the comment suggests over here this branch is always taken so why not just say JUMP next hex well it's another optimization so the jump instruction takes three bytes so it would be one byte for the jump opcode and then two bytes for the address that it's jumping to but a conditional Branch like this Branch not equal uses a relative address and so the assembler is going to actually replace this next hex not with the actual two byte address of this instruction of this load a instruction but it'll replace it with a an offset either a negative offset to go backwards or a positive offset to go forwards and it'll use just eight bits to set that offset so one limitation of conditional branches like this is that you can't jump more than 127 ish by it's in either direction but you know here it's not jumping very far and so Wozniak was able to save a byte although again you know at the uh you know creating a subtle unrelated dependency here on this increment instruction uh and the state of why but you know because this Branch will always be taken it'll keep parsing hex characters and shifting them into the H and L variables uh until it encounters a non-hex character of some sort and the result of that is that we can type you know one hex character just like one and hit enter and it interprets that as zero zero one because it just shifted that one in on the right side here if I type 1 2 well then it's interprets that as zero one two three it interprets as a obviously one two three four it'll interpret as you know four digits but if I do five six seven these first digits just get shifted out and the last I'm left with the last four is so it interprets one two three four five six seven as address so it's just going to parse hex digits until it runs into something that's not a hex digit like a character turn or something and it catches that here and continues on down here at not hex here the first thing it does is it

### Examine mode [21:29]

compares the Y register to the Y save variable so it's comparing the see if Y is the same as what it was before we started parsing any hex digits right because we stored Y into y save up here before we started parsing hex digits so if we come down here and it turns out that Y is still equal to that same value well that means we didn't actually read any hex digits at all and so that's not a valid entry and so what it does is it just jumps up to escape which just resets everything so that handles this case here where let's say we want to examine zero two zero through blah which is not a valid hex entry so what does it do with that not valid hex entry well as the zero two zero so it was able to print that much but then when it gets to this it's just like I don't know what to do with that so it just goes to escape it prints the backslash prompt and just resets everything so all of this functionality in just 248 bytes of code and it still does a pretty reasonable job of error checking but if we make it past that we must have gotten at least some valid hex characters so we have some sort of address that we're working with and here's where it needs to decide what to do based on the mode variable and the way it does that is pretty interesting it does this bit test on the mode variable and to understand the effect of that let's go back and look at the different values we had for mode if we go back up examine mode is zero store mode is 7B and block examine mode is AE and remember it was kind of weird that the mode value came from you know the value of dot or colon red from the keyboard but for store we did the shift left which gave us 7B and that seemed kind of strange but if we look at the binary representation of those three values they happen to have the top two bits set in a very particular way so this bit here bit six is a zero for examine and block examine and a one for store so that bit there you can think of as indicating whether we're examining or storing and then if we're examining this bit 7 is either 0 or 1 to indicate whether we're examining a block or just examining a single right and the significance of this is that one of the things that the bit instruction does is it sets the Overflow flag based on bit six and it sets the minus flag based on bit seven so just by doing bit mode these two bits get put into CPU flags that we could use for branching so we do bit mode to set the flags and then Branch if overflow is clear to not store because if the Overflow flag is clear or zero that means we're not storing if the Overflow flag is set or one then that does mean we're storing so I think this comment is actually wrong because if bit 6 is set then we're storing if it's clear if it's zero then we're examining or block examining right because it's saying if it's clear then we're not storing so I think this comment is actually wrong in fact even the printed Apple One manual says bit six equals zero for store but that's not true that six is going to be one for store mode and you know I kind of looked I was surprised I couldn't find anyone else that uh you know pointed out that this comment was wrong and you know surely I'm not the first person to notice this but anyhow if we're examining overflow will be clear and we'll Branch down here to not store and here the branch if minus will jump if we're doing a block exam and this comment is correct but just to examine a single byte it'll drop through to here so this block of code copies the hex address that was entered from the h l variables and it puts it into the store L and store H variables and the exam L and exam H variables and it does that with this sort of weird Loop thing which again is there to save a few bytes X starts as 2 and then it loads L minus 1 comma X so actually plus X so it's l minus 1 plus 2 if x is 2. so this is actually L plus 1. and if you look you know L was in address location 28 L plus 1 is 29 and so that's actually referring to H because of the way these are organized in memory so the first time through this Loop this is actually going to load H and then using the same logic it's going to store it in sth or store h and it's also going to store it in exam h then it decrements X and X is now going to be one so it's not zero so we jump back up here and now when we're loading L minus 1 plus x is now one so it's l minus 1 plus 1. so now we're loading l storing it in STL and exam L and then we hit this decrement x again which decrements X to Zero and then we fall through this branch and continue on so that is the effect of copying whatever is in hnl to sdh and STL as well as exam H and exam L I'll show you how those are used here in a minute but after we fall through this Branch not equal we're also going to and end up here where it's going to print out the address so we load a this is the character for a carriage return and we jump to echo which will just print that character term then we load the exam H so the high order byte we jump to a subroutine that'll print the byte we load the exam low order byte and we print that byte then we load a this is a colon and we print that out and we load and load a space just a blank print that out and then finally load the actual data using an indirect read and print that byte out so all of that's just doing this print that we see where it prints a carriage return and then the high byte the low byte a colon a space and then finally the value so that's pretty straightforward then the mode is reset to zero so the x is still Zero from this stuff up here so it stores X into mode so it resets the mode to zero and that's so that if we do something like this where we look at you know say zero two zero through zero two zero five it'll reset it to just regular exam mode so we can just do space zero three zero and it'll print that range zero two zero three zero two zero five and then it defaults back to just regular examine mode where it just prints a single value zero three zero so it resets mode to zero there and then let's go down here a little bit it Compares l and H to exam L and exam H and this might seem a little strange because we just set exam H to equal l and H so why would they be different but this is going to come into play for Block examine mode you know if we again

### Block examine mode [28:28]

if we type in something like zero two zero dot zero two seven f the way this is actually parsed is we start out in examine mode you know mode zero and it starts parsing hex digits so we parse zero two zero and then as soon as it encounters the first non-ex digit here which is this Dot we end up at not hex right where is not hex up here somewhere we end up at not hex right and that's where we're checking the mode and you know we're still just in examine mode so it drops down here and does everything that we just looked at and so when it gets down here and Compares exam L and exam H to l and H it equals that so it goes back up to the top and continues parsing well that's when it sees the dot and it switches modes so now it's switched to block examine mode and then it goes and it parses this hex address well when it's done parsing this hex address it sees the carriage return which I'll type right now so it parses this hex address and then it gets to the carriage return well the carriage return is not hex and we're back up here at not hex which is right here and so again we do that bit test on mode is not store so we end up down here at not store but this time mode is block exam so this Branch minus we're in Block exam it skips all this stuff here and just goes to exam next and so it doesn't copy l and H to exam L and exam H it just jumps down to exam next here and here's where it resets the mode to zero but now when we compare exam L and exam H to l and H exam L and exam H are zero two zero l and H now are zero two seven F because that's the last thing that we parsed so this so then this drops through and we increment exam L and then if exam L wraps around to zero we'll also increment exam h otherwise or either way we'll drop down here so this is just kind of a 16-bit increment then it's going to do this it's going to and exam L with 7 to check if it's a multiple of eight because you know every eight bytes that we print we want to print a carriage return and the current address again just so we get this nice format then it always goes up to next print and this Branch here is taken if the result of that and we just did says the address is not a multiple of eight so in that case it skips printing the address just prints a space and the next byte of data and this just keeps incrementing exam l right here until exam L gets to equal l and H and so that's how examine and block examine work so now let's take a look at

### Store mode [31:16]

storing a value to memory and how that works so if I type something like zero four zero zero colon b e you know I want to store the value b e into address zero four zero well we're going to start out in examine mode because we always start in examine mode and so the zero four zero is parsed as a hex value until it hits the first non-hex character which is the colon in this case at that point because we're in examine mode if I execute this it prints out the address and whatever happens to be in memory at that location which is a B I mean before we changed it then it continues parsing it sees the colon and that's going to cause it to switch modes to store mode and then it sees the blanket ignores the blank and then it starts parsing hex value again into H and L and then at the end of the hex parsing it encounters a carriage return which is not hex and so we're back up at not hex again so let's go up here to not hex but now our mode is going to be store mode and the hex value we just parsed is b e right that's the last hex value we entered so we got some hex digits so we're going to bypass this and now we're going to test the mode well now we're in store mode so we'll fall through this and start doing this stuff so L contains the low byte or in this case the only byte of the hex data that we typed in this case be so it loads L it loads the be into the a register and then it stores it at store low comma x is zero so this is really just storing it at the address pointed to by store L which in memory is followed by store h so sdl sth is the address that it's going to store to or points to the address and the value it's going to store is in the a register which is just loaded from L and this STL sth was the address that was saved back when we were in examine mode and processing this hex value so zero four zero that's what's in store L and store h so we're basically writing the be two zero four zero then it increments store low and if that wraps to zero it also increments store high and then it goes to the next item and is still in store mode so we can actually store multiple values in subsequent memory locations because it's incrementing the store address each time so if we do zero four zero colon zero one two three four five and so on the zero four zero is parsed in examine mode and so it just prints out what was there but then the colon switches it to store mode and then each time it encounters a new hex value followed by a not hex value in this case blank or at the end of carriage return it stores each of those into the store H and store L address which it's incrementing each time so this does kind of what you'd expect and so if we examine now zero four zero through zero four zero seven let's say you can see it's stored zero one two three four five in those locations and then this is just whatever happened to be there before and so that's actually pretty much all

### Print routines [34:28]

of the functionality of wasmon you know the only code we really haven't looked at is for printing so if we go all the way to the bottom of the code here's the sort of printing code that we haven't looked at yet there's a subroutine called echo which just prints whatever byte is in the a register so you can see here it uses a bit test to check bit seven um and then just branches back to Echo in a loop waiting for bit seven to be cleared which is I guess with the Apple One Hardware tells it that the display is ready for a character and when it's ready it just sends the a whatever's in the a register to the display so obviously we would need to change this code to adapt to the serial interface that I've got on my computer and then once it displays that character it returns from the subroutine then there's another subroutine for printing a hex character of whatever happens to be in the low four bits of the a register and it's pretty straightforward it zeros out the high four bits by ending it with zero f and then by oring it with b0 it Maps the value zero through nine to the digit zero through nine and then it Compares here if it's less than 10 basically then it jumps down to Echo and prints out the character Zero through nine whatever the character was if it's greater than 10 or greater than equal to 10 then it adds 6 to it and so that basically just adds an offset so that you know ba becomes the appropriate character for the letter a and once it does that it just falls through to the echo routine here which will print you know whatever letter A through F and then this return from subroutine will return from the print hex subroutine in that case and then finally there's a subroutine for printing a byte and what that does is it pushes the a register onto the stack then shifts it right four bits and then calls the subroutine to print a hex digit so by shifting it right four bits and printing the hex digit it prints the first character of the byte and in this subroutine uh you know is the one we just looked at it returns it comes back up here and we pull a off the stack and so we end up with a where it started and then this and here we fall you know we fall into the print hex it's not prints the second character of the byte by you know falling through here and falling into Echo and printing that character and now this return from subroutine actually returns from whatever called print byte so it's kind of clever how this works together and falls through so you have one return statement here for three different functions that all do sort of different things I think that's kind of clever but anyhow that's a complete walkthrough of how wasmon works I hope you found that interesting and you know as always thanks to my patrons for making this kind of video possible this is definitely not the sort of content that's going to win YouTube but I like that I can do these deep Dives and you know a few people are interested enough to support this sort of thing so thank you
