PIC Microcontroller - Family Core Architectural Differences - PIC24 and DsPIC 16-bit Microcontrollers

PIC24 and DsPIC 16-bit Microcontrollers

In 2001, Microchip introduced the dsPIC series of chips, which entered mass production in late 2004. They are Microchip's first inherently 16-bit microcontrollers. PIC24 devices are designed as general purpose microcontrollers. dsPIC devices include digital signal processing capabilities in addition.

Although still similar to earlier PIC architectures, there are significant enhancements:

  • All registers are 16 bits wide
  • Data address space expanded to 64 Kbytes
  • First 2K is reserved for peripheral control registers
  • Data bank switching is not required unless RAM exceeds 62K
  • "f operand" direct addressing extended to 13 bits (8 Kbytes)
  • 16 W registers available for register-register operations.

(But operations on f operands always reference W0.)

  • Program counter is 22 bits (Bits 22:1; bit 0 is always 0)
  • Instructions are 24 bits wide
  • Instructions come in byte (B=1) and (16-bit) word (B=0) forms
  • Stack is in RAM (with W15 as stack pointer); there is no hardware stack
  • W14 is the frame pointer
  • Data stored in ROM may be accessed directly ("Program Space Visibility")
  • Interrupt vectors for different interrupt sources are supported.

Some features are:

  • hardware MAC (multiply–accumulate)
  • barrel shifting
  • bit reversal
  • (16×16)-bit single-cycle multiplication and other DSP operations
  • hardware divide assist (19 cycles for 16/32-bit divide)
  • hardware support for loop indexing
  • Direct memory access

dsPICs can be programmed in C using Microchip's C30 compiler which is a variant of GCC.

Instruction ROM is 24 bits wide. Software can access ROM in 16-bit words, where even words hold the least significant 16 bits of each instruction, and odd words hold the most significant 8 bits. The high half of odd words reads as zero. The program counter is 23 bits wide, but the least significant bit is always 0, so there are 22 modifiable bits.

Instructions come in 2 main varieties. One is like the classic PIC instructions, with an operation between W0 and a value in a specified f register (i.e. the first 8K of RAM), and a destination select bit selecting which is updated with the result. The W registers are memory-mapped. so the f operand may be any W register,

The other form, new to the PIC24, specifies 3 W register operands, 2 of which allow a 3-bit addressing mode specification:

PIC24 addressing modes
s operand d operand Description
ppp Reg Syntax qqq Reg Syntax
000 ssss Ws 000 dddd Wd Register direct
001 ssss 001 dddd Indirect
010 ssss 010 dddd Indirect with postdecrement
011 ssss 011 dddd Indirect with postincrement
100 ssss 100 dddd Indirect with pretdecrement
101 ssss 101 dddd Indirect with preincrement
11x ssss 11x dddd Indirect with register offset
11k kkkk #u5 (Unused, illegal) 5-bit unsigned immediate

The register offset addressing mode is only available to 2-operand instructions. 3-operand instructions use Ww as the second source operand, and use this encoding for an unsigned 5-bit immediate source. Note that the same Ww may be added to both Wd and Ws.

A few instructions are 2 words long. The second word is a NOP, which includes up to 16 bits of additional immediate operand.

PIC24 24-bit instruction set
2
3
2
2
2
1
2
0
1
9
1
8
1
7
1
6
1
5
1
4
1
3
1
2
1
1
1
0

9

8

7

6

5

4

3

2

1

0
Mnemonic C
?
Z
?
N
?
Description
0 0 0 0 opcode offset Control transfers
0 0 0 0 0 0 0 0 NOP No operation (& 2nd instruction word)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 n NOP Second word of absolute branch (bits 22:16)
0 0 0 0 0 0 0 0 n NOP Second word of DO instruction
0 0 0 0 0 0 0 1 0 op —0— a Computed control transfer (to 16-bit Wa)
0 0 0 0 0 0 0 1 0 0 0 —0— a CALL Ra Push PC, jump to Wa
0 0 0 0 0 0 0 1 0 0 1 —0— a RCALL Ra Push PC, jump to PC+2×Wa
0 0 0 0 0 0 0 1 0 1 0 —0— a GOTO Ra Jump to Wa
0 0 0 0 0 0 0 1 0 1 1 —0— a BRA Ra Jump to PC+2×Wa
0 0 0 0 0 0 1 0 n<15:1> 0 CALL addr23 Push PC, jump to absolute address
—0— 0 0 0 0 0 0 0 0 0 n<22:16>
0 0 0 0 0 0 1 1 (Reserved)
0 0 0 0 0 1 0 0 n 0 GOTO addr23 Jump to absolute address
—0— 0 0 0 0 0 0 0 0 0 n<22:16>
0 0 0 0 0 1 0 1 0 B k d RETLW #k,Wd Wn = #u10, pop PC
0 0 0 0 0 1 1 0 0 0 —0— RETURN pop PC
0 0 0 0 0 1 1 0 0 1 —0— RETFIE C Z N pop SR, PC
0 0 0 0 0 1 1 1 n RCALL address Push PC, PC += 2*s16
0 0 0 0 1 0 0 0 0 0 k DO #k, addr Zero-overhead loop; k+1 is repeat count, PC+2n last instruction
—0— n
0 0 0 0 1 0 0 0 0 0 k REPEAT #k Repeat next instruction k+1 times
0 0 0 0 1 0 0 0 n RCALL address Push PC, PC += 2*s16
0 0 0 0 1 0 1 (Reserved)
0 0 0 0 1 1 0 a n BRA Oa, addr If accumulator a overflowed, PC += 2*simm16
0 0 0 0 1 1 1 a n BRA Sa, addr If accumulator a saturated, PC += 2*simm16
0 opcode w B q d p s ALU operations: Wd ← OP(Ww,Ws)
0 0 0 1 0 w B q d p s SUBR Ww,Ws,Wd C Z N Wd ← Ws − Ww (Wd ← Ws + ~Ww + 1)
0 0 0 1 1 w B q d p s SUBBR Ww,Ws,Wd C Z N Wd ← Ws + ~Ww + C (Wd ← Ws − Ww − C̅)
0 0 1 0 k d MOV #k,Wd Wd ← #imm16
0 0 1 1 cond n Conditional branch to PC+2*n
0 0 1 1 0 0 0 0 n BRA OV,addr Branch if PSR.V is set
0 0 1 1 0 0 0 1 n BRA C,addr Branch if PSR.C is set
0 0 1 1 0 0 1 0 n BRA Z,addr Branch if PSR.Z is set
0 0 1 1 0 0 1 1 n BRA N,addr Branch if PSR.N is set
0 0 1 1 0 1 0 0 n BRA LE,addr Branch if PSR.Z, or PSR.N ≠ PSR.V
0 0 1 1 0 1 0 1 n BRA LT,addr Branch if PSR.N ≠ PSR.V
0 0 1 1 0 1 1 0 n BRA LEU,addr Branch if PSR.Z is set, or PSR.C is clear
0 0 1 1 0 1 1 1 n BRA addr Branch unconditionally
0 0 1 1 1 0 0 0 n BRA NOV,addr Branch if PSR.V is clear
0 0 1 1 1 0 0 1 n BRA NC,addr Branch if PSR.C is clear
0 0 1 1 1 0 1 0 n BRA NZ,addr Branch if PSR.Z is clear
0 0 1 1 1 0 1 1 n BRA NN,addr Branch if PSR.N is clear
0 0 1 1 1 1 0 0 n BRA GT,addr Branch if PSR.Z is clear, and PSR.N = PSR.V
0 0 1 1 1 1 0 1 n BRA GE,addr Branch if PSR.N = PSR.V
0 0 1 1 1 1 1 0 n BRA GTU,addr Branch if PSR.Z is clear, and PSR.C is set
0 0 1 1 1 1 1 1 n (Reserved)
0 opcode w B q d p s ALU operations: Wd ← OP(Ww,Ws)
0 1 0 0 0 w B q d p s ADD Ww,Ws,Wd C Z N Wd ← Ww + Ws
0 1 0 0 1 w B q d p s ADDC Ww,Ws,Wd C Z N Wd ← Ww + Ws + C
0 1 0 1 0 w B q d p s SUB Ww,Ws,Wd C Z N Wd ← Ww − Ws
0 1 0 1 1 w B q d p s SUBB Ww,Ws,Wd C Z N Wd ← Ww + ~Ws + C (Wd ← Ww − ~Ws − C̅)
0 1 1 0 0 w B q d p s AND Ww,Ws,Wd Z N Wd ← Ww & Ws, logical and
0 1 1 0 1 w B q d p s XOR Ww,Ws,Wd Z N Wd ← Ww ^ Ws, exclusive or
0 1 1 1 0 w B q d p s IOR Ww,Ws,Wd Z N Wd ← Ww | Ws, inclusive or
0 1 1 1 1 w B q d p s MOV Ws,Wd Z N Wd ← Ws (offset mode allowed)
1 0 0 0 0 f d MOV f,Wd Wd ← f
1 0 0 0 1 f s MOV Ws,f f ← Ws
1 0 0 1 0 k B k d k s MOV ,Wd Load with 10-bit signed offset
1 0 0 1 1 k B k d k s MOV Ws, Store with 10-bit signed offset
1 0 1 0 0 opcod b Z B 0 0 0 p s Bit operations on Ws
1 0 1 0 0 0 0 0 b 0 B 0 0 0 p s BSET #b,Ws Set bit b of Ws
1 0 1 0 0 0 0 1 b 0 B 0 0 0 p s BCLR #b,Ws Clear bit b of Ws
1 0 1 0 0 0 1 0 b 0 B 0 0 0 p s BTG #b,Ws Toggle bit b of Ws
1 0 1 0 0 0 1 1 b 0 0 0 0 0 p s BTST.C #b,Ws C Set PSR.C = bit b of Ws
1 0 1 0 0 0 1 1 b 1 0 0 0 0 p s BTST.Z #b,Ws Z Set PSR.Z to complement of bit b of Ws
1 0 1 0 0 1 0 0 b Z 0 0 0 0 p s BTSTS.z #b,Ws C/Z Bit test (into C or Z), then set
1 0 1 0 0 1 0 1 Z w 0 0 0 0 p s BTST.z Ww,Ws C/Z Test bit (dynamic)
1 0 1 0 0 1 1 0 b 0 0 0 0 0 p s BTSS #b,Ws Test bit b of Ws, skip if set
1 0 1 0 0 1 1 1 b 0 0 0 0 0 p s BTSS #b,Ws Test bit b of Ws, skip if clear
1 0 1 0 1 opcod b f Bit operations on f
1 0 1 0 1 0 0 0 b f b BSET f, #b Set bit b of f
1 0 1 0 1 0 0 1 b f BCLR.B #b,f Clear bit b of f
1 0 1 0 1 0 1 0 b f BTG.B #b,f Toggle bit b of f
1 0 1 0 1 0 1 1 b f BTST.B #b,f Z Test bit b of f
1 0 1 0 1 1 0 0 b f BTSTS.B #b,f Z Test bit b of f, then set
1 0 1 0 1 1 0 1 Z w 0 0 0 0 p s BSW.z Ws,Ww Copy PSW bit to bit Ww of Wb
1 0 1 0 1 1 1 0 b f BTSS #b,f Test bit b of f, skip if set
1 0 1 0 1 1 1 1 b f BTSC #b,f Test bit b of f, skip if clear
1 0 1 1 0 0 opcod B k d Register-immediate operations
1 0 1 1 0 0 0 0 0 B k d ADD #u10,Wd C N Z Wd ← Wd + imm10
1 0 1 1 0 0 0 0 1 B k d ADC #u10,Wd C N Z Wd ← Wd + imm10 + C
1 0 1 1 0 0 0 1 0 B k d SUB #u10,Wd C N Z Wd ← Wd − imm10
1 0 1 1 0 0 0 1 1 B k d SUBB #u10,Wd C N Z Wd ← Wd − imm10 − C̅
1 0 1 1 0 0 1 0 0 B k d AND #u10,Wd N Z Wd ← Wd & imm10
1 0 1 1 0 0 1 0 1 B k d XOR #u10,Wd N Z Wd ← Wd ^ imm10
1 0 1 1 0 0 1 1 0 B k d IOR #u10,Wd N Z Wd ← Wd | imm10
1 0 1 1 0 0 1 1 1 B k d MOV #u10,Wd Wd ← imm10
1 0 1 1 0 1 opcod B D f ALU operations: dest ← OP(f,W0)
1 0 1 1 0 1 0 0 0 B D f ADD f C N Z dest ← f + W0
1 0 1 1 0 1 0 0 1 B D f ADC f C N Z dest ← f + W0 + C
1 0 1 1 0 1 0 1 0 B D f SUB f C N Z dest ← f − W0
1 0 1 1 0 1 0 1 1 B D f SUBB f C N Z dest ← f − W0 + C̅
1 0 1 1 0 1 1 0 0 B D f AND f N Z dest ← f & W0
1 0 1 1 0 1 1 0 1 B D f XOR f N Z dest ← f ^ W0
1 0 1 1 0 1 1 1 0 B D f IOR f N Z dest ← f | W0
1 0 1 1 0 1 1 1 1 B 1 f MOV WREG,f dest ← W0
1 0 1 1 1 0 0 op w d 0 p s 16×16→32 multiplication
1 0 1 1 1 0 0 0 0 w d 0 p s MUL.UU Ww,Ws,Wd Wd+1:Wd ← Wb * Ws (unsigned)
1 0 1 1 1 0 0 0 1 w d 0 p s MUL.US Ww,Ws,Wd Wd+1:Wd ← Wb * Ws (Ws signed)
1 0 1 1 1 0 0 1 0 w d 0 p s MUL.SU Ww,Ws,Wd Wd+1:Wd ← Wb * Ws (Wb signed)
1 0 1 1 1 0 0 1 1 w d 0 p s MUL.SS Ww,Ws,Wd Wd+1:Wd ← Wb * Ws (signed)
1 0 1 1 1 0 1 op w d p s Program memory access
1 0 1 1 1 0 1 0 0 B qqq d p s TBLRDL ,Wd Wd ← PROGRAM (bits 15:0)
1 0 1 1 1 0 1 0 1 B qqq d p s TBLRDH ,Wd Wd ← PROGRAM (bit 23:16)
1 0 1 1 1 0 1 1 0 B qqq d p s TBLWTL Ws, PROGRAM ← Ws (bits 15:0)
1 0 1 1 1 0 1 1 1 B qqq d p s TBLWTH , PROGRAM ← Ws (bit 23:16)
1 0 1 1 1 1 0 0 0 B 0 f MUL f W3:W2 ← f * W0 (unsigned)
1 0 1 1 1 1 0 1 (Reserved)
1 0 1 1 1 1 1 0 0 0 000 d 0 p s MOV.D Ws,Wd Move register pair (source may be memory)
1 0 1 1 1 1 1 0 1 0 q d 000 s 0 MOV.D Ws,Wd Move register pair (dest may be memory)
1 0 1 1 1 1 1 1 (Reserved)
1 1 0 0 0 m A S x y i j a DSP MAC (dsPIC only)
1 1 0 0 1 Other DSP instructions (dsPIC only)
1 1 0 0 1 1 1 1 0 0 000 d p s FF1R Ws,Wd Find first one from right (lsb)
1 1 0 0 1 1 1 1 1 0 000 d p s FF1L Ws,Wd Find first one from left (msb)
1 1 0 1 0 0 opcod B q d p s Shift/rotate W register
1 1 0 1 0 0 0 0 0 B q d p s SL Ws,Wd C N Z Wd ← Ws << 1, shift left (into carry)
1 1 0 1 0 0 0 1 0 B q d p s LSR Ws,Wd C N Z Wd ← Ws >> 1, logical shift right
1 1 0 1 0 0 0 1 1 B q d p s ASR Ws,Wd C N Z Wd ← Ws >> 1, arithmetic shift right
1 1 0 1 0 0 1 0 0 B q d p s RLNC Ws,Wd N Z Wd ← Ws <<< 1, rotate left (no carry)
1 1 0 1 0 0 1 0 1 B q d p s RLC Ws,Wd C N Z C:Wd ← Ws:C << 1, rotate left through carry
1 1 0 1 0 0 1 1 0 B q d p s RRNC Ws,Wd N Z Wd ← Ws >>> 1, rotate right (no carry)
1 1 0 1 0 0 1 1 1 B q d p s RRC Ws,Wd C N Z Wd:C ← C:Ws >> 1, rotate right through carry
1 1 0 1 0 1 opcod B D f Shift/rotate f
1 1 0 1 0 1 0 0 0 B D f SL f C N Z dest ← f << 1, shift left (into carry)
1 1 0 1 0 1 0 1 0 B D f LSR f C N Z dest ← f >> 1, logical shift right
1 1 0 1 0 1 0 1 1 B D f ASR f C N Z dest ← f >> 1, arithmetic shift right
1 1 0 1 0 1 1 0 0 B D f RLNC f N Z dest ← f <<< 1, rotate left (no carry)
1 1 0 1 0 1 1 0 1 B D f RLC f C N Z C:dest ← f:C << 1, rotate left through carry
1 1 0 1 0 1 1 1 0 B D f RRNC f N Z dest ← f >>> 1, rotate right (no carry)
1 1 0 1 0 1 1 1 1 B D f RRC f C N Z dest:C ← C:f >> 1, rotate right through carry
1 1 0 1 1 0 0 0 U t v W 0 0 s 32/16 and 16/16 divide steps (prefix with REPEAT #17)
1 1 0 1 1 0 0 0 0 0000 v 0 0 0 s DIV.S Wv,Ws C N Z Divide step, W0 ← Wv/Ws, W1 ← remainder
1 1 0 1 1 0 0 0 0 t v 1 0 0 s DIV.SD Wv,Ws C N Z Divide step, W0 ← Wt:Wv/Ws, W1 ← remainder
1 1 0 1 1 0 0 0 1 0000 v 0 0 0 s DIV.U Wv,Ws C N Z Divide step, W0 ← Wv/Ws, W1 ← remainder
1 1 0 1 1 0 0 0 1 t v 1 0 0 s DIV.UD Wv,Ws C N Z Divide step, W0 ← Wt:Wv/Ws, W1 ← remainder
1 1 0 1 1 0 0 1 0 t 0 0 0 0 0 0 0 s DIVF Wt,Ws C N Z Divide step, W0 ← Wt:0/Ws, W1 ← remainder
1 1 0 1 1 0 1 (Reserved)
1 1 0 1 1 1 0 0 (Reserved)
1 1 0 1 1 1 0 0 0 w d 0 0 0 s SL Ww,Ws,Wd N Z Wd ← Wv << Ws
1 1 0 1 1 1 0 0 0 w d 1 0 0 k SL Ww,#u4,Wd N Z Wd ← Wv << imm4
1 1 0 1 1 1 1 0 0 w d 0 0 0 s LSR Ww,Ws,Wd N Z Wd ← Wv>> Ws, logical shift right
1 1 0 1 1 1 1 0 0 w d 1 0 0 k LSR Ww,#u4,Wd N Z Wd ← Wv>> imm4, logical shift right
1 1 0 1 1 1 1 0 1 w d 0 0 0 s ASR Ww,Ws,Wd N Z Wd ← Wv>> Ws, arithmetic shift right
1 1 0 1 1 1 1 0 1 w d 1 0 0 k ASR Wv,#u4,Wd N Z Wd ← Wv>> imm4, arithmetic shift right
1 1 0 1 1 1 1 1 0 0000 d p s FBCL Ws,Wd C Find permissible arithmetic normalization shift
1 1 1 0 0 0 0 0 0 0000 B 0 0 0 p s CP0 Ws C N Z Compare with zero, Ws − 0
1 1 1 0 0 0 0 1 0 w B 0 0 0 p s CP Ww,Ws C N Z Compare, Wb − Ws (Wb + ~Ws + 1)
1 1 1 0 0 0 0 1 1 w B 0 0 0 p s CPB Ww,Ws C N Z Compare with borrow, Wb + ~Ws + C (Wb − Ws − C̅)
1 1 1 0 0 0 1 0 0 B 0 f CP0 Ws C N Z Compare with zero, f − 0
1 1 1 0 0 0 1 1 0 B 0 f CP f C N Z Compare f, f − W0
1 1 1 0 0 0 1 1 1 B 0 f CPB f C N Z Compare f with borrow, f + ~W0 + C (f − W0 − C̅)
1 1 1 0 0 1 0 (Reserved)
1 1 1 0 0 1 1 0 0 w B 0 0 0 0 0 0 s CPSGT Ww,Ws Compare and skip if greater than (Wb > Ws, signed)
1 1 1 0 0 1 1 0 1 w B 0 0 0 0 0 0 s CPSLT Ww,Ws Compare and skip if less than (Wb < Ws, signed)
1 1 1 0 0 1 1 1 0 w B 0 0 0 0 0 0 s CPSNE Ww,Ws Compare and skip if not equal (Wb ≠ Ws)
1 1 1 0 0 1 1 1 1 w B 0 0 0 0 0 0 s CPSNE Ww,Ws Compare and skip if equal (Wb = Ws)
1 1 1 0 1 0 0 0 0 B q d p s INC Ws,Wd C N Z Wd ← Ws+1
1 1 1 0 1 0 0 0 1 B q d p s INC2 Ws,Wd C N Z Wd ← Ws+2
1 1 1 0 1 0 0 1 0 B q d p s DEC Ws,Wd C N Z Wd ← Ws−1
1 1 1 0 1 0 0 1 1 B q d p s DEC2 Ws,Wd C N Z Wd ← Ws−2
1 1 1 0 1 0 1 0 0 B q d p s NEG Ws,Wd C N Z Wd ← ~Ws+1
1 1 1 0 1 0 1 0 1 B q d p s COM Ws,Wd N Z Wd ← ~Ws
1 1 1 0 1 0 1 1 0 B q d 000 0000 CLR Wd Wd ← 0
1 1 1 0 1 0 1 1 1 B q d 000 0000 SETM Wd Wd ← ~0
1 1 1 0 1 1 0 0 0 B D f INC f C N Z dest ← f+1
1 1 1 0 1 1 0 0 1 B D f INC2 f C N Z dest ← f+2
1 1 1 0 1 1 0 1 0 B D f DEC f C N Z dest ← f−1
1 1 1 0 1 1 0 1 1 B D f DEC f C N Z dest ← f−2
1 1 1 0 1 1 1 0 0 B D f NEG f C N Z dest ← ~f+1
1 1 1 0 1 1 1 0 1 B D f COM f N Z dest ← ~f
1 1 1 0 1 1 1 1 0 B D f CLR f dest ← 0
1 1 1 0 1 1 1 1 1 B D f SETM f dest ← ~0
1 1 1 1 0 0 m A 1 x y i j opc DSP MPY/MAC/ED/EDAC (dsPIC only)
1 1 1 1 0 1 (Reserved)
1 1 1 1 1 0 0 0 f 0 PUSH f Push f on top of stack
1 1 1 1 1 0 0 1 f 0 POP f Pop f from top of stack
1 1 1 1 1 0 1 0 0 0 k LNK #u14 Push W14, W14 ← W15, W15 += u14
1 1 1 1 1 0 1 0 1 0 —0— ULNK W15 ← W14, pop W14
1 1 1 1 1 0 1 1 0 0 000 d p s SE Ws,Wd C N Z Wd ← sign_extend(Ws), copy bit 7 to bits 15:8
1 1 1 1 1 0 1 1 1 0 000 d p s ZE Ws,Wd 1 0 Z Wd ← zero_extend(Ws), clear bits 15:8
1 1 1 1 1 1 0 0 0 0 k DISI #u14 Disable interrupt for k+1 cycles
1 1 1 1 1 1 0 1 0 0 000 d 000 s EXCH Ws,Wd Swap contents of registers Ws, Wd
1 1 1 1 1 1 0 1 0 1 000 0000 000 s DAW.B Ws C Decimal adjust based on C, DC
1 1 1 1 1 1 0 1 1 B 000 0000 000 s SWAP Ws Swap halves of Ws
1 1 1 1 1 1 1 0 0 0 —0— RESET Software reset
1 1 1 1 1 1 1 0 0 1 0 —0— k PWRSAV #u1 Go into sleep or idle mode
1 1 1 1 1 1 1 0 0 1 1 —0— CLRWDT Clear watchdog timer
1 1 1 1 1 1 1 0 1 0 0 —0— POP.S Pop shadow registers (W0–3, part of PSR)
1 1 1 1 1 1 1 0 1 0 1 —0— PUSH.S Push shadow registers (W0–3, part of PSR)
1 1 1 1 1 1 1 0 1 1 (Reserved)
1 1 1 1 1 1 1 1 NOPR No operation (version #2)

Read more about this topic:  PIC Microcontroller, Family Core Architectural Differences