mem.c - Read/write the PIC’s program memory.¶
 
#include "pic24_util.h"
typedef short          Word16;
typedef unsigned short UWord16;
typedef long           Word32;
typedef unsigned long  UWord32;
 
Write these in C so that can we use the __PIC24H__, __PIC24F__ defines.
void WriteMem(UWord16 val) {
  UNUSED(val);
  asm("mov W0, NVMCON");
  __builtin_write_NVM();
 
Wait for write end.
  asm("1: btsc NVMCON, #15");
  asm("bra 1b");
}
#if (defined(__PIC24E__) || defined(__dsPIC33E__))
void WriteMem2(UWord16 addrhi, UWord16 addrlo, UWord16 val) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  UNUSED(val);
 
Init Pointer to page to be erased.
  asm("mov W0, NVMADRU");
Init Pointer to offset to be erased.
  asm("mov W1, NVMADR");
  asm("mov W2, NVMCON");
  //__builtin_write_NVM();
  asm("disi #06");
  asm("mov #0x55, W0");
  asm("mov W0, NVMKEY");
  asm("mov #0xAA, W0");
  asm("mov W0, NVMKEY");
  asm("bset NVMCON, #15");
  asm("nop");
  asm("nop");
 
Wait for write end.
  asm("1: btsc NVMCON, #15");
  asm(" bra 1b");
}
#endif
//_LoadAddr:  ;W0=NVMADRU,W1=NVMADR - no return values
void LoadAddr(UWord16 nvmadru, UWord16 nvmadr) {
  UNUSED(nvmadru);
  UNUSED(nvmadr);
  asm("mov W0, TBLPAG");
  asm("mov W1, W1");
}
//_WriteLatch: ;W0=TBLPAG,W1=Wn,W2=WordHi,W3=WordLo - no return values
void WriteLatch(UWord16 addrhi,UWord16 addrlo, UWord16 wordhi, UWord16 wordlo) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  UNUSED(wordhi);
  UNUSED(wordlo);
  asm("mov W0, TBLPAG");
  asm("tblwtl W3, [W1]");
  asm("tblwth W2, [W1]");
}
#if (defined(__PIC24E__) || defined(__dsPIC33E__))
//_LoadTwoWords: ;W0=TBLPAG,W1=Wn,W2=WordHi,W3=WordLo W4=Word2Hi,W5=Word2Lo
//W0,W1 not really used
void LoadTwoWords(UWord16 addrhi, UWord16 addrlo, UWord16 wordhi, UWord16 wordlo, UWord16 word2hi, UWord16 word2lo) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  UNUSED(wordhi);
  UNUSED(wordlo);
  UNUSED(word2hi);
  UNUSED(word2lo);
  asm("mov #0xFA,W0");
  asm("mov W0, TBLPAG");
  asm("mov #0, W1");
  asm("tblwtl W3, [W1]");
  asm("tblwth W2, [W1++]");
  asm("tblwtl W5, [W1]");
  asm("tblwth W4, [W1++]");
}
#endif
//_ReadLatch: ;W0=TBLPAG,W1=Wn - data in W1:W0
UWord32 ReadLatch(UWord16 addrhi, UWord16 addrlo) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  asm("mov W0, TBLPAG");
  asm("tblrdl [W1], W0");
  asm("tblrdh [W1], W1");
This gives a compiler warning because not explicitly returning a value from the function, but since this is assembly, do not know how to prevent warning. The function is correct, since W1:W0 being used to return the tblrdl,tblrdh. Could write less efficient code and use a temporary UWord32.
Attempts to suppress following warning:
bootloaderpic24_dspic33_bootloader.Xmem.c:110:1: warning: control reaches end of non-void function [-Wreturn-type]
#pragma GCC diagnostic warning “-Wreturn-type” works. However, if I later re-enable it at any point in this file with a #pragma GCC diagnostic warning “-Wreturn-type”, then the warning still appears. So, leave the warning for now, rather than possibly hide future warnings. See https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html for more information.
}
void ResetDevice(void) {
#if (defined(__PIC24E__) || defined(__dsPIC33E__))
  asm("goto 0x1300");
#else
  asm("goto 0x0E00");
#endif
}
void ResetDeviceasPOR(void) {
  _POR = 1;
  ResetDevice();
}
#if (defined(__PIC24E__) || defined(__dsPIC33E__))
void Erase(UWord16 addrhi, UWord16 addrlo, UWord16 val) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  UNUSED(val);
  asm("mov W2,NVMCON");
 
Init Pointer to page to be erased.
  asm("mov W0, NVMADRU");
Init Pointer to offset to be erased.
  asm("mov W1, NVMADR");
  //__builtin_write_NVM();
  asm("disi #06");
  asm("mov #0x55, W0");
  asm("mov W0, NVMKEY");
  asm("mov #0xAA, W0");
  asm("mov W0, NVMKEY");
  asm("bset NVMCON, #15");
  asm("nop");
  asm("nop");
 
Wait for write end.
  asm("1: btsc NVMCON, #15");
  asm(" bra 1b");
}
#else
//_Erase:
void Erase(UWord16 addrhi, UWord16 addrlo, UWord16 val) {
  UNUSED(addrhi);
  UNUSED(addrlo);
  UNUSED(val);
  asm("push TBLPAG");
  asm("mov W2, NVMCON");
 
Init Pointer to page to be erased.
  asm("mov W0, TBLPAG");
Dummy write to select the row.
  asm("tblwtl W1,[W1]");
  __builtin_write_NVM();
 
Wait for write end.
  asm("1: btsc NVMCON, #15");
  asm(" bra 1b");
  asm("pop TBLPAG");
}
#endif