Advanced 6502 Assembly Programming for the Apple II

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

It's kind of a dry presentation, but I love old school low-level stuff like this. Thanks for posting.

๐Ÿ‘๏ธŽ︎ 6 ๐Ÿ‘ค๏ธŽ︎ u/fresh_account2222 ๐Ÿ“…๏ธŽ︎ Dec 10 2020 ๐Ÿ—ซ︎ replies

Neat. I've been playing around with emulating the Apple ][ under linapple on retropie. I initially got into retropie because of the consoles, but became fascinated with the emulators for old systems like the vectrix, amiga, apple ][, amstrad, sinclair, original mac, etc.

'retro computing' is interesting. It falls somewhere between 'retro gaming' and 'understanding things at the low level'

๐Ÿ‘๏ธŽ︎ 3 ๐Ÿ‘ค๏ธŽ︎ u/supercyberlurker ๐Ÿ“…๏ธŽ︎ Dec 10 2020 ๐Ÿ—ซ︎ replies
Captions
i'm stephen edwards and i'm going to talk about advanced 6502 assembly language programming for the apple 2 series of computers i've been coding in 6502 assembly language since about 1982 so about 80 of my life here i am in a magazine article from around then bragging about how i was going to be programming the ample tune assembly i clearly remember the day i figured it out we were cowering in our basement during yet another tornado warning and i was reading the apple ii reference manual steve wozniak's gift to hobbyists and cloners alike this book is a marvel and it actually came with a computer yes i'm old enough to remember when computers came with useful documentation but mind you this was the last millennium this book tells you absolutely everything about the guts of an apple ii including character set information lists of i o locations diagrams on perverse memory layout of the text and graphics displays in the apple ii schematics monitor rom listings and most relevant to my story and appendix on the 6502 instruction set about the driest introduction to 6502 assembly language you can imagine i remember when i cracked the code that night when i first understood that everything had to go through the accumulator on its way to and from memory but i'm getting ahead of myself it's good to understand the context of the processor if you're going to program it at the start of 1975 there were a handful of viable single chip 8-bit processors the intel 8008 which had been around since 1972 only cost 25 dollars but ran at 500 kilohertz only had a single external 8-bit bus demanding specialized or numerous support chips had a meager 3500 transistors and could only address 16k of memory the intel 8080 came along in 1974 and was a substantial improvement it could access 64k of memory with its separate 16-bit address bus consisted of 6000 transistors and ran at 2 megahertz but sold for a premium 150 at the end of 1975. nevertheless the 8080 ended up in the heart of the altar 8800 which launched the first personal computer revolution and its successors the 8086 and 8088 gave us the behemoth known as the ibm pc which we've been stuck with ever since motorola 6800 had also come out in 1974 and was comparable to the 8080 but simpler it had only 4 100 transistors ran at one megahertz instead of two and had a smaller register set motorola was selling it for 175 dollars a group of folks who worked on the 6800 including chuck petal and bill mensch left motorola in august of 1974 to build a simpler cheaper processor to compete with the 6800 thus was born the mos technologies 6502 it reached the market in late 1975 at a price of around 25 thanks in part to its low transistor count of only 3510 about that of the 8008 but it was far easier to use than that intel chip as you might imagine there was quite a lot of drama and litigation surrounding the genesis of the 6502 but that's a different story to understand the 6502 let's work from the outside in it's pin out is straightforward but worth understanding packaged as a 40 pin dip most of its pins are devoted to its 16-bit address bus and 8-bit data bus which allows it to access 64k the remaining pins include a single 1 megahertz clock a read write signal interrupt and reset inputs sync and ready pins that can be used to single step the processor in a single 5 volt power supply the programmer's model of the 6502 which is a list of registers and other programmable visible state is extremely simple even by the standards of 70s era single chip processors it is an accumulator-based architecture centered around a single 8-bit accumulator a on which virtually all operations are performed two 8-bit index registers are mostly intended to hold address offsets although they can be used for loop indices and other temporary storage rounding out the registers is the lone 16-bit register the program counter an 8-bit stack pointer that limits the stack to a minuscule of 256 bytes insufficient for high-level languages like c and an 8-bit status register with the usual zero carry and negative bits used to control conditional branches thanks in part to the amazing visual 6502 project which i strongly suggest you google the layout of the 6502 die is now well understood and can actually shed lighter than design of the instruction set when we look inside we see three regions the top region is a regular looking brom that decodes instructions and feeds signals to the control logic the second band in the chip which in turn sends control signals to the data path that covers a little more than the lower third of the chip the structure of the programmer's model is visible in the data path it's arranged as eight one bit rows the columns are from left to right the y x and stack registers the arithmetic logic unit or alu the accumulator and finally the program counter which is larger both because it is 16 bits and because it includes logic for incrementing this is a nifty visualization of all the 6502s opcodes which i adapted from gary little's inside the apple 2e at the center fittingly is the accumulator and virtually all the interesting arithmetic instructions including add compare exclusivore and others operate on the accumulator in memory the two index registers can be loaded stored incremented decremented and transferred to and from the accumulator a number of instructions modify the stack pointer including push pop and jump to and return from subroutine conditional branch and unconditional jump instructions modify the program counter finally an additional group of instructions transfer and modify the status register now let's dive into the details of the 6502 instruction set if we're going to program it we need to know what tools we have at our disposal instructions start with an 8-bit op code and may be followed by one or two bytes of literal data depending on the instruction's addressing mode the encoding of the 6502 instruction set perplexed me for years in part because of opcode matrix drawings like this one from a rockwell datasheet which didn't provide too much insight here's a better way to look at it the least two significant bits in each instruction divides the instructions into four groups the top three bits determine the operation such as add or subtract and the middle three bits determine the addressing mode mostly there are many exceptions group 1 instructions include the familiar add subtract compare and logical operations with a fairly orthogonal set of addressing modes group 2 instructions include shift and rotate as well as instructions that load and store the x register these provide fewer addressing modes than those in group one the opcodes ending in zero zero are more of a mess there are at least five subgroups including more index register instructions flag control instructions conditional branches and stack instructions finally the original 6502 didn't have any valid instructions that ended in 1-1 let's go through the group 1 instructions in some detail since they are nearly orthogonal and present us with mostly important addressing modes lda loads the accumulator with an 8-bit value this example uses immediate addressing denoted by the pound sign or the value to be loaded comes immediately after the opcode sta stores the accumulator in memory this example uses zero page addressing in which the address comes from the single byte following the op code implying that this addressing mode can only refer to the first 256 bytes of memory it took me years to realize it but the 6502's zero page is meant to be treated like a large register file accessing zero page memory is often 25 percent faster than accessing the rest of memory not because the physical memory is any faster but simply because the processor does not have to load a third instruction byte looking back i didn't realize this when i started programming because the apple monitor consumes about 25 percent of zero page locations dos 3.3 or protoss consumes some more and applesoft consumes all the rest well almost the result is that if you're interested in doing assembly from applesoft which i at a tender age was unfortunately attempting to do zero page locations are in very short supply adc adds a number taken from memory plus the carry flag to the accumulator including the carry flag enables multi-bite arithmetic but there's no add without carry on the 6502 you just clear the carry flag beforehand this is using zero page index addressing where the address of the byte to be added comes from adding the single byte after the instruction to the x register sbc is subtract with carry meaning the complement of the carry flag indicates a borrow again for multibyte arithmetic bite and memory is subtracted from the accumulator this is using absolute addressing where the address for the byte to be subtracted comes from the two bytes following the instruction in little endian order cmp is compare like spc it subtracts a byte in memory from the accumulator but it discards the result and only updates the flags in the status register typically for a conditional branch this is using absolute indexed by x addressing which takes the address from the two bytes following the instruction and adds the contents of the x index register to compute the address of the byte to subtract and is the bitwise logical operator it reads a byte from memory here using the absolute index by y addressing mode computes the bitwise and of it with the accumulator and stores the result in the accumulator ora is bitwise logical or which operates much like and this example is using the indirect indexed addressing mode which is the commonly used complex addressing mode the 6502 doesn't have a 16-bit index register none of the addressing modes i've shown so far can let you access an arbitrary address in memory indirect indexed addressing fixes the shortcoming by letting you specify a location zero page that is treated as a 16-bit address very much in keeping with the zero page as a register file view i mentioned earlier after loading the two bytes and zero page addressed by the byte following the instruction the 6502 adds the contents of the y register to compute the final address of the operand such as the byte being ored into the accumulator eor is exclusive or another bitwise logical operator like and and ora this example is using the uncommonly used indexed indirect addressing mode like indirect index the address of the operand is given by a pair of bytes in xero page but here the address of those bytes is the sum of the byte after the instruction plus the x register that is the x register is added to compute the zero page location holding the address that is before the 16 bit address is computed it's something like having the x register index an array of addresses held in xero page group 2 instructions don't support the indirect addressing modes but are otherwise very similar to group 1 instructions and are largely orthogonal ldx loads value into the x register such as a literal of the group 2 instructions ldx is the only one that can use a literal like this sdx stores the value in the x register into memory here at a zero page address inc is a read modify write instruction that adds one to the value of a byted memory here using zero page indexed addressing dec does the opposite of ink decreasing the value in memory by one asl is arithmetic shift left it shifts bits left by one shifting a zero into the least significant bit and shifting the msb into the carry flag this example is using the accumulator addressing mode where the source and destination is the accumulator by itself asl and other bit shifting instructions can also perform a read modify write operation on memory lsr is logical shift right it shifts the bits right by one the most significant bit becomes zero and the least significant bit goes into the carry flag this example illustrates a bit shift instruction used with a read modify write addressing mode rol is like asl but it takes the new lsb from the carry flag enabling multi-byte shifting ror is like lsr but it takes the new msb from the carry flag now we're into miscellaneous instructions that generally follow few patterns for example ldy sty cpy and cpx are analogous to their accumulator centric variants but can be used with only a few addressing modes jmp is an unconditional jump which comes in two flavors this is the more common version where the 16-bit target address is held in the two bytes following the instruction the other addressing mode of jump is unique again the two bytes after the instructions specify a 16-bit address but unlike before they are treated as the address of the target address to be read from memory that is this is a little like indirect indexed addressing where a 16-bit address is read from memory but rather than insisting the address reside in zero page the address can reside anywhere in memory this addressing mode is rarely used but finds use in the apple ii monitors csw field two bytes that contain the address of the routine currently responsible for printing a character typically to the screen but this can be changed to say send the output to a printer the bit instruction has my vote for strangest instruction in the 6502 it loads a byte from memory loads its two most significant bits into the negative and overflow flags then performs a logical and with the accumulator and sets the zero flag based on the outcome of the and without changing the accumulator it's probably most useful for checking the msb of an i o location like the keyboard strobe but the and with accumulator functionality can also be used to check if one or more other bits in the byte are all clear here's a collection of single byte instructions these increment and decrement the index registers which is useful when doing counted loops shuttle the contents of index registers to and from the accumulator and provide the rarely used ability to save and update the stack pointer here are more single byte instructions that can set and clear various status register flags the carry variants are used often in conjunction with adc and sbc instructions the 6502's decimal flag is quite unusual for a processor when set it makes the adc and sbc instructions calculate with binary coded decimal instead of binary this is one of the few aspects of the 6502 that was ever patented however i know of little use of this feature the 6502 variant used in the nintendo entertainment system went so far as to remove the decimal mode circuitry since it consumes a fair amount of area in the alu the 6502's conditional branch instructions are straightforward each is followed by a single byte containing a two's complement program counter relative offset limiting conditional branches to a range of roughly 127 bytes each branch tests one of four flags in the status register namely negative overflow carry or zero and each can be checked for being set or clear the 6502 stack related instructions round out our discussion the stack is used primarily for storing subroutine return addresses the jsr jump to subroutine instruction pushes the 16-bit program counter on the stack and sends control to the address and the two bytes following the instruction the rts returned from subroutine instruction undoes the effect of a jsr popping the return address from the stack the rarely used rti returned from interrupt instruction works like rts but also pops a saved status register value from the stack where the 6502's interrupt handling mechanism pushed it the processor status can also be saved and restored from the stack with the complementary php and plp instructions the pha and pla instructions push and pop the accumulator value on the stack these are commonly used for temporarily saving a value since you don't have to worry about managing the memory for the value brk is break which is a software interrupt that can be used for stopping programs when you are debugging them its instruction code is zero so sending control to uninitialized memory often leads to a break instruction being executed finally nop is no operation a surprisingly useful instruction that can be used to increase the delay of a timing loop or patch a buggy program without reassembling now let's talk about programming this beast to illustrate a number of coding techniques i wrote this little demo program which performs this eye-catching but physically inaccurate simulation of 30 bouncing balls i started with a vision of what i wanted this bouncing ball example to look like which i knew would consist of some initialization followed by the simulation of the physics of the balls here's the pseudocode my code begins by clearing the first high-res screen and then switching to it doing it in this order hides the surprisingly slow screen clearing process next i draw the frame two horizontal lines and two vertical lines this is fast enough so you don't see it next i set up the positions and velocities of all the balls and then draw the balls on the screen in their initial locations then i enter the main loop which loops over each ball i begin by erasing the ball since we're going to update its position then i update its horizontal position based on its velocity and check whether it needs to bounce off a wall i apply gravity which just increases the ball's vertical velocity and then update the vertical position which may involve bouncing off the bottom finally i redraw the ball in its new position once all the balls have been updated i check to see whether a key has been pressed if it hasn't i repeat the main loop finally if the user has pressed the r key i restart the program which i found useful for debugging i'm going to bring you through the code i wrote to perform these tasks but for to make any sense i need to teach you about graphics on the apple ii to understand graphics on the apple ii you need to understand its text mode and how woz implemented it the text mode on the apple ii series displays 24 lines of 40 characters each each character is represented with a single byte and displayed as a matrix of 7 by 8 pixels the first apple 2s could only display uppercase 2e and later models included lowercase my 11 year old daughter was taught to look for friendly numbers when doing arithmetic for normal humans things like 10 and 100 are considered friendly but computer people know better we love powers of two which is why we don't think 40 by 24 is very friendly at all i can only imagine how disagreeable was must have found these numbers because to get around them he came up with an ingenious solution that has cursed apple ii programmers ever since his reasoning must have gone like this 24 isn't a power of two but it's eight times three and i like eight and forty isn't a power of two but three times forty is a hundred and twenty which is almost 128 and eight times 128 is 1024 which is one k which i really like so woz split the screen into three bands of eight lines each and put the first line of each band into the first 128 bytes the second line into the second and so forth wasting only 64 bytes out of 1024 total now if you look at one of those inscrutable maps of addresses of the text screen it begins to make sense the lines on the top third of the screen start at 400 and then every 128 bytes after that then the lines in the second third start 40 bytes after each of the first batch of lines followed by the lines in the remaining third the apple ii's low resolution or low res mode treats each character as a pair of pixels each having one of 16 colors giving a 40 by 48 display or 40 by 40 with four lines of text at the bottom was actually worked on a version of breakout for atari so it's not surprising that a little brick out was supplied with early versions of the apple ii but i doubt the apple ii would have been quite as successful were it not for the high resolution or high res mode that was basically hacked into the apple ii hi-res mode is a 140 by 192 pixel mode that provides six colors green purple blue and orange in addition to black and white each high-res page the apple ii supports two consumes a whopping 8k of memory each which which is an exorbitant amount of memory for hobbyists in the late 1970s nevertheless most games use high-res mode and it's what i used for my bouncing ball demo although i only use black and white one of the challenges with high-res mode is its memory layout which is like eight text pages one after the other instead of representing a seven by eight pixel character each byte in hi-res represents three and a half colored pixels in a row and like in text in lores mode each row consists of 40 sequential bytes in memory but then it gets weird the top row starts at the beginning of high res memory and the next seven rows each start 10 24 bytes after the last the next eight rows start 128 bytes after the previous eight rows just like in the text mode display and the next eight start 128 bytes after those like text mode this goes on for the top third of the screen then woz uses the same trick he used for text starting at row 64 the addresses start again this time 40 bytes from the start of high raised memory this odd memory layout gives rise to the characteristic venetian blinds effect you see when a high-res image is loaded into memory sequentially such as from disk the addresses make a little more sense if you look at them in binary the lower five bits of the address indicate the column mostly the lower three bits of the row number appear in bits 10 through 12 and the next three appear earlier in bits 7 through 9 which gives the address for the first 64 rows as in text mode the next third of the screen or 64 rows are just 40 bytes beyond the first third and the remaining 64 rows are another 40 bytes beyond that the punch line is that woz was able to use a single 4-bit adder to compute these addresses which saved hardware but left programmers with a headache here's the code from the applisoft basic roms that compute the base address of a high-res pixel about the top two-thirds is responsible for the roll computation in part because the 6502 can only shift one bit at a time this code is long and slow which is exactly what we don't want in assembly the solution used by most high performance apple ii games was to throw lookup tables at the problem these are two 192 byte long lookup tables the first table contains the most significant bytes of the address of each row of the high-res screen the second table contains the least significant bytes the tables are about 300 bytes longer than the code but are tens of times faster this is the typical trade-off the fastest code invariably consumes more memory than the shortest code the best choice depends on the application you can find these sorts of tricks described in books like mark pelzarski's graphically speaking and jeffrey stanton's apple graphics and arcade game design the encoding of high-res color pixels is as idiosyncratic as their addresses and the story i'm going to tell is far simpler than what's really going on but it's enough for now every two bytes represents seven color pixels the least significant seven bits of each byte represent the pixels from left to right which is backwards from how we write numbers the most significant bit of each byte selects its palette choosing between green purple and blue orange black and white is easier to understand each zero is a black pixel and each one is a white in fact on a black and white monitor this horizontal high res resolution is doubled to 280 by 192. all zeros is black setting the two least significant bits makes the leftmost pixel appear white adding two more ones lights up the next pixel and adding three more ones and a one in the lsb of the second byte lights up the next two pixels bytes with seven ones produce all white pixels to get color we set every other bit for example setting the odd number pixels in the first byte and the even numbered ones except for the msb gives purple similarly setting the even numbered bits gives green two or more consecutive ones produce white pixels and you can mix purple and green nearby setting the msb switches to the blue orange palette here the odd numbered pixels gives blue even numbers gives orange consecutive ones give white and consecutive zeros give black now seven is another very unfriendly number indeed especially coupled with the 6502's limited ability to do bit shifting and so while it's possible to draw single pixels nearby to create a shape it's too slow for most games once more the usual suspects threw lookup tables at the problem the usual solution is so-called pre-shifted shapes in which seven versions of each sprite are precomputed and stored in memory ready to be quickly copied onto the screen here are the tables i used for the bouncing balls each ball is eight pixels high and eight pixels wide represented as two groups of eight bytes the first for the first byte of memory the second for the bite immediately after that every eight bytes in these tables represents a version of the ball shifted one black and white pixel to the right on the screen even though it looks like they're going the other way now i can explain to you my code for clearing and displaying the high-res screen it's straightforward yet representative of the sort of thinking you routinely do when coding in 6502 assembly first i set up the gbassal and gbassh bytes in xero page to 2000 the start of the first high-res page but even here i'm doing something subtle at the end of this code x has 20 and both a and y have zero this was for this three statement inner loop which writes the zero in the accumulator to 256 bytes in memory addressed by increasing y note that an offset of zero is written first so that the b and e exits the loop when it reaches zero again next i increase g bash to move to the next memory page and decrement x remember that x started holding 20 which is exactly the number of pages in the high-res screen since it's much easier to compare a register with zero rather than a constant my loops usually count down rather than up finally when both loops are done i use the bit instruction to touch the two soft switches these are memory mapped i o locations that switch graphics to high-res mode then switches on graphics i could have used something like lda or sta but i wanted to illustrate one use of the bit instruction reading a memory location without saving the result here's my horizontal line code which illustrates a typical kind of function linkage in 6502 namely using whatever registers happen to be convenient to pass arguments here i chose to use the accumulator to hold the byte to be written to the screen and why to hold the row number it's very helpful to also list the global variables your routine uses since the code that calls it might be relying on them not changing i begin by saving the color byte by pushing the accumulator on the stack since i need to use the accumulator for something else i read the address of the row from the lookup tables and store it in gbass l and gbassh then i load y with the number of bytes to write minus 1 so i can count backwards and restore the color byte in the accumulator by popping it off the stack the loop writes the color byte then goes to the previous byte here i want to stop after writing byte 0 so i use bpl to branch until y turns negative for the vertical line routine i save the color in a zero page location because i need to recall it quickly within the inner loop and i'm already using both index registers and the accumulator here since i want to draw up to row one but not row zero i use b and e to test the end condition which branches unless x is zero now let's talk about the code for drawing a ball on the screen first i decided to use an old graphics trick for placing sprites on the screen i exclusive or them onto the screen instead of simply copying them which lets you use the same fast code for both drawing and erasing sprites here's the logic for the exclusive r of two bits a and b if you start with a equal to zero the result is the value of b if you start with a equal to one the result is the opposite of the value of b here's a way to graphically show the same thing xoring with a black pixel gives the new pixel xoring with a white pixel flips the color of the new pixel the result is that if we start with a black screen an xor with a white ball we get a white ball if you xor the same white ball again it goes away now if we xor it a third time it reappears the exclusive ore technique doesn't distinguish erasing a sprite from drawing another nearby so when two sprites overlap their common white pixels cancel out and appear transparent a visual artifact fortunately because xor commutes you can redraw and erase the balls in any order while unfortunate my hope was that the balls would move fast enough for you not to notice this did it work i knew the speed of the ball drawing function would be critical so i wrote it starting from these inner few lines which load a byte from the screen exclusive ors it with a byte from the pre-shifted shape table stores that on the screen then does it again for the next byte this code assumes i've put the address of the beginning of the row into g basil and gbassh so the y index register needs to hold the bytes offset in the row that leaves the x register to hold the index into the shape tables i decided to try to preserve the x register value between iterations but needed the y register for looking up row addresses so i stored the current row number in the hgrx zero page address this code only displays two bytes in a single row to display a ball we need to execute eight times on different rows so i wrapped it in a loop that first reads the next row address from the address lookup tables using the row number in the y index register which i increment before storing back in its hdry zero page location after xoring the two bytes i increment x which holds the index into the shape tables to exit the loop i look at the lowest three bits of this index if they just became zero we just finished drawing the eighth row of some ball so we can return now let's talk about how i handle horizontal movement since there are seven black and white pixels per high-res byte smooth horizontal motion demands the byte number to update once every seven pixels while i could have stored the horizontal position as a number of pixels and divided it by seven to determine byte and shift numbers division is comparatively expensive on the 6502 and we aren't moving the balls around randomly so i wanted a different approach another issue was that i wanted the balls to move at fractional speeds horizontally and not just one or two pixels each time this meant that i needed some bits that would represent fractions of a pixel horizontally then i remembered since each ball is eight rows high and i am storing the bytes in order the second shifted ball is at offset eight the third is at offset 16 and so forth i decided to represent the horizontal position of each ball with two bytes in tables called ball xl and ball xh ball xh contains the byte offset of the ball which ranges between 0 and 39 ball xl contains the shift number of the ball times 8. storing it this way provides two advantages first the shift number is already multiplied by eight ready for indexing into the shape tables second the least significant three bits allow me to model moving as little as one eighth of a pixel at a time which makes the motion smoother here's the first half of the horizontal movement code which assumes the ball numbers in the x register first i add ball dx the horizontal velocity to ball xl now if the result was negative this means the ball moved to the previous column and we need to correct for this so we add 56 to correct for the underflow which we can do without clearing the carry since we know it was set and decrement the byte number if the byte number reached zero we know we hit the wall and branch to bounce x otherwise we're done when there wasn't any underflow we next checked for overflow we first save the updated ball xl value which may be wrong since we check for overflow by subtracting 7 times 8 or 56 and checking whether borrow occurred if the carry was clear there was a borrow meaning the shift number was in range the byte number does not need to be adjusted and we can branch to x done otherwise we store the now corrected shift number increment the column check to see whether we've hit the right wall and if so bounce by negating the horizontal velocity note that this all assumes the ball isn't moving too fast horizontally which i ensure when i generate the initial velocities i also use a pair of bytes to represent the vertical position but encode them more simply the high byte in ball dyh is the row number the low byte in ball dyl represents fractions of a pixel vertically the vertical code starts by applying gravity which increases the vertical velocity by one pixel per update and adds this to the current vertical position this sequence of instructions is standard for adding two 16-bit numbers finally i check to see if the vertical position has exceeded the bottom if it has i fall through to the bounce code since we may be moving quickly near the bottom of the screen the simple reverse velocity procedure we use for horizontal movement doesn't work here instead we reflect the vertical position around the bottom line by subtracting the y value from twice the value of bottom why twice if y is just a little more than the bottom position twice times bottom minus y is just a little bit less than the bottom position as desired finally we negate the vertical velocity by subtracting it from zero both these instruction sequences illustrate the standard way to subtract two 16-bit numbers this is hardly the final word on 6502 or apple ii assembly language programming my graphics code is still comparatively simple since it does not perform page flipping to avoid flicker and it's only black and white and there are many more tricks to 6502 assembly including many variants and using pre-computed tables self-modifying code and even dynamic code generation all of which have found use in various programs that push the 6502 far beyond what its designers intended regardless i hope this has given you some insight into the 6502 instruction set and how to use it to write interesting code for the apple ii series the source for my bouncing balls example can be found on my website which is an easy google away
Info
Channel: Stephen Edwards
Views: 12,516
Rating: undefined out of 5
Keywords: Assembly Language, 6502, Apple II
Id: WEliEAc3ZyA
Channel Id: undefined
Length: 33min 44sec (2024 seconds)
Published: Sun Jul 12 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.