While I'm putting off a couple of projects, I thought this'd be fun. The ill-defined criteria is basically the coolness of syntax and addressing modes. Not counting lack of math instructions or barrel shifters that only go one bit per instruction.
1. Arm
+ Lots of registers. Return address has own register (neat). Versatile syntax with conditional suffixes. Block transfer instructions. Easy to implement a jump table.
- No separate shift/rotate instructions outside Thumb mode.
2. x86 (32 bit)
+ Most versatile syntax and addressing modes.
- Many commands out of date but still usable.
3. 6502
+ Probably the best asm for beginners. Indexed addressing modes. Small command set and only 0-2 operands per instruction. Has decimal mode on other systems than the NES although I never tried it.
- Need to be clever (or just look at first party Nintendo code) to implement a jump table. Takes a bit of mental gymnastics to write decent functionality without using too many bytes of ram. Lacking addressing modes that would make sense (but are in 65816).
4. z80 (8080)
+ Versatile for an 8-bit cpu. Can use two 8-bit regs like a 16-bit one.
- Gameboy cpu lacks addressing modes that would make sense (can't load from memory directly into a 16-bit reg!) Way too many shift instructions.
CPUs I haven't tried programming in: Motorola, MIPS, PowerPC, SPARC
MIPS: ARM's retarded older brother with more registers
I loved MIPS R2000 when I was back in college. You only need 9 instructions to be turing complete (or so I think I remember)!
This one is also interesting:
http://bitstuff.blogspot.com/2007/02/su ... ative.html
http://en.wikipedia.org/wiki/One_instru ... t_computer
Neat. I dare him to make Space Invaders with that.
Well, I don't know that many assembly languages but as far I can remember :
6502 > Atmel > Pic > C85
C85 is a plain terrible assembly language, it lacks a lot of instrucitons and adressing modes that would make sense and you should find a complicated way arround that.
The only beef I have with 6502 is the lack of inc A, dec A and swap instruction that would be VERY usefull, and the lack of some adressing modes for common intruction, like stx $xxxx,Y lacking, which is a shame. It's also a shame that lda $xx,Y doesn't exist (altough you usually have your tables outisde of zero page).
I also like the assembly language for Atmel microprocessor (altough I haven't practiced it for a long while). You basically had a lot of registers (32) and this is very convignent. But as soon as you want to acess actual memory, you're forced to use complex instructions to do so, which is lame.
1. 6502
+ Easy to use.
- Isn't the 65C02.
2. SPC-700
+ Like 6502, with some auto-increment instructions.
3. PIC18
+ Indirect indexing, with auto-inc. All instructions take the same amount time (except a few like JMP). Instructions for working with individual bits.
- Only one work register. Just one interrupt vector at a fixed address. Requires bankswitching to access internal registers.
Memblers wrote:
2. SPC-700
+ Like 6502, with some auto-increment instructions.
I have to say that is not true, it is harder than 6502/65(c)816 because Most SNES Sceners/Developers have a very hard time programming the SPC-700. Except for EKid of XMSNES fame (and yourself, of course).
My ASM Ranks:
the top most is the best, the bottom is the worst
#1. 65(c)816 - Very good Assembly language.
#2. 6502 - Same as #1, but very minimal.
#3. 16/8 bit x86/x88 - Not the very best, But I do stuff to a DOS ANSI game creator named ZZT every once in a while.
Hamtaro126 wrote:
Memblers wrote:
2. SPC-700
+ Like 6502, with some auto-increment instructions.
I have to say that is not true, it is harder than 6502/65(c)816 because Most SNES Sceners/Developers have a very hard time programming the SPC-700.
Might that have something to do with the unfamiliar syntax?
tepples wrote:
Hamtaro126 wrote:
Memblers wrote:
2. SPC-700
+ Like 6502, with some auto-increment instructions.
I have to say that is not true, it is harder than 6502/65(c)816 because Most SNES Sceners/Developers have a very hard time programming the SPC-700.
Might that have something to do with the unfamiliar syntax?
Either that, or loading your program onto the thing in the first place. I had to disassemble it's little boot-loader ROM to make sense of the loading procedure.
But the syntax difference is as simple as this:
Code:
mov a,#$FF
mov $00,a
instead of
lda #$FF
sta $00
Memblers wrote:
3. PIC18
+ Indirect indexing, with auto-inc. All instructions take the same amount time (except a few like JMP). Instructions for working with individual bits.
- Only one work register. Just one interrupt vector at a fixed address. Requires bankswitching to access internal registers.
Uh. PIC18 has two interrupt vectors, and I've never written a program that needs direct access to more than 384 bytes of RAM (of 3968) (as apposed to pointer-like access via the FSRs)
Now PIC16 (96 bytes directly addressable of ~336) or PIC12 (16 bytes directly addressable of 256), those definitely have the downsides you're talking about.
And how is W so different from A? Using X and Y for arithmetic feels on par with the PIC's directly-addressable registers.
1. 65xx series
1a. 6502
+ Simplicity and elegance in all aspects.
(other points covered by others above)
1b. SPC-700
As others have said, quite similar to 6502.
+ More consistent assembler syntax, especially move instruction.
+ Good number of 16-bit instructions that use Y and A registers as a pair.
+ Ability to use 256-byte direct page as 256 registers for most instructions. So you can directly increment, add to, etc. one of these bytes, without touching any registers.
- Hardly used anywhere else than SPC-700.
1c. 65816
+ Clean extension of 6502, doesn't lose elegance. Feels sort of like M68K.
- Adjustable size of A/X/Y registers means headaches/subtle errors when calling routines that need different sizes.
2. M68K
+ Many registers (8 data, 8 address), none treated specially*.
+ Tons of addressing modes. Not sure if any CISC has more.
+ Extensive instruction set, consistent, very little limitation.
- Not really used anymore, except in some ColdFire embedded processors.
3. PowerPC
+ Tons of registers (32 data, 32 floating-point), none treated specially**.
+ Three-operand instructions, for example add r3,r4,r5 does r3 = r4 + r5. Avoids lots of copying to avoid modifying the source values. Also gives you useful things like "subtract register from immediate".
+ Instructions don't set condition codes unless told to.
+ Multiple sets of condition codes. So you can do three comparisons in a row, each putting the result into different condition codes, then three branches in a row that are based on the results of the comparisons. Important for pipelining.
+ Subroutine call doesn't touch the stack, instead puts return address in lr register. Means leaf routines don't need to touch memory.
+ rlwimi instruction. Rotates source operand by shift count, then ANDs with mask, ANDs destination with complement of mask, and ORs results together and places in destination. Allows inserting an arbitrary run of bits from source in any position in destination, all in one clock (overlapped with whatever other instructions are executing, since it only occupies one integer unit).
- Not as transistor-efficient as ARM, still a heavyweight chip to manfacture.
- Only used in game consoles (and embedded devices) now.
- Instruction names aren't always easy to remember.
3. 8085
+ Good number of registers.
+ Some support for 16-bit operations.
+ Conditional call and return instructions.
- Different instructions depending on source/destination (similar to 6502, but generally worse). Z-80 fixes the assembler syntax to be regular.
- Instructions take way too many cycles.
* OK, technically A7 (stack pointer) is treated slightly differently when using pre-decrement and post-increment modes when moving a byte, where it's adjusted by 2 rather than 1, to keep the stack aligned.
** OK, again, r0 is treated as a zero constant in some instructions.
lidnariq wrote:
Memblers wrote:
3. PIC18
+ Indirect indexing, with auto-inc. All instructions take the same amount time (except a few like JMP). Instructions for working with individual bits.
- Only one work register. Just one interrupt vector at a fixed address. Requires bankswitching to access internal registers.
Uh. PIC18 has two interrupt vectors, and I've never written a program that needs direct access to more than 384 bytes of RAM (of 3968) (as apposed to pointer-like access via the FSRs)
You're right, I had forgotten about the interrupt priority. On Squeedo, everything but reading the UART was high priority.
Quote:
Now PIC16 (96 bytes directly addressable of ~336) or PIC12 (16 bytes directly addressable of 256), those definitely have the downsides you're talking about.
That's what I was thinking of, because I started out with a PIC16 and later moved to PIC18.
Quote:
And how is W so different from A? Using X and Y for arithmetic feels on par with the PIC's directly-addressable registers.
W does seem the same as A once you're used to it. It's also nice to have MOVFF (though it's a 2-cycle instruction, IIRC).
I got the impression that Arm is like PowerPC crossed with 65xx after glancing at some PowerPC code.
Forgot to mention another negative about ARM, no immediate loads > #$FF. Doesn't really matter due to the pseudo ldr reg, =imm.
strat wrote:
I got the impression that Arm is like PowerPC crossed with 65xx after glancing at some PowerPC code.
Forgot to mention another negative about ARM, no immediate loads > #$FF. Doesn't really matter due to the pseudo ldr reg, =imm.
Only thing I can remember from coding on the PPC are those weird shifting instructions (RLWINM et al).. Can't say I liked it much.
Well, you can load immediates >0xFF without LDR on ARM, as long as it fits the rule
0xYY ROL Z (or maybe it's ROR, doesn't really matter though). So, e.g. MOV R0,#0x5000 is fine.
Arm has immediate loads for big shifted numbers, and negative numbers.
mic_ wrote:
Well, you can load immediates >0xFF without LDR on ARM, as long as it fits the rule 0xYY ROL Z (or maybe it's ROR, doesn't really matter though). So, e.g. MOV R0,#0x5000 is fine.
And if you can break a constant into two 0xYY ROR Z for different values of Z, you can load it in a MOV/ORR combo, similar in concept to the LUI/ORI combo in MIPS. This is especially useful on GBA and DS, whose I/O register addresses are generally of the form 0x0XX000YY. This sequence (2 cycles and no memory seeks) is faster than an LDR (3 cycles and 2 memory seeks), especially on architectures whose bus or cache has a penalty for nonsequential accesses.
ObNES: If you want to make an efficient emulator, like the PocketNES emulator that Dwedit maintains, you have to know this stuff.
Oh. I just went to my old GBA demo and replaced
mov r2, #0x80
mov r4, r2, lsl #19
with mov r2, #0x4000000
whee-hah