adam_smasher wrote:I love the 6502 - but one could easily argue that the 6502's register paucity, or its huge number of obviously "missing" instructions (push and pull X or Y, for instance), or the aspects of its design that make it a poor target for C compilers are similarly debilitating.
The CMOS 6502 (65c02) has been out for about 35 years and is still in production with no end in sight, unlike the NMOS which went out of production many years ago. The 65c02 does have push and pull X and Y (PHX, PLX, PHY, PLY), and quite a few others. The following is from my page on the differences between the NMOS and CMOS '02, at
http://wilsonminesco.com/NMOS-CMOSdif/ :
CMOS 65c02 new instructions that were not on the NMOS 6502 at all:
Code: Select all
instruction op code
& addr mode (in hex) description
BRA rel 80 Branch Relative Always (unconditionally), range -128 to +127.
PHX DA PusH X. ‾⌉
PLX FA PulL X. | No need to go through A for these anymore.
PHY 5A PusH Y. |
PLY 7A PulL Y. _⌋
STZ addr 9C ‾⌉
STZ addr,X 9E | STore a Zero, regardless of what's in A, X, or Y.
STZ ZP 64 | Processor registers are not affected by STZ.
STZ ZP,X 74 _⌋
TRB addr 1C ‾⌉ Test & Reset memory Bits with A.
TRB ZP 14 _⌋
TSB addr 0C ‾⌉ Test & Set memory Bits with A.
TSB ZP 04 _⌋
BBR ZP 0F-7F [1] Branch if specified Bit is Reset. ‾⌉ These are most useful
BBS ZP 8F-FF [1] Branch if specified Bit is Set. | when I/O is in ZP. They
RMB ZP 07-77 [1] Reset specified Memory Bit. | are on WDC & Rockwell but
SMB ZP 87-F7 [1] Set specified Memory Bit. _⌋ not GTE/CMD or Synertek.
STP DB SToP the processor until the next RST. ‾⌉
Power-supply current drops to nearly zero. | These two are
| on WDC only.
WAI CB WAIt. It's like STP, but any interrupt |
will make it resume execution. Especially |
useful for superfast interrupt response, |
with zero latency. See interrupts primer. _⌋
Note: [1] Only the most-significant digit of the op code changes; so for example BBR's
op codes are 0F, 1F, 2F, 3F, 4F, 5F, 6F, and 7F, for BBR0 to BBR7. The bit number is
specified in the op code rather than the operand. These operate in ZP only. Rockwell
added these first, for their microcontrollers that had I/O in ZP. WDC added them in
the early 1990's. The Aug '92 data sheet shows the W65C02S available without them, and
the W65C02SB with them, but said eventually they would all have them, and be labeled
W65C02S, without the B. By the July '96 data sheet, these instructions were standard
in all of them.
CMOS 65c02 instructions' addressing modes that were not on the NMOS 6502:
Code: Select all
instruction op code
& addr mode (in hex) description
ADC (addr) 72 ADC absolute indirect
AND (addr) 32 AND absolute indirect
BIT addr,X 3C BIT absolute indexed
BIT ZP,X 34 BIT zero-page indexed
BIT # 89 BIT immediate
CMP (addr) D2 CMP absolute indirect
DEC A 3A DECrement accumulator (alternate mnemonic: DEA)
INC A 1A INCrement accumulator (alternate mnemonic: INA)
EOR (addr) 52 EOR absolute indirect
JMP (addr,X) 7C JMP absolute indexed indirect
LDA (addr) B2 LDA absolute indirect
ORA (addr) 12 ORA absolute indirect
SBC (addr) F2 SBC absolute indirect
STA (addr) 92 STA absolute indirect
Admittedly though, it is still poorly suited for a C compiler.
In spite of my raking the PIC16 over the coals, I have become somewhat comfortable with it because of experience and the macros I have developed for it. One of the backwards-thinking things is the instructions saying for example "If such-and-such is true, then
don't do the following." I have hidden that in the macros, like in the following routine which uses the macros but is also called by a macro so once it's in place, I don't have to keep seeing the ugly details. It's for displaying strings which could be in different pages of ROM:
Code: Select all
; DISP_ROM_STRING below is for displaying strings from the program memory pages containing the strings.
; It is called in the DISP_ROM_STR macro.
; Displaying will start where cursor position variable CURSOR_POS says, which is zero-based, meaning 0 is top line, left end.
; MIN_CURSOR_POS is not used.
; CURSOR_POS will not get incremented here; but a CHR$(254) (þ) will do SET_LCD_ADR to the beginning of the 2nd line.
; Start with the low program-memory address byte of the string's 1st char, minus 1, in W. This will go into TEMP_1 and be the
; index to keep fetching the next byte of the string, incrementing TEMP_1 each time, until a 00 byte is read.
; Start with high byte of string addr in TEMP_4.
; Typical usage would be MOVLW HIGH str_adr, MOVWF TEMP_4, MOVLW LOW (str_addr - 1), CALL DISP_ROM_STRING.
; The entry W value for the first string in the page will be 0, even though that first char starts at addr xx01.
; You will often want to call CLR_LCD first. Note that CLR_LCD takes 5ms. The DISP_ROM_STR macro provides that option.
DISP_ROM_STRING: ; Uses TEMP_1, 2, 4, & LOOP_CNT_3. Start with ADL of desired string, minus 1, in W.
MOVWF TEMP_1 ; The strings most often needed during signal generation should be in STR_TBL3,
; because shortness of program memory made me disable and enable interrupts in only
MOVF CURSOR_POS, W ; one place, and I put the comparisons in reverse order because the STR_TBL1 section
CALL SET_LCD_ADR ; has an additional (ADDLW H'FE') instruction. SET_LCD_ADR uses LCD_TEMP.
BEGIN ; Remember that writing to PCL makes PCLATH<4:0> get transferred to PCH.
MOVF TEMP_4, W ; See which 256-byte page the desired string table is in.
CASE
CASE_OF_ HIGH STR_TBL3 ; In the case of it being in string table 3:
COPY TEMP_4, TO, PCLATH ; We can't use the LOOK_UP macro here because of the MOVF / MOVLW difference.
MOVF TEMP_1, W ; Get the index into the strings page back in W.
CALL STR_TBL3 ; This is the PIC16 mickey-mouse lookup with RETLW's following the ADDWF PCL, F.
CLRF PCLATH ; PCLATh must be cleared before the jump assembled by the END_OF.
END_OF ; Now strings in STR_TBL3 will get interrupts enabled again sooner than others.
CASE_OF_ HIGH STR_TBL2 ; If we want the second string table, do this second part.
COPY TEMP_4, TO, PCLATH ; We can't use the LOOK_UP macro here because of the MOVF / MOVLW difference.
MOVF TEMP_1, W ; Get the index into the strings page back in W.
CALL STR_TBL2 ; This is the PIC16 mickey-mouse lookup with RETLW's following the ADDWF PCL, F.
CLRF PCLATH ; PCLATh must be cleared before the jump assembled by the END_OF.
END_OF
; CASE_OF_ HIGH STR_TBL1 ; Here, by default, we need the first string table (hence the commenting-out).
COPY TEMP_4, TO, PCLATH ; We can't use the LOOK_UP macro here because of the MOVF / MOVLW difference.
MOVF TEMP_1, W ; Get the index into the strings page back in W.
ADDLW H'FE' ; (This is because of the GOTO START at beginning of 256-byte page STR_TBL1 is in.)
CALL STR_TBL1 ; This is the PIC16 mickey-mouse lookup with RETLW's following the ADDWF PCL, F.
CLRF PCLATH ; PCLATh must be cleared before the jump assembled by the END_OF.
; END_OF_
END_CASE
ANDLW H'FF' ; Unfortunately RETLW in STR_TBLs doesn't affect flags, and CLRF clears Z; hence this line.
WHILE_NOT_ZERO ; If the byte fetched was non-0, we still have more of the string to display.
SUBLW D'254' ; See if it's CHR$(254) which is to tell it to go to the next line.
IF_EQ ; If it is, tell the LCD to go to addr $10, to skip
CALL SET10 ; the rest of the top line. (It also can't increment across the boundary automatically.)
ELSE_ ; Otherwise, SET_LCD_ADR uses LCD_TEMP.
SUBLW D'254' ; (get our original number back which we had before the destructive compare-to-254 above)
CALL WR_LCD_AUTO ; you can put it in the display without setting the address every time. Uses TEMP_2.
END_IF
INCF TEMP_1, F ; Get ready to check the next byte.
REPEAT
RETURN
;------------------
I have this kind of macros for the 65c02 as well in a section of my website starting at
http://wilsonminesco.com/StructureMacros/ .