by whobre on 2/6/25, 1:28 AM with 289 comments
by kazinator on 2/6/25, 4:00 AM
The 68000 has more registers and wider data types: but the registers are all uniformly the same. It's really just two registers A and D, copied a bunch of times in to D0 to D7, and A0 to A7. Whatever you can do with D0 can be done with D3 and so on. Some A's are dedicated, like for a stack pointer.
Simplicity of structure has to be balanced with simplicity of programming.
It's not that easy to program the 6502, because in moderately complex programs, you're constantly running into its limitations.
The best way to learn how to hack around the limitations of a tiny machine is to completely ignore them and become a seasoned software engineer. A seasoned engineer will read the instruction set manual in one setting, and other pertinent documents, and the clever hacks will start brewing in their head.
You don't have to start with tiny systems to get this skill. When you're new, you don't have the maturity for that; get something that's a bit easier to program with more addressing modes and easier handling of larger arrays, more registers, wider integers.
by crest on 2/6/25, 11:14 AM
If you want to learn a small, yet powerful instruction set with a few quirks go for ARM v6M. It‘s still in meaningful production (no the Monster 6502 doesn‘t count), has good platform support in the latest open source toolchains (debuggers, compilers, assemblers, linkers, etc.).
If you value openness of the architecture enough to deal with a less mature platform (as of early 2025) then pick a RISC-V MCU instead. If you can‘t decide pick a RP2350 :-).
The ARMv6M instruction set is small and no loading constants doesn‘t require long winded instruction sequences if you do it as documented (PC-relative load instead of shifting in immediate data). You don‘t have to deal with self modifying code and/or the zero page to index memory. Your registers are the same width as the address space. Yes it‘s 32 bits, but that makes it simpler to learn, use and teach than all 8/16 bit and most 16 bit instruction sets I’ve seen because you don‘t have to work around to narrow registers for common operations. To anyone who thinks this sounds boring: don‘t worry ARMv6 still has enough quirks you can use for code golfing.
by gustavopezzi on 2/6/25, 9:39 PM
I have taught 68K, MIPS, ARM, x86, etc., and the overall good student feedback I got by teaching 6502 is mostly because of the surrounding context that comes with the CPU. The reason 6502 clicked better than other modern alternatives (MIPS, ARM, x86, etc.) was because we use it to program a real machine that is simple to understand (i.e. Nintendo Entertainment System). Rudimentary memory mapped IO, no operating system, no pipelined instructions, no delay slots, no network, no extra noise, ...it's just a simple box with a a clock inside, a CPU, some memory addresses, some helper chips, IO mapped to memory addresses, and that's pretty much it!!! So, even though I agree that the 6502 is not the simplest instruction set out there, THIS simplicity of the system helped a lot.
And about the limitations of the 6502 CPU, these limitations were also important for students to understand that these instructions have a reason to be the way they are. CPUs were designed and wired given the constraints of that time, and that reflects on how we programmed for them.
So, even thought this was mostly empirical, I have to say picking 6502 and the NES to teach beginners was successful. Once again, not really because it was the 6502, but because the 6502 forced us to go simple in terms of the sytem we were moving bits left and right.
Once students played around with the 6502 and saw NES tiles moving on the screen, then it was super cool to evolve and show them how the 68000 did things differently, and then evolve more and show how MIPS came, show how pipelining works, how to take advantage of delay slots, and being able to compare the differences of RISC and CISC. It's super simple to evolve once the basics are there.
by julian55 on 2/6/25, 9:15 AM
by serviceberry on 2/6/25, 3:33 AM
It's very utilitarian and most commonly just used for debugging and reverse engineering. So why would you waste time on the assembly language of a long-obsolete platform?
Plus, the best way to learn assembly is to experiment. Write some code in your favorite language and look at the intermediate assembler output, or peek under the hood with objdump or gdb. Try to make changes and see what happens. Yes, you can do that with an emulator of a vintage computer, but it's going to be harder. You need to learn the architecture of that computer, including all the hardware and ROM facilities the assembly is interacting with to do something as simple as putting text on the screen... and none of this is going to be even remotely applicable to Linux (or Windows) on x86-64.
by lutusp on 2/6/25, 11:16 AM
It was for me. In 1977 I lived in a little cabin in Oregon. I bought an Apple II as a diversion. Within a year I was working on a program that later became "Apple Writer" (https://en.wikipedia.org/wiki/Apple_Writer), written entirely in assembly.
Some in this conversation identify 6502 assembly as rather clunky and difficult to use. In retrospect I have to agree, but in 1977 I didn't have a basis for comparison.
There were no fast, high-level languages available for the Apple II, so my little program became an Apple product, primarily from the lack of alternatives.
Consider this -- Apple Writer lived in 8 kilobytes of RAM, but actually did things. It even had a macro language people used to process address lists.
I just boosted my main system to 96 gigabytes of RAM to be able to more easily host DeepSeek locally (I have an RTX 4090). I just realized that's enough RAM to hold almost 12 million copies of Apple Writer.
This is all pretty surreal ... but I've had occasion to say that a number of times since 1977.
by hippospark on 2/6/25, 3:46 AM
by pizza234 on 2/6/25, 9:17 AM
Programming anything of moderate complexity on the 6502 is hard. 8 bits are way too restrictive (e.g. screen addressing on the Commodore 64). Multiplications/divisions need to be hand-rolled. And even 16 bit sums/subtractions are simple but still not trivial to perform efficiently.
The 8086+DOS platform is way easier to work on, in comparison (if one wants to learn basic assembly).
by nickyisonline on 2/6/25, 11:17 AM
by WalterBright on 2/6/25, 6:58 PM
One day, I asked my friend Shal Farley, what was a stack? He said "Imagine a stack of plates. You added a plate (pushed it on the stack), and took off a plate (popped it off the stack). Suddenly, Shal had turned the lights on! I instantly understood it.
Then, I began working with a 6800 microprocessor on a little board. It had something like 40 instructions, that all fit on a card. 40 instructions were simple to learn, and suddenly, I got it.
I want back to the -10 manual, and it all made sense.
by dhosek on 2/6/25, 3:22 AM
by toolslive on 2/6/25, 10:00 AM
I guess most people just give up once they see the ugliness of what they got from Intel.
by ergonaught on 2/6/25, 3:04 AM
Still do, really, though I’m decades beyond wanting to write anything in assembly now.
by KingOfCoders on 2/6/25, 4:50 AM
by kiwih on 2/6/25, 4:24 AM
It's taught to all computer science and software engineering students. Most students would take it in their first year, second semester.
We cover everything from the basics to hand-compiling code with functions, stacks, arrays, pointers etc.
We have our own emulator and even web platform for students to step forward (and backward!) their code: https://cgi.cse.unsw.edu.au/~cs1521/mipsy/
by progmetaldev on 2/6/25, 4:26 AM
I feel like learning modern assembly would be more useful, but maybe 6502 assembly is far easier to pick up? The first language I learned was Atari BASIC around 1991, and it was enough to get me to keep on moving to better languages and more powerful CPUs, but I wonder where I would have ended up if I learned assembly either before or after Atari BASIC. I try to keep up with technology, and have read quite a bit on different assembly dialects. I still haven't learned an assembly that I can program in, and I suppose it's because there are so many other high-level languages now and I feel like I need to keep up to what is used in "industry" rather than what is more obscure (but might help in debugging).
by ChrisMarshallNY on 2/6/25, 11:13 AM
Eventually, I ended up doing ASM with 68000 (Mac Plus), but by then, I was well on my way with higher-level languages.
Starting from Machine Language helped me a lot in understanding some of the more fundamental concepts of software. It was also an excellent troubleshooting teacher, which has probably been the most valuable software development skill I have.
These days, though, with the current complexity of CPUs, I don’t think it would be reasonable to start folks off with assembly/machine languages, anymore. I’m not sure that “retro” CPUs would really represent some of the difficulties experienced with highly parallel processors. I would worry that it might encourage an “idealized” view of the underlying architecture.
by analog31 on 2/6/25, 3:37 AM
For me, it was Z80, just because Radio Shack had a book on it. I never actually built or programmed a Z80 system, but I still fall back on that knowledge when working with microcontrollers.
by Dwedit on 2/6/25, 6:55 AM
SBC is implemented by adding the ones-complement (XOR FF) of the number or register. And the carry flag is backwards compared to other architectures, such as the Z80. On input, Carry Set means that you don't want an additional one subtracted, and Carry Clear means you do want an additional one subtracted. Then on output, Carry Set means that no borrow took place, and Carry Clear means that borrow took place. When borrow takes place, you get an additional one subtracted, and that lets you chain the low bytes up to the high bytes and subtract bigger numbers.
CMP is like SBC, except it always adds the extra one whether your input carry is set or not, making it act like you'd expect comparison to act.
by WillAdams on 2/6/25, 2:53 PM
https://en.wikipedia.org/wiki/MMIX
has a quite deep corpus and what looks to be a good introduction:
https://www.mmix.cs.hm.edu/getstarted.html
(and I say that as a person who owns a much battered copy of Inman & Inman's _Apple Machine Language_)
by nyrikki on 2/6/25, 6:57 PM
It is Purpose built, load-store etc...
You can use the simplified MMIX-SIM
Then you can move to typical RISC features like full pipeline, cache, etc...
Then you can move to actual hardware etc..
But I am probably bitter, I learned on a Heathkit ET 3400, and I find that a lot of the quirks of the 6800 are something I had to get around to understand modern processors.
MMIX may not be 'useful' for real applications, but being intentionally free of those quirks is very useful for understanding the core concepts, at least for the few people I have had try it.
by smitelli on 2/6/25, 7:07 PM
by dwheeler on 2/7/25, 12:35 AM
The 6502 was designed to be easily implemented with relatively few transistors. For that it was amazing. There is a reason it was popular! But its CPU registers are only 8-bit, its call stack is 256 bytes, and for real work you need to use the zero page (zpage) well. None of these are likely to relevant to a modern software developer using assembly. Its design encourages the use of global locations, again, an approach that don't make sense on modern systems.
I say this as someone who admires what the 6502 was able to achieve in its time, and I even have a long-running page dedicated to the 6502: https://dwheeler.com/6502/
If you want retro and easy, the 68000 has it beat in terms of simplicity of development. The 68K is quite regular & a little more like modern systems (sort of).
However, I think starting retro is often a disservice. Most the time the reason to use assembly is performance. If you're running code on chips more than a dollar or so, getting performance out of modern architectures is MUCH different than retro computers. For example, today a lot depends on memory cache latency, yet is typically not a serious concern on most retro computers. So learners will learn to focus on the wrong problems.
If you want a modern simple architecture, may I suggest RISC V? That's under a royalty-free open source license, and real computers use it today. It's pretty simple (your basic load-store architecture) and you can pick only the modules you care about. Full disclosure: I work for the Linux Foundation, but I'd say that anyway.
Plausible alternatives are ARM and x86. If you subset them, they're okay.
The reality is that assembly languages reflect the underlying system, and that will change over time.
by daitangio on 2/6/25, 1:09 PM
Zero page is like a having 256 generic RISC registers (a bit faster than accessing to other memory areas).
Very easy to understand how the assembly is micro-coded
Cons:
It is impossible to create a "generic" memory pointer with an index >255 without auto-modifying code.
It is a true 8bit only system and cannot manipulate 16bit word easily Steve Wozniac created a small VM just to manage 16 bit Integers (see the his Byte magazine articles).
Too much addressing mode.
So I like 6502, but I disagree a bit.
by Sardtok on 2/6/25, 2:01 PM
I'm not saying 6502 assembly can't be an interesting endeavor, but it's a bit restrictive for a first language. Maybe if you already know some low-level programming like C. But it's still easier to do things with a few more registers. And it's not like you have to use every register and instruction available on the CPU to write some assembly.
by blkhp19 on 2/6/25, 3:47 AM
I wrote one in Swift a few years back, and then ended up developing it further into an NES emulator capable of playing Donkey Kong. It was a great learning experience.
by acc_297 on 2/6/25, 2:11 PM
That was pretty great for learning assembly, I can't comment on any other approach - no doubt there are other good options.
by dekhn on 2/6/25, 5:44 PM
by MarkusWandel on 2/6/25, 5:37 PM
The 6502 wasn't. Everything about the 6502 was "do more with less" and you had to be really clever to eke out performance on it. But that's a good thing! A clean, big CISC architecture like the former ones is also a good compiler target. The 6502 was deeply weird, but programming it in assembly was necessary to get it to fly. That's an era. If you want to relive that era, then go for it. It's much more quirkily fun that, say, the 8080 (the Z80 is another beast, though backwards compatible) and much more mainstream than the otherwise better 6809, all of which are also from the "assembly language required for performance" era.
by zeta0134 on 2/6/25, 4:08 PM
Problems with the ISA become obvious the moment you want to scale your program beyond toy complexity. The stack is absurdly tiny, and trying to use it as a calling convention quickly becomes both a performance and a nesting depth bottleneck. I work around this for my larger projects by using zeropage scratch as a sortof manually-managed local scope for routines, but it requires carefully tracking which otherwise global bytes my programs are using at various nesting levels. Recursion is off the table both with this technique (difficult to manage) and with the stack (256 bytes will be exhausted very quickly). The C compilers I'm aware of work around this (slowly!) by using a separate software stack for arguments to functions.
It's pretty fun though! I'm working on a full modern indie game for the NES, which is 100% programmed in 6502 assembly for performance reasons. The existing C toolchains for the NES are either very slow (cc65) or not yet mature (llvm-mos). Most of the true complexity in the project is algorithmic stuff, like resource allocation and deciding how much work to do on a given frame. The 6502 ISA is a bit slower to write than higher level code, but it's not really a major limiter now that I've got my process down.
Here's that game if you're interested: https://zeta0134.itch.io/tactus
by bb88 on 2/6/25, 3:07 AM
The problem was that Applesoft basic set the high bit on data going out a serial or parallel port which was a problem for printing and sending data out through a modem. So if you wanted to keep the high bit one had to use 6502 assembly.
by JKCalhoun on 2/6/25, 3:54 AM
In any event, try out the KIM-1 simulator if you want to use your 6502 coding skills: https://maksimkorzh.github.io/KIM-1/
by monocasa on 2/6/25, 4:20 AM
Biggest issue is that register width is half of pointer width, so for arbitrary pointers you at least need to make a trip through the zero page.
That fact alone really obfuscates a lot of what you're trying to teach as a first stab in assembly.
I say this as someone who has a whole lesson plan in 6502 asm.
by dtaht on 2/6/25, 4:26 AM
That said, I loved the zero page on the 6502...
by larusso on 2/6/25, 6:05 AM
by donatj on 2/6/25, 1:39 PM
I end up having to talk myself down like "no, we're here to learn, not to create another language"
by WhyOhWhyQ on 2/6/25, 5:39 PM
You can go through that in one pleasant sitting.
by efitz on 2/6/25, 6:54 PM
If you want to learn to write programs in assembly language or to debug disassembly of programs written in higher languages, then learn the language for the platform that you want to target. This also covers the "I want to write/understand retro stuff" case.
If you want to understand how high-level programs are compiled into assembly language, then read Aho[1].
If you want to understand how algorithms are implemented in assembly, read Knuth[2]. Knuth invented a hypothetical computer "MIX" with its own assembly level instruction set and I believe that MIX has actually been implemented in software several times.
If you just want to play a little bit with assembly, "dipping your toes in the water", then I agree with the OP that 6502 is simple and easy to learn, but it is not practical for many modern use cases and has sharp edges.
[1] "Compilers - Principles, Techniques and Tools", by Alfred V. Aho et al. https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniq...
[2] "The Art of Computer Programming", Volume 1, by Donald Knuth, Section 1.3 "MIX" (p. 124 in the 3rd edition) https://en.wikipedia.org/wiki/The_Art_of_Computer_Programmin...
by aappleby on 2/6/25, 4:33 AM
by louthy on 2/6/25, 2:07 PM
If I was to think of the most approachable assembler it would be the ARM assembler for the original ARM2. A real thing of beauty. Which is not what anyone would normally say about any assembly language! I remember going from ARM to MIPS and being utterly horrified by its ugliness compared to ARM!
by quantified on 2/6/25, 2:53 AM
Having worked with the 6809 series as well, it wouldn't be a bad choice either. The Freescale 68HC12 is still in production. Little systems with limited-yet-real I/O give the programmer very useful feedback.
by sircastor on 2/6/25, 4:40 PM
by samspot on 2/6/25, 7:13 PM
by gxd on 2/6/25, 1:49 PM
by js8 on 2/6/25, 6:25 AM
by Findecanor on 2/6/25, 5:03 AM
For teaching, I would instead go with RISC-V. In particular RISC-V with the bitmanip extensions, which make some things much easier and gives it feature-parity with the base set on x86 and ARM. The Raspberry Pico 2 has two RISC-V CPUs with those. The board is easy to use, widely available and has a lot of support. There are also alternative boards with the same MCU but other form factors and features.
by herczegzsolt on 2/6/25, 6:32 AM
Around the same timey I had to learn AVR8 family assembly (for ATMega328P) which was a joy in comparison.
I don't think AVR assembly is any better or easier then 16bit Intel, but just the fact that it's a usable and actually triable thing makes a world of difference.
I guess what i'm trying to say is that you shouldn't underestimate the importance of learning something useful instead of something antiquated, even when it is not the simplest thing to do.
by PeterStuer on 2/6/25, 7:48 AM
Also, for me the excellent 68000 instruction set was design wise far more a continuation of the clean Z80 style than the messy 6502.
by relistan on 2/6/25, 8:21 AM
by ein0p on 2/6/25, 9:50 AM
by lizknope on 2/6/25, 4:17 PM
I learned M68K in a college class in 1995. When I saw x86 asm 2 years later it looked like a mess. But I've never needed to write asm for a job.
I'm thinking about learning 6502 because my first computer (Atari 800) and first dedicated game console (original Nintendo NES) both used the 6502 and it would be fun to write games for them when I retire.
by MarkusWandel on 2/6/25, 5:22 PM
On the other hand, the cleaner, more modern architectures are easily targeted by compilers. If you really want to live the "assembly language required for performance" era, the 6502 is fine. Equally quirky is MCS-51. I've written nontrivial assembly language projects for both "back in the day".
by rayholt on 2/6/25, 5:20 PM
by vertnerd on 2/6/25, 12:26 PM
Nevertheless, when I went to teach a short intro to CPU class to high school students recently, I chose the venerable 6502 for programming. Why? Because performing the 8-bit arithmetic and performing hand assembly are all very manageable on the 6502. Any 8-bit CPU would do, frankly, but the connection between 6502 and early microcomputer history is intriguing (and I was familiar with it).
Everyone here is talking about how there are better assembly languages to learn first, but I wonder how many of them are practical for hand assembly. I still maintain that learning (and debugging software for) any CPU architecture beyond the 6502 was easy because of the skills I learned as a teenager, hand assembling 6502 code. That experience put me miles ahead of my colleagues who didn't have that experience when it came to working with low-level coding in the decades to follow.
by acjohnson55 on 2/6/25, 6:10 AM
by mr_coleman on 2/6/25, 8:24 PM
by thoughboxy on 2/6/25, 12:04 PM
by classichasclass on 2/6/25, 4:02 AM
a9 01 8d 20 d0 a9 93 20 d2 ff ...
When we got a KIM-1, we were able to write meaningful programs on it in a weekend, since we already had memorized all the hex.
by fjfaase on 2/6/25, 6:58 AM
by fargle on 2/6/25, 5:05 PM
VAX or 68K would be cleaner CISC ISA to learn first.
8086 (16 bit) x86 has the advantage of being ubiquitous and you can run on "hardware" everywhere. but the disadvantage of being a little weird wrt. segment registers. x86 32-bit is complicated, but at least flat memory space and you can mostly ignore the segments.
MIPS or one of the RISC-V variants is a second one to learn to contrast RISC load/store with CSIC.
by pcthrowaway on 2/6/25, 2:51 PM
Is this author arguing the 6502 is preferable because it's simpler? Or because there are more/better resources for learning?
by hcfman on 2/6/25, 9:30 AM
by DonHopkins on 2/6/25, 9:44 AM
by bArray on 2/6/25, 10:34 AM
by pcvarmint on 2/7/25, 9:32 AM
by yoyohello13 on 2/6/25, 2:56 PM
by Angostura on 2/6/25, 10:01 PM
by germandiago on 2/6/25, 6:42 AM
by firesteelrain on 2/6/25, 5:26 PM
What is the best platform to learn assembly on and where do I start? Books, videos, building my own computer, etc?
by eleitl on 2/6/25, 8:07 AM
by glouwbug on 2/6/25, 8:53 PM
by mud_dauber on 2/6/25, 8:10 PM
by pjmlp on 2/6/25, 6:21 AM
by amelius on 2/6/25, 10:05 AM
by a1o on 2/6/25, 12:49 PM
by brucehoult on 2/6/25, 4:49 AM
Yes.
> However, they are not ideal to start with: the “S” in RISC stands for “simple”, but the simplicity is more about internal implementation of the chips than the instruction set.
That is in fact a much better description of the 6502, which is not even a RISC but rather something almost prehistoric, where you figure out how much circuitry you could fit on a chip (or board) and then figured out what instruction set you could fit to that hardware.
Note that 6502 was the first machine code I learned as a 17 year old in 1980, after I got bored with BASIC after two days. I learned z80 on a ZX81 the year after and PDP-11 the same year. VAX in 1982, 6809 in 1983, and 68000 in 1984.
> Modern microprocessors are almost exclusively programmed with high-level languages and the direct usage of assembly instruction is not high on the list of priorities for CPU designers nowadays.
That's just absolutely not true.
They might be in some way "harder" than a CISC instruction set such as VAX but any of the above are far simpler to program than 6502, especially the base RISC-V RV32I instruction set.
> To illustrate this point, loading a 64-bit constant to a register on ARM64 can take 4 instructions with bit shifting.
Whereas you can't do it at all on a 6502! Loading a 64 bit constant into 8 zero page locations takes 16 instructions and 32 bytes of code on a 6502.
Let's not even talk about adding or comparing or multiplying two such values.
The GNU assembler for ARM64 doesn't help you out, but on RISC-V you can just type ...
li x10,0xfedcba9876543210
... and the assembler will generate the multiple instructions for you.by PaulHoule on 2/6/25, 1:18 PM
https://store.arduino.cc/products/arduino-uno-rev3
are affordable and have good tooling. Memory capacity is tiny but it is fast, andthere is a lot of I/O, you can even write console programs that use the serial ports or better, programs that do physical things and also communicate over the serial ports -- in some ways AVR-8 boards are more capable than conventional computers, phones, etc. So far as I can tell, AVR-8 was the last 8-bit architecture, if it has a real weakness it is that, compared to other microcontrollers, it's a dead end because you're going to upgrade to ESP-32 or ARM if you need more.
The 6052 has more registers than the PDP-8 but just barely. Writing compilers for the 6052 is difficult because there just aren't enough registers not to mind a limited set of addressing modes. If you want to do anything interesting with the 6502 you are likely to use virtual machine [1] techniques such as Wozniak's SWEET16 or the atrocious UCSD p-System [3] or Infocom's Z Machine [4]. That kind of stuff is really fun, but so is writing straightforward AVR-8 code.
I have fond memories of the 6809 which supported really advanced software engineering techniques at the time [5] but if I had to pick a classic 8-bit architecture that is easy to find hardware for today it would have to be the Z-80, or the successor eZ80, which I think the only 24 bit micro that didn't suck (had real 24 bit index registers!) Boards are available [6]
[1] as in 'Java Virtual Machine', not 'VM/CMS'
[2] https://en.wikipedia.org/wiki/SWEET16
[3] http://pascal.hansotten.com/ucsd-p-system/
[4] https://en.wikipedia.org/wiki/Z-machine
[5] https://en.wikipedia.org/wiki/OS-9
[6] https://www.olimex.com/Products/Retro-Computers/AgonLight2/o...
by pwdisswordfishz on 2/6/25, 6:31 AM
TIL
by dboreham on 2/6/25, 4:27 AM
by andyjohnson0 on 2/6/25, 9:06 AM
Its been a while now, but I remember feeling that the 68k was clearly powerful and elegant and a proper cpu, but also that I had little hope of understanding all the details. The 6502 was my first, and with hindsight was far less elegant with plenty of warts, but I felt at the time that I understood it pretty well. The 6802 was somewhere inbetween, I guess, and a very nice cpu to work with
I've never thought about it before, but I suppose I benefited from that progression 6502->6809->68k. Whether or not it makes sense now, I couldn't say.
(Never got on with the Z80. That brash upstart /s)