MCUs with toolchains that support assembly language programming - Page 1
Forum section: electronics / general

author: slugrustle
author_rank: Frequent Contributor
timestamp: August 10, 2025, 11:11:27 pm
content: I'm fond of programming microcontrollers in assembly and have mostly stuck with 8-bit PICs. I've done an ATtiny AVR once and a Holtek HT48R003 (very PIC-like, excellent IDE). I'm curious which microcontrollers currently in mass production have toolchains and documentation conducive to assembly language programming. Does anyone here have favorites?Microchip switching from MPASM to PIC-AS was annoying, but I was able to figure it out.

author: John Coloccia
author_rank: Super Contributor
timestamp: August 10, 2025, 11:21:28 pm
content: Pretty much everyone.What's your poison? The arm mcus have a dirt simple assembly. Hard to imagine why this is fun, but if you're looking for simple...

author: brucehoult
author_rank: Super Contributor
timestamp: August 10, 2025, 11:50:07 pm
content: Quote from: slugrustle on August 10, 2025, 11:11:27 pmAll of them, obviously.Older ones such as older PIC, 6502, z80needto be programmed in assembly language unless you're willing to throw away large amounts of ROM space or execution speed or both..QuoteThe WCH family of 32 bit RISC-V microcontrollers, but especially the cute little $0.10 CH32V003 with 2k RAM and 16k flash and 48Mhz.But anything RISC-V or Arm is equally suitable for both asm and C programming. AVR and MSP430 too.The files attached to the following message contain complete asm source for blinky on CH32V003.https://www.eevblog.com/forum/microcontrollers/ch32v003-blinky-in-riscv-assembly/msg4976077/#msg4976077

author: shabaz
author_rank: Frequent Contributor
timestamp: August 10, 2025, 11:52:02 pm
content: There's a similar recent thread here, where the OP wished to program in assembler:https://www.eevblog.com/forum/microcontrollers/suggestions-for-a-microcontroller-(general-purpose)/

author: slugrustle
author_rank: Frequent Contributor
timestamp: August 11, 2025, 12:41:18 am
content: Quote from: brucehoult on August 10, 2025, 11:50:07 pmWell, if they don't have good documentation of the register set, memory map, or instructions, that would be a hindrance. If there's no ready made assembler conducive to use by a human, that would also be annoying. PIC-AS is more like that than MPASM was, for example (but still workable). The toolchain can sometimes be difficult or annoying to set up for an assembly language project.I have to say that Holtek's IDE and assembler were just 100% fantastic for this on their 8-bit MCUs.Thanks for highlighting ARM, RISC-V, AVR, and MSP430. Those make sense as opposed to something like RL78.

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 01:49:03 am
content: Quote from: slugrustle on August 11, 2025, 12:41:18 amOh gawd.I don't know any reason you'd choose that unless you have NEC 78K assembly language code from the 80s you want to port to something newer with as little effort as possible. Or maybe you need some specific interface or certification that you need -- in which case you'll already know you need it.But even if you're in that kind of field, and love Renesas, they do have lines with modern Arm and RISC-V cores too.

author: John Coloccia
author_rank: Super Contributor
timestamp: August 11, 2025, 01:54:02 am
content: Quote from: brucehoult on August 11, 2025, 01:49:03 amI had to work with on one of the NEC 4-bit micros, which for some reason I associate with the rl78.FWIW, I have no particular love for Renesas. RIP NEC, Hitatchi, Mitsubushi....did I leave anyone out? LOL

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 02:14:42 am
content: Quote from: slugrustle on August 11, 2025, 12:41:18 amIf there are C headers then you can read them and convert the definitions you need to asm.QuoteAll the ISAs I mentioned are supported by both GCC and LLVM . That means uniform support for all modern standard C/C++ features, consistent machine-independent optimisation, and consistent support for most aspects of assembly language, and easy ability to mix C and asm in a project. In fact it's easiest to build even pure asm projects by giving the source files to thegccorclangdriver program and let it call the assembler and linker with the right options for you.With the GCC toolchain you can just install thebinutilsassembler / linker / disassembler / library tools if you really want, but it's very convenient to have the C compiler too.With the LLVM toolchain there is no stand-alone native assembler, assembly to a native.ois done by theclangC compiler, and then linked bylld. though LLVM might still be experimental for AVR and MSP430, I'm not too sure. Back-porting to older and <32 bit ISAs such as these (and 6502!) is a relatively recent thing for LLVM

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 04:10:06 am
content: Quote from: Peabody on August 11, 2025, 03:13:38 amThey're PDP-11s with twice as many registers (14 ) compensated by a few missing addressing modes  to keep the instructions at 2-bytes :-) R2 and R3 don't really exist as GPRs, but are instead used to read/write the status register (R2) or generate common constants -1, 0, +1, +2, +4, +8. 4 for src operands ... Rn, @Rn, @Rn+, 0xNNNN(Rn) ... and 2 for dst ... Rn and 0xNNNN(Rn) ... plus the same PDP-11 special-casing of the PC to get immediate (@PC+) and relative (0xNNNN(PC)).

author: nctnico
author_rank: Super Contributor
timestamp: August 11, 2025, 07:44:34 am
content: Quote from: brucehoult on August 10, 2025, 11:50:07 pmSorry but this is plain wrong. What is needed are A) a good C compiler optimised for 8 bit platforms and B) a different coding style (like not using pointers so much). A good 8 bit oriented C compiler will produce better code compared to a skilled assembly programmer. And a whole lot quicker too. Microhip's PIC compiler and Keil's 8051 compiler are good examples of such compilers.

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 08:57:54 am
content: Quote from: nctnico on August 11, 2025, 07:44:34 amUsing pointers, recursive functions, etc is an integral part of C programming. If you have to avoid those in order to get efficient code then your compiler is not producing efficient code from C.I have extensive experience with 6502 and Z80 and know that what I say is true for them.I have not written much PIC code, but a little, and I've read through the instruction sets for them, and the earlier ones are extremely hostile to high level languages, even to the point of anything before PIC18 (2000) not being able to call functions to an arbitrary depth with inaccessible on-chip return address stacks with 2-8 entries.I note that PIC16 is still produced and has a maximum of 1K RAM and 28k instructions of flash and run at 32 MHz, which is considerably bigger than the very popular ATTiny85 which is 512 bytes of RAM, 8K bytes of flash (4k instructions), and 20 MHz clock and is a very capable target for arbitrary C code. In fact it's the same RAM as an ATmega168, but more than 3x the amount of program code space. It's more code (but less RAM) than the very popular ATMega328 found in e.g. Arduino Uno.You simply can not make a conforming C compiler for PIC16 without resorting to interpreting some more sensible instruction set.Fortunately the interpreter for a simple bytecode stack machine can be pretty small, and you've got a lot of flash anyway, and with 32 MHz you can possibly still end up faster than a 1 MHz 6502.And don't tell me that no one uses PIC16 now. It's probably still 2/3 of 8 bit PIC unit sales. And unlike the low end AVRs you can't program it in proper C.

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 09:06:28 am
content: This looks interesting as a base for writing more arbitrary programs on pre-PIC18.---PICoForth is the compiler for PIC12 and PIC16 families of famous Microchip's microcontrollersCALLING STYLESthere are 3 styles of calling words:inline - the word is compiled inline. usesful for simple words like dup, drop etc and for words that are called few times. :pic-inline .... ;simple call - uses call and return instructions to call the word there is hardware limit to 8 levels. Many of library words consumes 1 level of stack. The interrupt consumes 1 level of stack too :pic ..... ;return stack call there is no limit to 8 levels of stack, the return address is stored in return stack. This method is slower than simple call and consumes 2 bytes of ram (in return stack) :pic-rcall .... ;

author: nctnico
author_rank: Super Contributor
timestamp: August 11, 2025, 09:35:55 am
content: Quote from: brucehoult on August 11, 2025, 08:57:54 amBut still, using C is way more efficient compared to using assembly. And that is the whole point. For example, Keil has an extensive document about the best coding strategies for using C in combination with the 8051. If you just dismiss C because you can't use all of it on a platform, then you are throwing out the baby with the bathwater.

author: peter-h
author_rank: Super Contributor
timestamp: August 11, 2025, 09:41:17 am
content: QuoteI did a lot of this in the 1980s, asm and IAR C.Asm wasmuchfaster but now I know a bit more about C I can see a lot of the difference was due to the integer promotion in C.asm:add a, cC:ld l, ald h, 0ld b, 0add hl, bcld a, lQuoteThat is true for sureFor many years I sold a C programmable Z180 based RS232/4xx comms box and we sold the Hitech C compiler with it, the compiler going for a cool £450We bought a load of licenses just as Hitech sold out to Microchip. That compiler was better than the IAR one but only a bit. Its printf library wasfarbetter because it used fast non-IEEE floats, whereas IAR's runtimes were pig slow, and lazily written. I wrote a lot of custom comms-related runtimes for the Hitech compiler.And I think a big part of the reason people say asm is much faster than C is crap runtime libs, often written in C and poorly. IEEE floats, pointless in most embedded work, are up to 10x slower than "hacked" ones. Integer promotion is another part of it which prevents efficient 8 bit algorithm implementation (but you may never be doing that).ARM32 asm is also pretty horrible.And finally modern chips are so fast that performance is rarely an issue. But for the low end ones you still need to do asm because of limited flash alone.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 11, 2025, 09:46:31 am
content: Quote from: peter-h on August 11, 2025, 09:41:17 amYeah. C was clearly designed for 16-bit machines. Using it on 8-bit machines requires a bit care; lazy programmers (me included) use a lot ofint, and integer promotion rules also promote to int or unsigned int, which are by definition at least 16 bits. Which is inefficient on 8-bit machines.Some tackle this by compiler options like -mint8 (AVR-GCC) (which makes the compiler non-standard-compliant and modifies int to be 8 bits wide) but to me that seems like horrible idea. Just remember the target you are writing to when performance matters. And on very small MCUs it often does.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 11, 2025, 09:50:05 am
content: Quote from: peter-h on August 11, 2025, 09:41:17 amWhy so? I find it pretty nice and simple. Basically the only complaint I have would be inherent lack of loading arbitrary immediate values and instead having to do PC-relative load and put constant pools close-by, but we do have the handy @ syntax to automate that, not too bad?

author: brucehoult
author_rank: Super Contributor
timestamp: August 11, 2025, 10:14:09 am
content: Quote from: nctnico on August 11, 2025, 09:35:55 amYou can't be a little bit pregnant. It's either C -- ALL of it -- or it's just something like Rust or Java or zig that borrow a smaller or larger amount of C syntax.Yes of course using a compiler will let you churn out code faster than writing in asm. But if you're not using real C then you're in an isolated backwater that can't share code with the rest of the world.The 8051 is a VERY different animal to PIC16 and lower. You can't compare them. In many way it's not all that different in capability to 8080, just a different twist.In particular 8051 has a proper SP with stack in RAM, used by call / return / push / pop. You can also transfer SP to a register e.g. R0/R1 and use that to access stack memory (maybe after a few inc/dec), or transfer to A and do arbitrary arithmetic before transferring t R0/R1 for memory access. Arbitrary stack access is not that different to 8080/Z80 where you do "ld hl,offset; add hl,sp; ld r,(hl)" .. 5 bytes of code which is not that horrid. And 2 more instructions/bytes to get an adjacent byte. On 8051 it'll be like "mov a,sp; subb a,#nn; mov r0,a; mov a, @r0" -- again 5 bytes of code. With adjacent bytes again then just "dec r0;mov a,@r0". The only difference is 8051 can only load to A so needs to them mov to another register before loading the next byte. And the offset is 8 bits, not 16 like on 8080 (which is fine .. I wish 8080 could save that byte of code!).Obviously it is also much more convenient for dealing with pointers including arrays and structs than PIC16 and earlier.Using all of C on 8051: no problem at all. Code is not that tiny, but you can DO everything.

author: nctnico
author_rank: Super Contributor
timestamp: August 11, 2025, 12:54:45 pm
content: You are mistaken. 8051 has no real stack (except for a 7 deep call/return thingy IIRC). It is one of the crappiest microcontrollers to write a C compiler for.

author: peter-h
author_rank: Super Contributor
timestamp: August 11, 2025, 02:02:27 pm
content: QuoteYou are obviously an expert so you know it, but there is a lot to learn about parameter passing conventions in function calls, etc. I've disassembled a lot of my C code, when stepping through into the STM supplied libc.a (no sources provided) you have only the disassembly to work with. I spent many hours tracing through code, to find where it was expecting a mutex function to be implemented, etc.What we did in the 1980s, with Z180 and IAR C, was to develop most of the product in C, which hugely speeded up productivity (it was a DP8344 based coax/twinax IBM compatible box, so very complex, and had to use the IAR "large model" where each function, no bigger than 4k or so, would be banked-in, so you could have up to 1MB of code on a "Z80" CPU) and then I would write bottlenecks in asm. For example, on another product which parsed HPGL, I would asm code a "sscanf" dedicated to handling only the ddddd.dddd decimal format, for which there is a very efficient hack which loads a float value directly.You could argue the same hacks could have been done in C but asm was still several times faster.And I would suggest that is the way to do it even today - unless using something like a 168MHz STM 32F4xx + in which case you won't need asm except for special stuff like code which must never be optimised, or coding for a chip with 512 words of FLASHThe latter is the only "asm only" case now... yes it does exist, but probably in stuff like toasters!

author: cunningfellow
author_rank: Regular Contributor
timestamp: August 11, 2025, 10:00:27 pm
content: Quote from: nctnico on August 11, 2025, 07:44:34 amI am only an average assembly programmer and I think I beat AVR-GCC often enough in time critical parts of my hobby code.Quote from: nctnico on August 11, 2025, 07:44:34 amI can't argue that pointI mix C and ASM and only use ASM if the C is too slow. The C code gets written 10x faster than the ASM.

author: westfw
author_rank: Super Contributor
timestamp: August 12, 2025, 01:28:21 am
content: QuoteYou might take a look at the FTDI "VNC2" USB Microcontroller.About the worst assembly language documentation I've ever seen, and I've been unable to find ANY description of the actual CPU architecture that might make it more understandable :-( They assume that you'll be using their kernel, their libraries, and their C.A lot of architectures are supported by the Gnu assembler, which is sort-of nice since you get common directives and macro language and such. But it's an assembler aimed more at supporting their compilers, so it's not always the most pleasant assembler to use. And the syntax it implements for a given CPU may not match the CPU vendor's syntax.I guess you want the vendor assembly-language toolchain to be free? That's common, but not universal. (Eliminates the x86 family, I think. Except that there are alternatives to the Intel/Microsoft tools. I remember having to shell out for MASM...)A bunch of the modern microcontrollers won't document the CPU in the chip vendor documentation. They just refer you to the CPU IP vendor documentation. This includes ARM, MIPS, ESP (tensilica), and RISC-V. This CAN lead to a frustrating exercise in figuring out exactly what subset and/or extensions your particular chip can use, which what limitations might exist. (I find the ARM Cortex-M0 particularly annoying - any orthogonality was discarded to "compress" the instructions into 16 bits, and you're left wondering "which data processing instructions support an immediate operand and what was the range of those operands?")

author: brucehoult
author_rank: Super Contributor
timestamp: August 12, 2025, 02:51:00 am
content: Quote from: nctnico on August 11, 2025, 12:54:45 pmThat's not what the references available to me say.The SP is located at internal address 0x81 and points to another internal address (RAM). Things stored on the stack, whether by PUSH or by function call, are accessible using normal memory reference instructions, as I showed in my previous message.The main limitation is that the stack size is limited to the 128 bytes of internal memory that don't have another purpose, shared with global variables. However the contents are accessible and can, for example, be copied to/from a larger stack in the 64k external memory space.Not mentioned by me previously: there is no direct way to call a function via a pointer, but this can be done (with a little fiddling) by pushing the function address on to the stack using PUSH and then doing a RET. This is most conveniently done with the aid of a small helper function stub which receives the return address on the top of the stack and the desired function address under it. Pop both values, push them back in the opposite order, and do a RET. Alternatively the indirect function address can be passed in some other way (registers or some other internal memory location) and then simply pushed on top of the return address and do a RET to the desired function.You can also do this via "JMP @A+DPTR", which will be faster, but it once again requires a helper stub to turn the JMP into a CALL and it also means you can't use A or DPTR for argument-passing purposes.This document is quite explicit about how it all hangs together:https://www.silabs.com/documents/public/presentations/8051_Instruction_Set.pdfe.g. "PUSH Direct"----- This instruction increments the stack pointer (SP) by 1- The contents of Direct, which is an internal memory location or a SFR,are copied into the internal RAM location addressed by the stack pointer- Example:Code:PUSH 22HPUSH 23H- Initially the SP points to memory location 4FH and the contents of memory locations 22H and 23H are 11H and 12H respectively. After the above instructions, SP=51H, and the internal RAM locations 50H and 51H will store 11H and 12H respectively.----Similarly see the descriptions of ACALL and LCALL which prove examples very similar to those for PUSH, explicitly showing the return address saved into RAM, not some --as you say -- "7 deep call/return thingy".And also the description of RET:----- Suppose SP=0BH originally and internal RAM locations 0AH and 0BH contain the values 30H and 02H respectively. The instruction leaves SP=09H and program execution will continue at location 0230H.----It all seems very clear to me, and contrary to what you say.

author: brucehoult
author_rank: Super Contributor
timestamp: August 12, 2025, 03:38:13 am
content: Quote from: westfw on August 12, 2025, 01:28:21 amDude! You've stolen my go-to "awful ISA" example!Perhaps you'll be interested in what I've written about it.https://www.reddit.com/r/RISCV/comments/w5nduu/comment/ih9o9e2/QuoteRight. It's not the best for writing large amounts of asm as a result. Even something as simple as assigning symbolic names to registers in a function isn't possible except by using the C preprocessor and #define (and #undef after the function).The Arm (ONLY!) version adds a directive for this:Code:foo .req r0add foo,#1.unreq fooI don't know why that isn't propagated into the generic codebase.QuoteI actually prefer that, as long as they give you a good pointer to it.It's far better KNOWING they used a standard core than having to pore through the entire document to see if they made any little changes.They certainly should tell you exactly which core and what set of extensions are used.QuoteYes. This is what makes me hesitant to recommend C-M0 (Thumb1 in general) as the first asm for a beginner to learn. The actual operations provided are good, and there is a nice limited and documented set of them, well supported by compilers and other tools, but there are something like TWENTY different instruction formats with different sets of registers that can be used, different sizes of constants/offsets, and some are signed and some are unsigned.It's a real shame because the RP2040 is a pretty nice chip, and on the lower end you have the Puya 10c chip too (PY32F002A), and also the SAMD21 family with a number of boards including Arduinos the Seeeduino XIAO etc.Full Thumb2 is just TOO complex, too many instructions, no well-defined subsets.Same for Arm64. H&P tried to simplify it with LEGv8 but other than a GUI simulator there is no tool support (e.g. GCC or LLVM).Original ARMv2 or ARMv4 or something is perhaps the best option (for beginners) in the Arm ISA family. The number of instructions and instruction formats is small. But the individual instructions are complex, with conditional execution of everything and the "flexible 2nd argument".This is where I think RV32I or RV32E or even RV64I are so great. Just 40ish instructions in four basic formats, all registers are usable by every instruction, all immediate/offsets are signed with all normal instructions having 12 bits, with a couple of special instructions with 20 bit immediate. Documented in a single cohesive (for RV32I) chapter I think 18 pages long. Well supported by tools and libraries.And while the C extension formats are a bit more complicated and irregular -- similar to Thumb1 -- you can tell the compiler/assembler not to use them, or if it is allowed to use them then it's transparent to the programmer. You just write the full, general, instruction and the tool uses the compact one when it can. Thumb2 works in the same way, but it's a considerably larger instruction set, even in the C-M3.Well, ok, maybe C-M3 (ARMv7-M, without FP) is the best beginner's Arm ISA.

author: westfw
author_rank: Super Contributor
timestamp: August 12, 2025, 05:38:20 am
content: QuoteIt's not too bad now, depending on whether there is further indirection.I looked at ARM earlier on (ARM7TDMI, or maybe the original CM-3 chips?) and I remember finding an ARM32 reference with "except Thumb2 doesn't have x, y, and z." (Maybe just poor search skills or bad links. Now, there are nice separate manuals for ARMv6m and ARMv7m (although ARMv8m was still pretty messy?)RISC-V is a bit like that too. You get linked to a manual and have to manually subtract from it depending on subset/etc.(And the new AVR chips no longer have the "instruction set summary" section, cause I guess they wanted to eliminate 3 pages from their datasheets. Instead, you get referred to a generalized "avr instruction set" manual, and ... have to subtract out the ones that don't apply to your chip (identified by mysterious designator that requires another level of indirection. Sigh.))

author: peter-h
author_rank: Super Contributor
timestamp: August 12, 2025, 09:43:56 am
content: Yes exactly, the 32F4 is Thumb instruction set. Not trivial to pick up.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 12, 2025, 10:12:04 am
content: Quote from: westfw on August 12, 2025, 05:38:20 amIt's always the same story: excessive number of indirections, or poor documentation of what exactly applies; the genericity itself isn't the root problem.I mean, how hard it can be to write it like this:PART XYZ DatasheetChapter n: Instruction set architecturePlease refer to manual ABC1234. Part XYZ is variant QWERTY with extensions ASD and FGH.But no. Manufacturers can write 2000 pages of careful documentation but they are incapable of writing that SINGLE ****ING SENTENCE, which leads to sometimesdaysof wasted time per developer or collectively 100 man-years of lost time when people work under wrong assumptions and wonder why things don't work, or try to ask ChatGPT what the chip actually does and get the wrong answer.

author: paulca
author_rank: Super Contributor
timestamp: August 12, 2025, 10:14:38 am
content: Quote from: Siwastaja on August 11, 2025, 09:50:05 amThe issue is the "variants". Sure it's RISC. They reduced the instruction set. Only they then expanded it in conditionals, compounds and variants.Add r1, r0 IF Z and shift LEFT 16There are dozens and dozens of variants like this.These instructions and their complexity is not designed for humans. It is designed for compilers.

author: paulca
author_rank: Super Contributor
timestamp: August 12, 2025, 10:21:00 am
content: For the OP.You can get to something working very quickly by using just an Arduino and the _asm{} keyword inline ASM in C++.Not too much of a step to pull that ASM out into a *.s file and the arduino IDE will build it and link it. This will let your explore some of the "C++" call structures, if you want arguments or return values.The trickier part with ASM I found was .. it's very hard to find something "practical" which "needs" ASM. I found myself struggling and just defaulting back to C and giving up.So I went to a system where there is no C compiler and no safety net. If I wanted the system to do something I had no choice but to do it in ASM. There are limited avenues, but retro 8 bit computers is where bare human ASM coding was still king. There it's not just the hard way, in many cases it's the ONLY way. This oils the gears or exploration and forces you to see it through and "get good".Here is a post from when I recently visited AVR (Arduino) for some light ASM fun.https://www.eevblog.com/forum/beginners/cool-stuff-to-do-with-cheap-modules-1456/msg5948378/#msg5948378

author: Siwastaja
author_rank: Super Contributor
timestamp: August 12, 2025, 10:34:50 am
content: Quote from: paulca on August 12, 2025, 10:14:38 amMaybe their binary encodings is what you find nasty? But to me as a human(??) "add R0 shifted left by 8 to R1" is actuallyeasierthan "shift R0 by 8 and put it in R0; add R0 to R1". Just... combining two operations, skipping an intermediate temporary storage register. Operations themselves are still easy to understand.But maybe the challenged is in understanding what addressing modes, what offset ranges or intermediate ranges are available. Architectures where the same instruction can doanythingregardless of immediate value, or memory address, are of course easy to write, but they have wide instructions and thus waste a lot of program space.

author: nctnico
author_rank: Super Contributor
timestamp: August 12, 2025, 03:20:16 pm
content: Quote from: brucehoult on August 12, 2025, 02:51:00 amThat will be super slow. Again, I have extensive experience programming C on the 8051 and what you see the higher end C compilers doing is using the stack in IRAM for call/return only and tracking depth of C function calls while compiling to make sure the stack doesn't overflow. The stack isn't used to pass variables; typically function parameters are converted into global variables under the hood. Especially when there is external memory attached to the 8051. Also keep in mind that IRAM in the 8051 is precious because it is the only RAM which can be accessed quickly and essential to write fast interrupt service routines on a processor doing 4MIPS or so. Ofcourse you can emulate whatever you want, but only solutions which retain as much performance as possible are viable.

author: brucehoult
author_rank: Super Contributor
timestamp: August 12, 2025, 08:48:42 pm
content: Quote from: nctnico on August 12, 2025, 03:20:16 pmFFS.Your claim "8051 has no real stack (except for a 7 deep call/return thingy IIRC)." is incorrect.Ofcourseit is slow. That is what I said originally:QuoteTo which you replied "Sorry but this is plain wrong. What is needed are A) a good C compiler optimised for 8 bit platforms and B) a different coding style (like not using pointers so much). A good 8 bit oriented C compiler will produce better code compared to a skilled assembly programmer."No, a good 8 bit C compiler will NOT produce better code than a skilled assembly programmer, because compiling real C, using actual normal C features, inherently produces big and slow code on these machines.And, as I have said, it is simply impossible to compile C to native code on PIC16 and earlier. On 8051 it is possible, but slow. That is a very fundamental difference.QuoteI'm a compiler engineer. I've written compilers for such machines. The 6502 is very similar -- the hardware stack is limited to 256 bytes (vs 128 bytes on 8051, shared with globals), there are 256 bytes of fast memory (Zero Page). 8051 is actually better than 6502 here because it treats the first 8 bytes of IRAM even more specially, as register numbers embedded inside the 8 bit opcodes, not an extra byte.The best way to use 6502 in a modern compiler is to treat 16 or 32 bytes of Zero Page exactly the same as you'd treat registers on a modern RISC such as Arm or RISC-V or MIPS, divide them into caller-save, callee-save, and temporary registers, and use them to pass function arguments and return results. Unless a function has so many local variables that it overflows the global space used for "registers" the only use of the stack is function return addresses (on the hardware stack) and to save&restore the callee-save registers as needed (on a software-maintained stack in the main part of RAM).The 8051 will be exactly the same, except it already does the "part of IRAM are registers" mapping for you.QuoteOf course. But you're either compiling C or you're not. Maybe you find it useful to use a language that looks a bit like C but there are all kinds of things that are normal in C on any other machine but you can't use. Then it's not C.

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 12, 2025, 09:20:27 pm
content: Quote from: nctnico on August 12, 2025, 03:20:16 pmI think so too, I have used SDCC with Cypress FX1 and FX2 MCUs quite a bit in the past. I don't remember all details, but I think that was how it compiled function calls too.For someone willing to start with assembly, I would definitely recommend RISC-V if they want to begin with something current rather than ARM, which is less clean IMO and a bit harder to pick up. For something older, any 8-bit assembly will be a good learning experience, even if some of them will definitely be more fun than others. The 68k is of course great as well.

author: brucehoult
author_rank: Super Contributor
timestamp: August 12, 2025, 09:52:03 pm
content: Quote from: SiliconWizard on August 12, 2025, 09:20:27 pmI definitely second all of that.RV32I (or RV32E or RV64I) is a very small and simple instruction set that is nonetheless enough to efficiently implement all modern software.Obviously that doesn't include hardware accelerators for specialised functions such as floating point, SIMD, crypto such as AES or SHA etc but you candoall that stuff, more slowly, using integer calculations. The 8 bit CPUs and the 68000 don't have that stuff either. (the 68000 can use an add-on 68881 FPU chip, but I've never seen an actual 68000 with one, only 68020)The 8 bit CPUs have relatively small and simple and easy to learn instruction sets -- though not as simple as RV32I. The problem with them though is that they are very hard to learn to use effectively, with a lot of tricks and strange idioms needed .. and just plain big code. e.g. a 32 bit addadd a,b,con a 32 bit RISC becomes 13 instructions on a 6502.The only exceptions are that original 6800 is quite simple to learn, and 6809 and AVR are more complex but reasonably easy to use to write real programs. The rest of them are complete frustrating PITAs. But I enjoy puzzles.

author: westfw
author_rank: Super Contributor
timestamp: August 13, 2025, 01:45:54 am
content: QuoteNonsense. An application only needs to be "fast enough", not "as fast as possible."Thus the "viability" of assorted interpreted languages, from BASIC to PCode Pascal to Python. Not to mention any number of not-very-good compilers.(I'll nominate Parallax's "Stamp BASIC" as one of the largest performance gaps between "native assembly" and "HLL as used to do many useful things." (BASIC byte codes in bit-banged SPI Flash. Ran about 1000 "BASIC" statements per second...))And I'll nominate MSP430 as having the nicest assembly language of "current" microcontrollers.(Although: there are also current 68k variants. Not very popular in hobbyist circles, and with C compilers that are good enough that assembly language is less attractive, but they do exist. I'll admit to not being up-to-date WRT "Coldfire" vs the original 68k architecture.)

author: peter-h
author_rank: Super Contributor
timestamp: August 13, 2025, 07:30:02 am
content: QuoteThat's not bad actually...I once implemented Tiny Basic, Z180, 14MHz, on a user programmable comms product. It did < 100 lines per second but was quite usable. 1-2k code size on a Z180. That box also contained a Hisoft Pascal compiler+editor and most people used that; 1000x faster. But even more used that Hitech C cross-compiler package.I spent decades writing asm, so I am pretty familiar with the advantages, but in the old days C was a lot worse than today with ~200MHz arm32 chips for £5. Times have moved on. Maybe for extremely cost sensitive or very low power stuff one still uses specialised chips. And a lot of low power applications e.g. telemetry can be done by turning the processor on with a small duty cycle so no special low power chip is needed.

author: brucehoult
author_rank: Super Contributor
timestamp: August 13, 2025, 07:46:31 am
content: Quote from: westfw on August 13, 2025, 01:45:54 amMSP430 and Coldfire are fine and I wouldn't complain if someone asked me to program either one ... but I don't think they're anybetterthan the various Arm & RISC-V options, and they're rather niche. You can buy chips, but what boards are available other than the manufacturers' eval board?https://godbolt.org/z/zhn9o8fK9

author: nctnico
author_rank: Super Contributor
timestamp: August 13, 2025, 09:47:17 am
content: Quote from: westfw on August 13, 2025, 01:45:54 amI'm sorry, but you are pulling things out of context here. The context is that a compiler which always produces slow & bloated code is pretty much useless. Been there, done that. Take Dave Dunfield's 8051 C compiler as an example of how not to write a C compiler for the 8051. In case of the 8051 the higher end compiler makers (like Keil) choose certain solutions in order to allow their compilers to produce the most optimal code in terms of execution speed versus how much of C is implemented. This helps firmware development because the programmers don't need to resort to writing tedious assembly themselves. Which in turn makes the C compiler pay for itself.

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 13, 2025, 01:46:37 pm
content: For the 8051, I'll again take the example of the FX1/2 - pretty common MCUs for USB devices back in the days. I don't think anyone in their right mind would implement a full USB device using assembly only (but if any of you have, I'd be curious to see that). Keil C and even SDCC are decent options, even if it's a bit "limited" C, it still beats using assembly directly for anything moderately complex.But I don't think that was the point of this thread. The OP wants to use assembly so is probably not here to be lectured about the merits of high-level languages.

author: peter-h
author_rank: Super Contributor
timestamp: August 14, 2025, 06:38:06 am
content: I wonder why the OP wants assembler?It sounds like it is for learning to program in it. If it was that, one might recommend a different CPU. I am not sure many CPUs relevant to today's embedded scene, in production, would be very suitable.

author: Rafiki
author_rank: Contributor
timestamp: August 14, 2025, 11:50:56 am
content: Quote from: peter-h on August 13, 2025, 07:30:02 amDepends on how you define 'old days'. I remember when we switched from programing 8031 in ASM and PL/51 on the MCS (? the big blue tower with 8" disks) to PC. Even then Keil51 (v3.2 or was it v2x or 1?) was astonishingly good when it comes to code efficiency (and speed). Though there was another compiler manufacturer we also tested at these times which was terrible bad.

author: peter-h
author_rank: Super Contributor
timestamp: August 14, 2025, 12:11:29 pm
content: I remember the big blue Intel MCS devkits but never used one. I built my own CP/M 2.2 machines, with two 8" disk drives, and later 3.5" disk drives. The Intel stuff was incredibly expensive.We used IAR C from c. 1985 and of course productivity was much higher than asm. It was slow, some 10x slower than asm, but easily fast enough for the job.Today I would not choose a CPU for asm programming. Really cannot see the point. Although I have a product using the Atmel 90S1200 which will need re-doing using the nearest later one (tiny2313)https://www.eevblog.com/forum/microcontrollers/replacing-an-atmel-90s1200/and what will be asm again. Just now I see the 2313 has been dropped too

author: Rafiki
author_rank: Contributor
timestamp: August 14, 2025, 03:36:05 pm
content: It must have been 1987/88/89 when we compared Keil and I think it was IAR (IIRC). Keil was superior by far while the other one was astonishing bad. That's what I know for sure cause we decided to go the Keil way. At least at that time.

author: brucehoult
author_rank: Super Contributor
timestamp: August 14, 2025, 03:47:04 pm
content: Quote from: Rafiki on August 14, 2025, 03:36:05 pmA lot can happen in 35-40 years!Host PCs have gone from 5 MIPS to 10,000 MIPS. 2000x. Per core. From 1 core to 8-16 cores. And from 2-4 MB RAM to 8-32+ GB RAM. ~4000x. And from 20 MB disks to 1 TB. 50,000x.

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 14, 2025, 03:51:58 pm
content: And with that whopping evolution of hardware, software always consumes resources faster than hardware evolves, as Wirth noted a long time ago already.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 14, 2025, 03:58:28 pm
content: Quote from: SiliconWizard on August 14, 2025, 03:51:58 pmIt was looking bad, with software folks not catching up, but gladly we invented AI and now we are good again.

author: Siwastaja
author_rank: Super Contributor
timestamp: August 14, 2025, 04:01:17 pm
content: Quote from: brucehoult on August 14, 2025, 03:47:04 pmAnd, as a result, cross-compiling a typical medium-to-large-ish microcontroller project:Code:wc -l *.c37608 totalmake clean; time make -j24real0m1,015sWith this, I wouldn't even need to worry with getting dependency output for makefile right anymore! Or think about lesser optimization levels to make compilation faster.

author: westfw
author_rank: Super Contributor
timestamp: August 15, 2025, 08:47:41 pm
content: QuoteNo, I think we're talking about similar "context"; I just disagree with you. :-)I believe that a compiler that produces slow and bloated code is better than an unfamiliar assembly language, as long as your application fits and runs at "acceptable" speed. Nor does it have to be a "standards conforming" C compiler, or even a standard language.Just in the last few weeks, I've seen a couple people on the forums here say things like "I usually compile without optimization because [usually debugging.]" They're mostly derided, but there you have people intentionally putting up with slower and more bloated code... Similarly for the "free" versions of the Microchip PIC C compiler that produced awful code - people weren't happy about it, but they still found it useful. (However, note that the code quality from Microchip's free compilers has somewhat steadily improved, presumably in response to the "unhappy" part.)

author: John Coloccia
author_rank: Super Contributor
timestamp: August 16, 2025, 01:09:10 am
content: Quote from: westfw on August 15, 2025, 08:47:41 pmWe mostly have no need to optimize at the compiler level. That said, my particular applications are not toasters where it's valuable to save $.20...or $10...on a smaller, cheaper, more efficient processor. My driving force is most often IO and peripherals, and I usually end up with a chip that is overkill for what I need.I do think it's silly to preoptimize in any way. If you can get away with not, then what's the harm? Keep it as simple as possible. If it's a problem, then go for it.

author: paulca
author_rank: Super Contributor
timestamp: August 16, 2025, 09:52:14 am
content: I think it comes down to philosophy. Here me out.In software engineering when a novel problem is being solved which hasn't been solved before the first few iterations over the problem can present a "Simple and quite effective solution". Say:Solves 90% of the cases with 10 units of effort (complexity/performance/power whatever).However, after a few more iterations, a few more years and a few more genuises get to the problem they find a:Solution which solves 100% of the the cases with 35 units of effort.Here is the crux. Approach one is de-invested and effectively disappears.The "short simple happy path" approach is deprecated in favour of the more complete, more complex, more overheads version.This is seen as a "victory of abstraction".Compilers are right in the front lines of this stuff happening. The only blessing for compilers is that when they become popular and are for a popular architecture, when the above has completed and the compiler become mature, then the "nerds return" and now nobody cares if they try and troil for years to optimise things by finding those little short cuts around the abstractions.As anyone who has dealt with real world large scale application and the "-O" flag will tell you, there is merit in both approaches.I suppose to ignorantly reach in and pivot your minds, as I feel I must, remember software has "ZERO INSTANCE COST". 99% of the cost is in software engineer labour. This is why the industry spends 99% of it's optimisation in the software development and not the software itself. This is the opposite to electronics where the "per unit" cost is king and the optimisation focuses there.

author: slugrustle
author_rank: Frequent Contributor
timestamp: August 17, 2025, 01:23:12 am
content: Quote from: peter-h on August 14, 2025, 06:38:06 amI enjoy programming in assembly. I've mostly stuck to 8-bit PICs and was curious about more modern chips that might have good toolchain support for assembly language programming. I hope I said as much in the first post in the thread.Mostly, I'm doing really simple embedded stuff and find that assembly is a good match. I like how it makes me think about how the MCU actually works and enjoy some of the neat tricks one can pull in assembly that would be difficult or impossible in a higher level language. One of my favorites was a state machine for monitoring a quadrature rotary encoder. I made the state variable equal to the address offset from a computed relative branch that would jump to the section of code implementing the target state's logic.Another time, I wanted to very quickly shut down a power converter from an interrupt context. I happened to know that the main loop wouldn't be inside a subroutine when this happened, so I had the ISR modify the return address at the top of the hardware stack to point to the shutdown routine and then return from interrupt. That let me use the same section of code for normal and fast shutdown without worrying about reentrancy.And then of course, there's doing cycle accurate timing at the instruction level. All sorts of fun.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: August 17, 2025, 01:32:09 am
content: Quote from: slugrustle on August 10, 2025, 11:11:27 pmPretty much everything hassomeassembler support.What starts to separate the players, isDebug Support for AssemblerSome simple ASM-IQ tests:Can the debugger/simulator do symbolic watch on ASM variables?Can the debugger/simulator step into MACROs and include files?Can the debugger/simulator step freely between ASM and C source files?

author: Doctorandus_P
author_rank: Super Contributor
timestamp: August 17, 2025, 02:06:42 am
content: It's probably been written before in this thread, but I guess any uC family has an assembler. GCC usually first compiles to asm, which is then assembled, or at least it can create assembly listings, both for code analysis and for debugging the C compiler itself.Quote from: slugrustle on August 17, 2025, 01:23:12 am8-bit uC's are fairly straight forward, but the 32-bitters are a lot more complex. They have instruction cashing, look ahead for reading flash (with wait states), different clock domains with different frequencies on the processor, (and thus also synchronizers) and other complexities. As a result, you simply can't do cycle accurate timing anymore.A while ago I did some work of porting a network stack (UART + RS485 driver) from AVR to STM32. On AVR I could toggle the direction of the RS485 driver, and then write to the uart send data register, and there would be the expected 1 clock cycle delay between the RS485 pin and the start bit. On an STM32 which ran at a much higher clock frequency, the delay was much longer. And apparently this is to be expected. I have however not yet investigated this further.

author: brucehoult
author_rank: Super Contributor
timestamp: August 17, 2025, 03:10:28 am
content: Quote from: Doctorandus_P on August 17, 2025, 02:06:42 amGCC *always* compiles to asm, on all platforms.QuoteYou absolutely can on most 32 bit (and 64 bit)microcontrollers. They will have simple in-order pipelines -- often 2 or 3 stage (maximum 5), that have short and predictable branch timing with no need for dynamic branch prediction (or you can disable it), close-coupled SRAM with short access times (the same as L1 cache would be on a larger processor), and you can (unlike many of the 8 bit CPUs) copy critical code from flash into RAM and execute it from there with predictable timings.Even Linux SoCs often have microcontroller cores alongside the application processor cores for real-time bare metal code. Often this will be essentially the same type of CPU core as the application processor core(s), just without FPU or SIMD, without caches, without branch prediction. without MMU, and perhaps running at a lower clock speed.e.g. CV1800B with a 1.0 GHz 64 bit C906 application processor core (with MMU, FPU, 128 bit vector unit etc) plus a 700 MHz C906 64 bit microcontroller core. Or the SG2000/SG2002 with the same, plus an A53 application processor core.Or the SiFive U54-MC with four 64 bit U54 application processor cores along with one 64 bit E54 microcontroller core -- used for example in the FU-540 SoC (HiFive Unleashed) and Microchip PolarFire SoC FPGAs and PIC64GX.

author: Tation
author_rank: Regular Contributor
timestamp: August 17, 2025, 06:40:54 am
content: Quote from: slugrustle on August 17, 2025, 01:23:12 amA common C/C++ idiom for coding FSM is using a state variable storing a pointer to the function that will manage each state.For the fast shutdown (if I understood you correctly), can call the same shutdown function from main loop or ISR.I sometimes use assembly, but the scenarios where it is necessary are, progressively, more and more scarce.Sometime now into Zephyr using VS Code as IDE, and still able to debug/single step/breakpoint assembly functions.

author: peter-h
author_rank: Super Contributor
timestamp: August 17, 2025, 07:02:46 am
content: Cube IDE can set breakpoints on 32F4xx asm code. I used that extensively to work out the ST-supplied libc.a for which there were no sources.I don't think you get exact instruction timings on arm32 because of bus contention for peripherals and memory etc etc.

author: brucehoult
author_rank: Super Contributor
timestamp: August 17, 2025, 08:10:32 am
content: Quote from: peter-h on August 17, 2025, 07:02:46 amThe CPU should have priority for access to DTCM and ITCM, if peripherals can even access those areas at all.

author: abyrvalg
author_rank: Frequent Contributor
timestamp: August 17, 2025, 03:34:10 pm
content: One thing usual in 8-bit toolchains but often missing in 32-bit ones is asm include files describing peripheral regs. SVD converters should help with that, but that could be a bit frustrating.

author: NorthGuy
author_rank: Super Contributor
timestamp: August 17, 2025, 03:51:36 pm
content: Quote from: slugrustle on August 17, 2025, 01:23:12 amI think this is the understanding on how CPU works that you enjoy, not the assembler per se. I think that is where you should start from - from understanding how the CPU works. Once you understand this, you can design things for the CPU. Once you have a design you can implement it in assembler, or in C, or whatever meets your needs. This is different from the language-centered approach, which suggests to avoid CPU details and concentrate on the language - such as making your intentions known to the compiler and similar esoteric bullshit. Whether you actually use assembler or not is immaterial.Quote from: slugrustle on August 17, 2025, 01:23:12 amYou could implement the same design in C using a function pointer as your state variable. The same thing.Quote from: slugrustle on August 17, 2025, 01:23:12 amThis is a little bit of overkill. You could simply remember the stack position (STKPTR register in case of 8-bit PICs) where you have started your processing, then once you get the emergency condition, you simply restore the remembered position of the stack and jump to your emergency routine which will eventually enable the interrupts back. No need to return from the interrupt. This can be done in C too, except C cannot easily jump and must use calls. Otherwise, it's the same. My point is that it's rather your understanding of the stack/interrupt working that matters, not the fact that you write in assembler.In RISC load-store architectures - such as ARM32, RISC-V, MPIS (in PIC32M) etc. instructions are rather primitive (they're called RISC for their minimalist instruction set). All operations are between registers, the registers are aboundant, everything is straightforward. Therefore you rarely can do in assembler something drastically different from what the C compiler can master. On the other hand, it's quite easy for the C compiler to generate an optimized code. Hence writing in assembler will not be as beneficial as it could be in PICs. I suggest you try anyway.

author: brucehoult
author_rank: Super Contributor
timestamp: August 17, 2025, 03:56:02 pm
content: Quote from: NorthGuy on August 17, 2025, 03:51:36 pmsetjmp / longjmp

author: hans
author_rank: Super Contributor
timestamp: August 17, 2025, 05:41:20 pm
content: Quote from: NorthGuy on August 17, 2025, 03:51:36 pmWhen I look at optimizer output from GCC on ARM, I don't see a terrific amount of gains ...In university we had a competition to implement the fastest matrix multiply routine on an Arduino Uno. Besides generating unrolled assembly code (which ultimately is the fastest), my team was 2nd fastest written in C with some in in-line assembly. The code was not trailing behind much behind the assembly implementation, but ours was only using a few hundred bytes of code (instead of filling up almost the entire ATMEGA328P for a fully unrolled version).Most other teams stuck to a plain C implementation and were quite a lot slower.However, there were some interesting corners we needed to cut.For example, the AVR architecture does not contain a "zero" register, even though AVR-GCC is making use of one. This is a software convention which in assembly you could skip. The reason why you might want to do that, is because the ATMEGA's MUL instruction always places its results in R0/R1. Meaning that the single-cycle multiply operation quickly becomes a 4-5 cycle operation to move results out of R0/R1 and clear R0 again.To be honest, I'm not sure why AVR-GCC hasn't moved the zero register to another register.. I know that could be a breaking change, maybe its possible, but it sounds like a sane default after all those years to me.Anyhow a second optimization from the C environment, was the implementation of a 24-bit integer, given the matrix and integer sizes only needed 18 or 19 bits iirc. This is not information which could easily be provided in C.. perhaps with a bitfield.In other words.. in assembly there is no ABI or calling convention. This is a bless for solo projects, and I imagine a curse for any team effort.However, thats speaking about AVR..Imo quite a heterogenous instruction set and sometimes a bit of a mess to optimize fully. On 32-bit architectures you're not going to find the same troubles as I just mentioned. Up to uint64_t covers almost anything (except for more scientific applications). And fortunately even the compact instructions (like ARM Thumb) will write back the ALU result to one of its input operands (instead of some fixed register location).Solving these puzzles can be kind of fun, but I think compilers benefit tremendously from the more homogenous structure in modern ISAs. They are a lot more flexible, easier to optimize for, and therefore lot faster to work in. Also greatly thanks to C or other modern languages.

author: slugrustle
author_rank: Frequent Contributor
timestamp: August 17, 2025, 08:21:17 pm
content: Quote from: NorthGuy on August 17, 2025, 03:51:36 pmMaybe I have a less accurate assessment of my internal state than you do, but I really do enjoy programming in assembly. Down to understanding how the instructions work, picking the right one, thinking about the flags in the status register, etc. bruceholt wrote in one of his posts that he likes puzzles. Assembly programming is a lot of little fun puzzles, but it also has a tangible result. Very fun.

author: westfw
author_rank: Super Contributor
timestamp: August 17, 2025, 09:03:30 pm
content: QuoteOh! Good point! Especially since ARM CMSIS specifies (?) that peripherals are specified as structures...Conversion usually isn't too difficult, but it is a "barrier to entry." (We had a discussion of "minimal STM32 development" some years back, resulting in (among other things) these EMACS macros for converting the ST .h files to GAS format assembler include files:https://github.com/WestfW/Minimal-ARM/blob/master/inc/stm32f103c8.asmh#L6096)Some vendors are better than others. Microchip's .h files are generally nicely conditional ("#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))"), and have individual #defines for EVERY register, while others have only peripheral base addresses #defined, and only structures for the individual registers...

author: John Coloccia
author_rank: Super Contributor
timestamp: August 17, 2025, 09:22:24 pm
content: Quote from: slugrustle on August 17, 2025, 08:21:17 pmA good reason to program in assembly, and to do anything actually, is for fun. Life isn't an optimization problem.

author: westfw
author_rank: Super Contributor
timestamp: August 17, 2025, 09:29:35 pm
content: Quoteavr-gcc added 24-bit integers, back in v5.4 (I think.)I have a mental list of things that are "clear" performance advantages of assembly over C. Off the top of my head:Mixed size math.Access to "status bits.""flexible" ABIs to functions.

author: nctnico
author_rank: Super Contributor
timestamp: August 17, 2025, 09:47:46 pm
content: Quote from: westfw on August 17, 2025, 09:03:30 pmI used to be a fan of having individual registers but nowadays having structures makes a lot of sense to me. Especially when a peripheral exists more than once. You can iterate through the peripherals or pass a pointer or index to a function which is part of the driver. Say you have 4 identical UARTs. With individual register definitions, you can't write a single function which can serve all the UARTs. You'd need to have seperate functions for each UART.

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 17, 2025, 10:11:40 pm
content: Quote from: nctnico on August 17, 2025, 09:47:46 pmYes, that's definitely almost indispensable for code maintenance and reusability.You can do the same from assembly (since this is what the thread was about) by defining offsets from a base address instead of per-register adresses hard-coded.

author: NorthGuy
author_rank: Super Contributor
timestamp: August 17, 2025, 10:19:11 pm
content: Quote from: slugrustle on August 17, 2025, 08:21:17 pmIf you like puzzles, go with an instruction-rich CPU. Microchip recently released dsPIC33AK. It actually has less instructions than ARMv7, but the instructions have side effects, direct addressing etc. So you can combine things and find non-trivial solutions. IMHO, it's much more fun for assembler writer than ARM or RISC-V. dsPIC33AK is certainly much more complex than 8-bit PICs, but rather in a good way.Another thing for puzzles is FPGA if you look at the low level. You can even design your own CPU and invent your own assembler. But I guess it's a huge leap.

author: nctnico
author_rank: Super Contributor
timestamp: August 17, 2025, 10:24:45 pm
content: Quote from: NorthGuy on August 17, 2025, 10:19:11 pmIf you want to have fun with assembler, then try a MIPS with the one-delay-slot. Or the old Analog Devices ADSP2100 series DSP.

author: peter-h
author_rank: Super Contributor
timestamp: August 18, 2025, 07:55:08 am
content: For sure if you want to learn something new and different and don't care about it being useless for most applications, learn FPGA designI did that many years ago (Xilinx). Never again...

author: hans
author_rank: Super Contributor
timestamp: August 18, 2025, 08:36:10 am
content: Quote from: NorthGuy on August 17, 2025, 10:19:11 pmYes quite a big one, but there are also quite a few RISC-V softcores that support custom instructions which may lower the bar of entry.Its fun to see how much a program can speed up once you start using those custom instructions. I tested this for a radio DSP algorithm that ran on my own RISC-V emulator for SNR and Eb/N0 tests. Implemented a hypothetical SIMD MAC instruction for the RISC-V processor, and saw the runtime get cut in half.I suppose one could design even more application specific instructions, such as a demodulator that calculates atan2 in hardware and returns the constellation symbol (or bits) right away. Personally this is the part where I enjoy writing (in-line) assembly, because a regular C compiler cannot do this for me.Its borderline embedded, but there is also a huge scene for console game reverse engineering and console emulation, which may require high-performance emulation of CPU instruction sets or even hardware like soundcards or GPUs with specific featuresets. There is a lot of AVX programming happening in there.. quite a lot of interesting videos can be found on this topic.

author: brucehoult
author_rank: Super Contributor
timestamp: August 18, 2025, 09:33:24 am
content: Quote from: hans on August 18, 2025, 08:36:10 amThere are also FPGAs with embedded real CPU cores with custom instruction extension that defines a single (or limited number of) formats for custom instructions for which it grabs e.g. two register values (register numbers specified in the instruction format) and a code for the operation to be performed, and passes them off to something in the FPGA fabric, which then passes back a result, which is written to a register.Unlike with extending a soft core, you can't allow the FPGA to arbitrarily extend a hard core, but you can set things up to work within defined, limited but useful, parameters.