Or is there an assembly that get rid of this gibberish tradition?
Or is there an assembly that get rid of this gibberish tradition?
Even more so because the influx of new users of assembly languages that use it more than very occasionally are few and far between.
There has been some attempts. E.g. see [1] for an "assembler" that provides some higher level constructs where there's a simple mapping to underlying machine instructions, but that might go further than what you'd like.
MYARRAY: DEFW 100
ADD R1,R5,R7
MVI R2,R1,MYARRAY
how about: MYARRAY: WORD[100]
R1 = R5+R7
MYARRAY[R2] = R1
Not much harder top parse, and much easier to read. I see a couple of minor issues: needs a tweak to differentiate between (say) ADD and ADC; and assembler generally is small change, we're not putting much effort into it.A processor does not have a conception of brackets. Infix notation blurs the real number of operations. Processor has registers and your code does not say what you are putting in EAX what in EBX etc.
My example wasn't clear enough - I wasn't proposing full expression compiling. If you think (simplistically) of assembler as a macro processor that maps text mnemonics onto opcodes, I was proposing matching basic expression terms to opcodes (but only simple terms, like "x + y", that map to individual instructions).
Historically, there have been assemblers that do full expression compiling - where an expression compiles to multiple opcodes. But that's going back a way, when people still routinely used assembly. For modern purposes, where good compilers are easily available, something like that just confuses assembly with compilation.
There are a couple of different ways to understand assembly. Writing it with C-like infix expressions is a superior way to look at the code if you're trying to understand what it's doing on an algorithmic level (there's a reason we don't really hand-write assembly, after all!). But if you're working on assembly-level tooling, usually, you want very clear indications of what instruction you're working with, and "out_operands = opcode in_operands" or "opcode operands" are much, much clearer representations for such work. Most of the people who work with assembly care about the latter, and so the latter representation is more useful for them, and that's why we write assembly the way we do.
Multiplication results are stored in a double-length result register called MRF. The type of inputs is indicated by a modifier word in parentheses, so that multiplication between two signed integers is indicated as MRF = R2 * R3 (SSI); whereas multiplication between a signed and unsigned integer is MRF = R2 * R3 (SUI); There is no popcount, but binary log is written like R2 = LOGB F3; and presumably similar notation could be used for popcount.
Cache access seems to be controlled by mode bits in a control register. Sign extension is supported in only a few instructions, but is indicated by the trailing modifier (SE).
Yes - that's where is falls down :(
In contrast, the entire MIPS32 specification fits on one sheet of paper[1], and MIPS was used in some very productive and entertaining applications—the Sony PS1, PS2, and PSP, for instance.
ARM is similar, as is RISC-V (although the former has a flag register). I find these RISC assemblies in general more straightforward than x86-64. They are also register-register, load-store architectures that make memory accesses quite explicit.
This doesn't mean x86-64 or CISCs in general are inferior or superior to RISCs. They are two different approaches to the same problem, and as AMD has shown, it is possible to achieve good efficiency on CPUs using CISC ISAs, too.
[1]: https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_S...
Then again, 6502 specs can probably fit on one sheet of paper too, just as MIPS32 did, and it too has been used in very productive and entertaining applications—and yet it's even more idiosyncratic than x86; I've seen considerably more examples of "an instruction that sets flags; anywhere from 1 to 10 instructions that don't set flags; conditional branch" pattern in 6502 code than in x86.
I guess it's similar to learning functional vs. imperative programming language as your first intro to programming?
P.S. AT&T syntax for x86 is
a) backwards: "subl %eax, %ebx" vs "sub ebx, eax" for "ebx -= eax", ugh;
b) pretends that numbers are weird functions: "subl -32(%ebx,%ecx,4), %eax" vs "sub eax, [ebx+ecx * 4-32]" for "eax -= MEMORY_AS_ARRAY_OF_INT32[ebx+ecx * 4-32]", what the hell, minus thirty two is most definitely not a function with three arguments; neither is it a three dimensional array if we pretend that parens stand for array indexing as they do in FORTRAN.
That's fair. I started out with MIPS32. When I first saw x86 instructions, and a `mov`, my first thought was, 'what the heck? Where are the loads and stores? `mov rax, [rip + 32]` is 3 instructions in MIPS or any similar RISC, this looks weird.'
> P.S. AT&T syntax for x86 is
Oh, yeah, I hate it. x86 instructions can already get pretty long; now you have multiple suffixes just to account for size. The indexing operation is just ridiculous; Intel syntax makes it so much more straightforward.
I learned 6502 assembly as a kid right after basic... and ever since always had enjoyed it. Pretty much until the compilers became better optimizing code than me (not the 6502 one, of course)
The hard part about assembly language is its very limited abstraction. You’re only one step away from the metal. So it takes a lot of work to build a large program and it can be very tricky to get right because you don’t have a compiler or any types to help you. If you know what you’re doing, though, you can write some very small binaries!
You can write about assembly like a poet, at least.
AArch64 is more like regular than reduced instruction set computing. Its a very big complicated ISA but also not a complete mess like X86.
RISC-V is reduced by these standards but requires a very real instruction count penalty. The compressed ISA performs it's job admirably, do keep in mind, but I think it remains to be seen if some of the aggressively simple/clean aspects of risc-v end up hurting it.
Someone wrote a script that disassembled all the binaries on their Linux machine and counted the number of actual instructions used (mostly by gcc, of course). Only a tiny fraction of the total instructions were used:
http://0x80.pl/notesen/2014-01-01-instruction-utilization.ht...
Just take the top 30 of that chart and learn those. The x86 contains a lot of instructions that no one needs to worry about. Things related to the ancient segment mode or x87 floating point, OS-privileged instructions (context switching, HLT/LIDT/etc.), AMD-only 3DNow, etc.
The ISA is not the hard part anyway. Dealing with the ABI (System V on Linux) to interface with C/C++ code, the kernel syscall interface, position independent code/executable (PIC/PIE) are somewhat bigger concerns and are going to apply to RISC as well.
Modern AMD CPUs don't support it either, so it's entirely dead
Here is a bit of code extracted from the Diamonds source code:
\* This is executed each time you die (with some lives left)
maSTART_OVER GOSUBL dsQUICK_DRAW draw the bricks quickly, not disolve
maSET_FLAGS ST=0 6 you can't knock out diamonds yet.
ST=0 7 you have no key
GOSUBL hbDRAW_KEY make sure no key is showing
LCHEX #00001 white brick
GOSUBL srSTO15_C erase mode
GOSUBL emDRAW_BRICK show erase brick
LC(5) BONUS_TIME a good time...
GOSUBL srSTO25_C bonus time
GOSUBL dlDRAW_LIVES draw lives left
GOSUBL srRCL6_C get level addr
C=C-CON A,5 now pointing to X,Y and DIR
D0=C in D0 (pointing to X)
C=0 A
C=DAT0 2 read X
GOSUBL srSTO0_C X
D0=D0+ 2 pointing to Y
C=DAT0 2 read Y
GOSUBL srSTO1_C Y
D0=D0+ 2 pointing to DIR
C=0 A
C=DAT0 1 read Direction
GOSUBL srSTO2_C store it
GOSUB grGET_READY display the GET READY window D0.w = 42
.. to assign the immediate value 42 to the lower 16 bits of the D0 register (equivalent to MOVE.W #42, D0 in M68k assembly). Or: D0 = D0 + 2 (or D0 += 2)
.. just as in your example ("ADD.L #2, D0").You could also combine the asm with accessing variables etc. E.g.:
D0 = x + 2
.. would be ("MOVE.L x, D0; ADD.L #2, D0" if x was a heap variable or "MOVE.L someoffset(SP), D); ADD.L #2, D0" if on the stack. But you could also just insert the assembly directly into the code...I wish I still had the source (it was initially written in assembly, and the gradually converted to itself); it was "interesting" writing a compiler where you could reliably intersperse higher level code with assembly "safely"
But of course that puts pretty hard limits on the compiler (e.g. no optimizations), and you end up doing low level programming just with a different syntax.
That's to say, it looks convenient, and it was nice as a way of bootstrapping a simple compiler, but you're right to question whether the convenience is worth it.
If you expanded all names, that would add cognitive overhead for all users and reduce the useful information per character, and potentially reduce the information that can fit on a screen significantly.
While I'll agree that "cryptic sequences" are a more steep learning slope, they allow for much faster understanding of larger blocks of data/assembly once the "cryptic sequences" themselves are understood.
Terse doesn’t necessarily mean opaque. Even if sticking to three letter words was an absolute requirement, there are plenty of English words that would make a better jobs at conducting the idea without falling into a collection of unpronounceable idiosyncratic terms.
> as the information is spread across less characters that need to be interpreted by the brain.
That’s not how the brain interpret text generally, once reading is fully acquired. Words, or even group of words are taken all together.
Would it be for scriptural compactness alone, it would be far more efficient to use dedicated symbols optimized for that purpose. But if the idea is to optimize readability for an unknown large audience, then this is most likely a rather misguided choice.
>If you expanded all names, that would add cognitive overhead for all users
Well, I disagree. To my mind it would on the contrary significantly reduce cognitive load for those not already familiar with the uselessly abstruse terms, and add nothing to those already accustomed to code constructions in the machine specific language.
>reduce the useful information per character
Once again, this is a very poor metric for human interpretation of textual works.
> potentially reduce the information that can fit on a screen significantly.
So what? Number of signs displayed on the screen is certainly not the limiting factor here. How much juxtaposed signs a human attention can meaningfully handle is far more compelling.
>they allow for much faster understanding of larger blocks of data/assembly once the "cryptic sequences" themselves are understood.
I am not aware of any study that supports such a statement on empirical evidences. Maybe you can point me to such a study and help me change my mind?
Assembly, back in the time of punched cards, had some reasonable rationals for avoiding input sequences longer than strictly necessary. Bu these rational no longer fit the contemporary digital landscape.
(E.g. jump_if_greater would not be that good, jge is too short and unless you actually know what it is, it is hard to decipher, jmp_ge is not a bad compromise)
But apparently, this is not a win-win, but a lose-lose since this notation is hated by both assembly programmers and not assembly programmers :-D
That seems to be a bit tangent to my remark though: this seems to be more about adding syntactic structures, embodied with miscellaneous brackets, and there are still some obfuscating abbreviations like "ldstr".
ldstr "Hello!"
call void [mscorlib]System.Console::Write (string)
And come to that: ((write: "Hello!"))
So `ldstr` does indeed feature in the example but only as a "before" picture.But you're right, it is about adding syntactic features to the existing language.
Otherwise, mnemonics are the way they are because of history, but also practicality. Since you're going to be writing them a lot, you want them to be short. It also doesn't take too long until their meanings are burned into your brain.
Or is there an assembly that get rid of this gibberish tradition?
Look up Randall Hyde's HLA. The famous author of various Asm books thought he could make a better syntax, and... almost no one wanted it.
The real answer is that nobody is supposed to write assembly, and the way the instructions are written is very easy to parse. The only core that doesn't have the "it's ancient and we didn't know better" excuse is RISC-V, IMO.
C
dest = src1 op src2;
Only basic control flow, no structured loops and so forth