--- /dev/null
+CFLAGS= -g -fstack-protector-all -Wall -pedantic -std=gnu99 -fPIC -D_GNU_SOURCE
+LDFLAGS= $(CFLAGS)
+
+SRC=serial.c log.c boot.c protocol.c devices.c memory.c
+
+OBJS=$(SRC:%.c=%.o)
+
+all: boot test
+
+test: test.o
+
+boot: $(OBJS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+ rm -f $(OBJS) boot test
+
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "serial.h"
+#include "protocol.h"
+#include "devices.h"
+#include "memory.h"
+
+#define BAUD_RATE 19200
+#define PORT_NAME "/dev/ttyUSB0"
+
+
+void usage(const char * name)
+{
+ loge("Usage: %s [-b baud] [-p port] [-i] [-v] {file.hex}\n", name);
+ loge("-b baud Set baudrate (default: %d)\n", BAUD_RATE);
+ loge("-p port Set serial port (default: %s)\n", PORT_NAME);
+ loge("-i ID Only mode.\n");
+ loge("-v Verify after write\n");
+}
+
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+int bitmask(int value)
+{
+ int out = 0;
+ if (value >= (1<<1)) out |= 1;
+ if (value >= (1<<2)) out |= 1<<1;
+ if (value >= (1<<3)) out |= 1<<2;
+ if (value >= (1<<4)) out |= 1<<3;
+ if (value >= (1<<5)) out |= 1<<4;
+ if (value >= (1<<6)) out |= 1<<5;
+ if (value >= (1<<7)) out |= 1<<6;
+ if (value >= (1<<8)) out |= 1<<7;
+ if (value >= (1<<9)) out |= 1<<8;
+ if (value >= (1<<10)) out |= 1<<9;
+
+ return out;
+}
+/*
+ * This routine writes a memory plan out to the device
+ */
+int update_mem(port_t * pt, const devid_t * dev, uint16_t maxmem, mem_t * ram, int verify)
+{
+ mem_t * block = ram;
+ uint8_t buff[1024]; // scratch space
+
+ for (block=ram; block != NULL; block=block->next) {
+ int bstart = block->start / 2;
+
+ /* skip config words, we cant write them anyway */
+ if (bstart >= 0x8000) {
+ logd("UpdateMem: skip config block @ %04x", bstart);
+ continue;
+ }
+
+
+ uint8_t * p = block->bytes;
+ int left = block->len;
+ uint16_t addr = bstart;
+ int rowlen = dev->rowsize * 2;
+ logd("UpdateMem: new block %d bytes @ %04x", block->len, bstart);
+
+ while (left > 0) {
+ int off = 0;
+ int len = rowlen;
+
+ memset(buff, 255, sizeof(buff));
+ if (addr == bstart) {
+ /* first row, align the start */
+ if (addr % dev->rowsize != 0) {
+ addr &= ~bitmask(dev->rowsize);
+ off = (bstart - addr) * 2;
+ len -= off;
+ logd("UpdateMem: realigning %04X to %04X", bstart, addr);
+ }
+ }
+
+ len = MIN(len, left);
+
+ logd("UpdateMem: Preparing %d bytes @ %04X", len, addr);
+
+ /* partial row write, read first */
+ if (off != 0 || len < rowlen) {
+ logd("UpdateMem: Read %d words @ %04x", dev->rowsize, addr);
+ if (loader_readmem(pt, addr, buff, dev->rowsize)) {
+ loge("UpdateMem: Aborting on failed read");
+ return 1;
+ }
+ print_memory(addr, buff, dev->rowsize);
+ }
+
+ /* update with new values */
+ memcpy(&buff[off], p, len);
+
+ /* write the row */
+ logd("UpdateMem: Writing %d words @ %04x", dev->rowsize, addr);
+ print_memory(addr, buff, dev->rowsize);
+ if (loader_writemem(pt, addr, buff, dev->rowsize)) {
+ loge("UpdateMem: Aborting on failed write");
+ return 1;
+ }
+
+ if (verify) {
+ uint8_t again[1024];
+ sleep(1);
+ logd("UpdateMem: Verify %d words @ %04x", dev->rowsize, addr);
+ if (loader_readmem(pt, addr, again, dev->rowsize)) {
+ loge("UpdateMem: Aborting on failed read");
+ return 1;
+ }
+ print_memory(addr, again, dev->rowsize);
+ for (int i=0; i<rowlen; i++) {
+ if (again[i] != buff[i]) {
+ loge("UpdateMem: Verify failed on block 0x%04X", addr);
+ return 1;
+ }
+ }
+ }
+
+ /* shuffle along */
+ left -= len;
+ p += len;
+ addr += dev->rowsize;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ char * port = NULL;
+ int baud = BAUD_RATE;
+ int verify = 0;
+ int idonly = 0;
+
+ while ((opt=getopt(argc, argv, "h?b:p:ivd"))!=-1) {
+ switch (opt) {
+ case 'b':
+ baud = atoi(optarg);
+ break;
+ case 'p':
+ if (port) free(port);
+ port = strdup(optarg);
+ break;
+ case 'v':
+ verify=1;
+ break;
+ case 'i':
+ idonly=1;
+ break;
+ case 'd':
+ debug++;
+ break;
+ case 'h':
+ case '?':
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (port == NULL) port = PORT_NAME;
+
+ if (!idonly && optind >= argc) {
+ loge("Error: missing hexfile");
+ return 1;
+ }
+
+ mem_t * ram = NULL;
+
+ if (!idonly) {
+ FILE * fd = NULL;
+ if ((fd = fopen(argv[optind], "r"))==NULL) {
+ loge("Error opening %s: %s", argv[optind], strerror(errno));
+ return 1;
+ }
+ ram = load_ihex(fd);
+ fclose(fd);
+
+ logd("Memory Summary :-");
+ list_mem(ram);
+ }
+
+ logd("open serial port %s at %d baud", port, baud);
+ port_t * pt = serial_open(port, baud);
+ if (pt == NULL) return 1;
+
+ uint16_t maxmem;
+ uint16_t devid;
+ if (loader_connect(pt, &maxmem, &devid)) {
+ return 1;
+ }
+
+ const devid_t * dev = devid_to_info(devid);
+
+ if (idonly) {
+ logi("Device ID: %04X", devid);
+ logi(" Free Mem: %d words available", maxmem);
+ if (dev != NULL) {
+ logi(" Dev Name: %s", dev->name );
+ logi(" Max Mem: %d", dev->memsize );
+ }
+
+ return 0;
+ }
+ if (dev) logd("Device Name: %s", dev->name);
+
+ /* check that the selected program will fit on this device */
+ if (makesafe_mem(&ram, maxmem)) {
+ serial_close(pt);
+ return 1;
+ }
+ logd("After re-organisation");
+ list_mem(ram);
+
+ /* now write the updated memory plan to the device */
+ if (!update_mem(pt, dev, maxmem, ram, verify)) {
+ if (verify)
+ logi("Device Write (and Verify) Complete");
+ else
+ logi("Device Write Complete");
+ }
+
+ /* finished */
+ serial_close(pt);
+ logd("done.");
+ return 0;
+
+}
--- /dev/null
+#include <string.h>
+#include <stdint.h>
+#include "devices.h"
+
+/* list of devices we know the ID of */
+static const devid_t device_list[] = {
+ /* { devid, devmask, name, memwords, rowsize } */
+ { 0x3020, 0x3FFF, "PIC16F1454", 0x2000, 32 },
+ { 0x3024, 0x3FFF, "PIC16LF1454", 0x2000, 32 },
+ { 0x3021, 0x3FFF, "PIC16F1455", 0x2000, 32 },
+ { 0x3025, 0x3FFF, "PIC16LF1455", 0x2000, 32 },
+ { 0x3023, 0x3FFF, "PIC16F1459", 0x2000, 32 },
+ { 0x3027, 0x3FFF, "PIC16LF1459", 0x2000, 32 },
+ { 0x1480, 0x3FE0, "PIC16F1847", 0x2000, 32 },
+ { 0x14A0, 0x3FE0, "PIC16LF1847", 0x2000, 32 },
+ { 0x1B80, 0x3FE0, "PIC12F1840", 0x1000, 32 },
+ { 0x1BC0, 0x3FE0, "PIC12LF1840", 0x1000, 32 },
+ { 0, 0, NULL, 0, 0}
+};
+
+const char *devidtoname(uint16_t devid)
+{
+ const devid_t *d = device_list;
+ while (d->name != NULL) {
+ if ((devid & d->mask) == d->id)
+ return d->name;
+ d++;
+ }
+ return "Unknown";
+}
+
+const devid_t * devid_to_info(uint16_t devid)
+{
+ const devid_t *d = device_list;
+ while (d->name != NULL) {
+ if ((devid & d->mask) == d->id)
+ return d;
+ d++;
+ }
+ return NULL;
+}
--- /dev/null
+#ifndef DEVICE_INFO_H
+#define DEVICE_INFO_H
+
+typedef struct device_info {
+ uint16_t id;
+ uint16_t mask;
+ const char *name;
+ uint16_t memsize;
+ uint8_t rowsize;
+} devid_t;
+
+const char *devidtoname(uint16_t devid);
+const devid_t * devid_to_info(uint16_t devid);
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "log.h"
+
+int debug = 0;
+
+void logit(int type, const char * format, ...)
+{
+ va_list va;
+ va_start(va, format);
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ struct tm * now_tm = localtime(&(now.tv_sec));
+
+ if (type == LOG_INFO) {
+ vfprintf(stdout, format, va);
+ fprintf(stdout, "\n");
+ } else
+ if (type == LOG_DEBUG) {
+ if (debug > 0) {
+ fprintf(stderr, "%02d:%02d:%02d.%03d ", now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, (int)(now.tv_usec / 1000));
+ vfprintf(stderr, format, va);
+ fprintf(stderr, "\n");
+ }
+ } else {
+ vfprintf(stderr, format, va);
+ fprintf(stderr, "\n");
+ }
+
+ va_end(va);
+}
--- /dev/null
+/* log.c */
+
+enum log_types {
+ LOG_DEBUG, LOG_ERROR, LOG_INFO
+};
+
+#define logd(...) logit(LOG_DEBUG, __VA_ARGS__)
+#define loge(...) logit(LOG_ERROR, __VA_ARGS__)
+#define logi(...) logit(LOG_INFO, __VA_ARGS__)
+
+extern int debug;
+
+void logit(int type, const char *format, ...);
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "memory.h"
+#include "serial.h"
+#include "devices.h"
+#include "protocol.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+/* return 0 for end of file. -1 for error */
+int parse_ihex16(const char *line, uint8_t *bytes, int *addr, int *code)
+{
+ unsigned int sum, len, cksum;
+ unsigned int laddr, lcode;
+ int i;
+ const char *p;
+
+ if (line[0] != ':') return -1;
+ if (strlen(line) < 11) return -1;
+ p = &line[1];
+ if (!sscanf(p, "%02x", &len)) return -1;
+ p+=2;
+ if (strlen(line) < (11 + (len * 2))) return -1;
+ if (!sscanf(p, "%04x", &laddr)) return -1;
+ p += 4;
+ *addr = laddr; // little endian address record
+ if (!sscanf(p, "%02x", &lcode)) return -1;
+ p+=2;
+ *code = lcode & 0xFF;
+
+ /* end of file record */
+ if (*code == 1) return 0;
+
+ sum = (len & 0xFF) + ((*addr >> 8) & 0xFF) + (*addr & 0xFF) + (*code & 0xFF);
+
+ i = 0;
+ while (i < len) {
+ unsigned int byte;
+ /* files are little-endian */
+ if (!sscanf(p, "%02x", &byte)) return -1;
+ bytes[i+1] = byte & 0xFF;
+ sum += byte & 0xFF;
+ p += 2;
+
+ if (!sscanf(p, "%02x", &byte)) return -1;
+ bytes[i] = byte & 0xFF;
+ sum += byte & 0xFF;
+ i += 2;
+ p += 2;
+ }
+ if (!sscanf(p, "%02x", &cksum)) return -1;
+ if ( ((sum & 0xFF) + (cksum & 0xFF)) & 0xFF ) return -1;
+ return len;
+}
+
+static void mem_add(mem_t **head, uint32_t start, uint8_t * bytes, int len)
+{
+ /* look for an existing block this overlaps/adjoins */
+ mem_t * block = *head;
+ uint32_t end = start + len;
+
+ for(block = *head; block!=NULL; block=block->next) {
+ int bend = block->start + block->len;
+ /* before and not touching */
+ if (start < block->start && end+1 < block->start) continue;
+ /* after and not touching */
+ if (start > bend+1) continue;
+
+ /* therefore it at least touches */
+
+ /* starts before or on old block */
+ if (start <= block->start) {
+ int pre=0, lap=0, post=0;
+ pre = block->start - start; // bytes before the old block
+ lap = len - pre; // bytes overlapping, from start
+ if (lap > block->len) {
+ post = lap - block->len;
+ lap = block->len;
+ }
+ int newsize = block->len + pre + post;
+ uint8_t * newbytes = malloc(newsize);
+ memcpy(&newbytes[pre], block->bytes, block->len);
+ memcpy(newbytes, bytes, len);
+ free(block->bytes);
+ block->bytes = newbytes;
+ block->len = newsize;
+ block->start -= pre;
+ } else {
+ /* starts part way down / at end */
+ int pre=0, /*lap=0, */ post=0;
+ pre = start - block->start; // gap from start
+ //lap = MIN(block->len - pre, len);
+ if (end > bend) post = end - bend;
+ int newsize = block->len + post;
+ uint8_t * newbytes = malloc(newsize);
+ memcpy(newbytes, block->bytes, block->len);
+ memcpy(&newbytes[pre], bytes, len);
+ block->bytes = newbytes;
+ block->len = newsize;
+ }
+ return;
+ }
+
+ block = calloc(1, sizeof(mem_t));
+ block->start = start;
+ block->len = len;
+ block->bytes = malloc(len);
+ memcpy(block->bytes, bytes, len);
+ block->next = *head;
+ *head = block;
+}
+
+mem_t * load_ihex(FILE *in)
+{
+ uint32_t addrh = 0;
+
+ char buff[1024];
+
+ mem_t * ram = NULL;
+
+ while (!feof(in) && fgets(buff, sizeof(buff), in)!=NULL) {
+ if (buff[0] == '#') continue;
+
+ unsigned char bytes[80];
+ int len, addr, code;
+
+ if ((len=parse_ihex16(buff, bytes, &addr, &code)) <= 0) {
+ if (len < 0) loge("LoadIHEX: Bad line: %s\n", buff);
+ continue;
+ }
+
+ if (code == 4) {
+ addrh = ((bytes[0] << 8) | bytes[1]) << 16;
+ logd("LoadIHEX: Setting high addr 0x%02X%02X", bytes[0], bytes[1]);
+ } else
+ if (code == 1) {
+ /* end of file marker */
+ break;
+ } else
+ if (code == 0) {
+ /* normal code block */
+ uint32_t fulladdr = addrh | addr;
+ mem_add(&ram, fulladdr, bytes, len);
+ }
+ }
+ return ram;
+}
+
+/* summary of the memory blocks in this list */
+void list_mem(const mem_t * head)
+{
+ const mem_t *p = head;
+ while (p!=NULL) {
+ logd("%6X : %d bytes", p->start, p->len);
+ p = p->next;
+ }
+}
+
+/* check that the program will fit */
+int validate_mem(mem_t * head, uint16_t maxmem)
+{
+ if (head == NULL) {
+ loge("MemValidate: No program!");
+ return 1;
+ }
+
+ mem_t * p;
+ int used = 0;
+
+ /* test that all the memory blocks will fit */
+ for (p=head; p!=NULL; p=p->next) {
+ /* just ignore config bytes, we cant write them anyway */
+ if (p->start / 2 >= 0x8000) continue;
+
+ used += p->len / 2;
+
+ if (p->start / 2 >= maxmem || (p->start+p->len)/2 >= maxmem) {
+ loge("MemValidate: Program too large, overlaps bootloader.");
+ return 1;
+ }
+ }
+
+ logd("MemValidate: Used %d of %d leaving %d free.", used, maxmem, maxmem-used);
+
+ return 0;
+}
+
+/* reorganise bytes to work with the boot loader */
+int makesafe_mem(mem_t **head, uint16_t maxmem)
+{
+ /* it must fit safely first */
+ if (validate_mem(*head, maxmem)) return 1;
+
+ mem_t * new = malloc(sizeof(mem_t));
+ new->start = maxmem * 2;
+ new->len = 8;
+ new->bytes = malloc(8);
+ memset(new->bytes, 255, 8);
+
+ int found = 0;
+ /* find the code that goes in words 0-3 and move it */
+ mem_t * p = NULL;
+ for (p = *head; p!=NULL; p=p->next) {
+ if (p->start >= 0 && p->start <= 7) {
+ int pre = p->start;
+ int lap = MIN(8-pre, p->len);
+ memcpy(&new->bytes[pre], p->bytes, lap);
+ p->start += lap;
+ p->len -= lap;
+ memmove(p->bytes, &p->bytes[lap], p->len);
+ found++;
+ }
+ }
+
+ if (!found) {
+ loge("MakeSafeMem: Could not find start vector");
+ free(new);
+ return 1;
+ }
+
+ /* check that there is something sane in here
+ * Warning: this is very enhanced-midrange dependant */
+ found = 0;
+ uint8_t * m = new->bytes;
+ uint16_t lath = 0;
+ for (int i=0; i<4; i++) {
+ uint16_t in = (m[0] << 8) | m[1];
+ if ((in & 0x3F80) == 0x3180) { // MOVLP
+ lath = in & 0x007F;
+ logd("MakeSafeMem: 0x%04X MOVLP 0x%02X", i, lath);
+ }else
+ if ((in & 0x3800) == 0x2800) { // GOTO
+ uint16_t addr = in & 0x07FF;
+ addr |= lath << 8;
+ logd("MakeSafeMem: 0x%04X GOTO 0x%02X", i, addr);
+
+ if ( addr < 4) {
+ // an absolute goto within the reset vector
+ // this is silly and wrong, replace with NOP
+ logd("MakeSafeMem: Rewriting bad 'GOTO 0x%02X' to NOP", addr);
+ m[0] = 0;
+ m[1] = 0;
+ } else {
+ // there is a sane GOTO, hurrah
+ found = 1;
+ }
+ }
+ m += 2;
+ }
+
+ if (!found) {
+ loge("Start Vector did not contain a GOTO");
+ free(new);
+ return 1;
+ }
+
+ new->next = *head;
+ *head = new;
+
+ return 0;
+}
--- /dev/null
+#ifndef MEMORY_BLOCK_H
+#define MEMORY_BLOCK_H
+
+typedef struct memory {
+ uint32_t start;
+ uint16_t len;
+ uint8_t * bytes;
+ struct memory * next;
+} mem_t;
+
+mem_t *load_ihex(FILE *in);
+void list_mem(const mem_t * head);
+int validate_mem(mem_t * head, uint16_t maxmem);
+int makesafe_mem(mem_t **head, uint16_t maxmem);
+
+
+
+
+
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "serial.h"
+#include "protocol.h"
+
+static uint8_t checksum(uint8_t * buff, int len)
+{
+ int sum = 0;
+ int i;
+
+ for (i=0;i<len;i++) sum += buff[i];
+ return sum & 0xFF;
+}
+
+void print_memory(uint16_t addr, const unsigned char * buff, int words)
+{
+ int len = (words * 5) + 16;
+ char * line = malloc(len);
+ char * out = line;
+ out += snprintf(out, len-strlen(line), "Mem %04X: ", addr);
+
+ const unsigned char *p = &buff[0];
+ for (int i=0; i<words; i++) {
+ out += snprintf(out, len-strlen(line), "%02X%02X ", p[0], p[1] );
+ p+=2;
+ }
+ logd(line);
+ free(line);
+}
+
+void dumpbuff(const unsigned char * buff, int charlen)
+{
+ int len = (charlen * 3) + 16;
+ char * line = malloc(len);
+ char * out = line;
+ out += snprintf(out, len-strlen(line), "Dump: ");
+
+ const unsigned char *p = &buff[0];
+ for (int i=0; i<charlen; i++) {
+ out += snprintf(out, len-strlen(line), "%02X ", p[0] );
+ p++;
+ }
+ logd(line);
+ free(line);
+}
+
+int loader_readmem(port_t * pt, uint16_t addr, uint8_t * memory, int words)
+{
+ int len = (words * 2) + 4;
+ unsigned char * buff = malloc(len);
+
+ /* request to read memory block */
+ buff[0] = 'R';
+ buff[1] = addr >> 8;
+ buff[2] = addr & 0xFF;
+ buff[3] = checksum(buff, 3);
+
+ int ret = serial_write(pt, buff, 4);
+ if (ret <= 0) return 1;
+
+ bzero(buff, len);
+
+ /* read the response */
+ if (serial_read(pt, buff, 1)<=0) return 1;
+
+ if (buff[0] == 'E') {
+ loge("ReadMem %04X: Loader gave error", addr);
+ return 2;
+ }
+
+ if (buff[0] != 'R') {
+ loge("ReadMem %04X: Unknown response to read 0x%02X '%c'", addr, buff[0], buff[0]);
+ return 3;
+ }
+
+ /* now read the address, and check it matches */
+ ret = serial_read(pt, &buff[1], len-1);
+ if (ret < 1) {
+ loge("ReadMem %04X: Error read response", addr);
+ return 4;
+ }
+ if (ret < len-1) {
+ loge("ReadMem %04X: Short read %d of %d", addr, ret, len-1);
+ return 5;
+ }
+
+ int sum = checksum(buff, len-1);
+ if ((sum & 0xFF) != buff[len-1]) {
+ loge("ReadMem %04X: Bad checksum. %02X != %02X", addr, sum & 0xFF, buff[len-1]);
+ return 6;
+ }
+
+ uint16_t realaddr = (buff[1]<<8) | buff[2];
+ if (realaddr != addr) {
+ loge("ReadMem %04X: Actual Address %04X", addr, realaddr);
+ return 7;
+ }
+ logd("ReadMem %04X: Read Successful", realaddr);
+
+ memcpy(memory, &buff[3], (words * 2));
+ free(buff);
+
+ return 0;
+}
+
+
+int loader_writemem(port_t * pt, uint16_t addr, uint8_t * memory, int words)
+{
+ int len = (words * 2) + 4;
+ uint8_t * buff = malloc((words * 2) + 4);
+
+ /* request to read memory block */
+ buff[0] = 'W';
+ buff[1] = addr >> 8;
+ buff[2] = addr & 0xFF;
+
+ unsigned char * p = memory;
+ unsigned char * q = &buff[3];
+ for (int i=0; i<words; i++) {
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ *q = checksum(buff, len-1) & 0xFF;
+
+ logd("WriteMem %04X: Sending Write request", addr);
+ int ret = serial_write(pt, buff, len);
+ if (ret <= 0) { free(buff); return 1; }
+
+ logd("WriteMem %04X: Awaiting Write confirmation", addr);
+ /* read the response */
+ if (serial_read(pt, buff, 1)<=0) { free(buff); return 1; }
+
+ if (buff[0] == 'E') {
+ loge("WriteMem %04X: Bootloader gave an error", addr);
+ free(buff);
+ return 2;
+ }
+
+ if (buff[0] != 'W') {
+ loge("WriteMem %04X: unknown reponse '%c'", addr, buff[0]);
+ free(buff);
+ return 3;
+ }
+
+ /* now read the address, and check it matches */
+ ret = serial_read(pt, &buff[1], 3);
+ if (ret < 3) {
+ loge("WriteMem %04X: Error reading rest of response %d of %d", addr, ret, 3);
+ free(buff);
+ return 4;
+ }
+
+ uint16_t realaddr = (buff[1]<<8) | buff[2];
+ if (realaddr != addr) {
+ loge("WriteMem %04X: Actual location %04X", addr, realaddr);
+ free(buff);
+ return 5;
+ }
+ int sum = checksum(buff, 3);
+
+ if ((sum & 0xFF) != buff[3]) {
+ loge("WriteMem %04X: Bad checksum on confirmation. %02X != %02X", addr, sum & 0xFF, buff[3]);
+ dumpbuff(buff, 4);
+ free(buff);
+ return 8;
+ }
+
+ logd("WriteMem %04X: Write confirmed.", realaddr);
+ free(buff);
+
+ return 0;
+}
+
+/*
+ * Connect to the bootloader
+ * read the start of bootloader address
+ */
+int loader_connect(port_t * pt, uint16_t *maxmem, uint16_t *devid)
+{
+ if (pt == NULL) return 1;
+
+ logd("Connect: Assert break and wait for acknowledgement");
+ serial_break(pt, 1);
+
+ unsigned char buff[10];
+ int bootload = 0;
+ int ret;
+
+ logi("Please reset the device to enter bootloader mode");
+
+ while ((ret=serial_read(pt, buff, 1))> 0) {
+ if (buff[0] == 06) {
+ break;
+ } else {
+ logd("Connect: Want ESC (0x06) got 0x%02X ret=%d", buff[0], ret);
+ usleep(100000);
+ }
+ }
+
+ if (ret <= 0) {
+ if (ret == 0)
+ loge("Connect: Serial port closed");
+ else
+ loge("Connect: read error: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Next we should see 'B' 'L' */
+ while ((ret=serial_read(pt, &buff[1], 2))> 0) {
+ if (buff[1] == 'B' && buff[2] == 'L') {
+ bootload = 1;
+ break;
+ } else {
+ logd("Connect: Want 'BL' got '%c%c' ret=%d", buff[1], buff[2], ret);
+ }
+ bzero(buff,3);
+ }
+
+ if (ret <= 0) {
+ if (ret == 0)
+ loge("Connect: Serial port closed");
+ else
+ loge("Connect: read error: %s", strerror(errno));
+ return 1;
+ }
+
+ /* turn break off now we are in bootloader mode */
+ serial_break(pt, 0);
+
+ if (!bootload) {
+ serial_close(pt);
+ loge("Connect: Could not find bootloader");
+ return 1;
+ }
+
+ logd("Connect: Release break. Read memory size.");
+
+ /* now read the bootloaders location, and thus mem size */
+ ret=serial_read(pt, &buff[3], 5);
+
+ if (ret < 3) {
+ if (ret == 0)
+ loge("Connect: Serial port closed");
+ else
+ loge("Connect: read error: %s", strerror(errno));
+ return 1;
+ }
+
+ if (buff[7] != (checksum(buff,7) & 0xFF)) {
+ loge("Connect: Bad checksum");
+ return 1;
+ }
+
+ *devid = (buff[3] << 8) | buff[4];
+ logd("Connect: Device ID: 0x%04X", *devid);
+
+ *maxmem = (buff[5] << 8) | buff[6];
+ logd("Connect: Memory Size: 0x%04X", *maxmem);
+
+ return 0;
+}
--- /dev/null
+/* proto.c */
+void print_memory(uint16_t addr, const unsigned char *buff, int words);
+void dumpbuff(const unsigned char *buff, int charlen);
+int loader_readmem(port_t *pt, uint16_t addr, uint8_t *memory, int words);
+int loader_writemem(port_t *pt, uint16_t addr, uint8_t *memory, int words);
+int loader_connect(port_t *pt, uint16_t *maxmem, uint16_t *devid);
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "log.h"
+#include "serial.h"
+
+struct serial_port {
+ int fd;
+};
+
+static speed_t baud(int speed)
+{
+ if (speed == 230400) return B230400; else
+ if (speed == 115200) return B115200; else
+ if (speed == 57600) return B57600; else
+ if (speed == 38400) return B38400; else
+ if (speed == 19200) return B19200; else
+ if (speed == 9600) return B9600; else
+ if (speed == 4800) return B4800; else
+ if (speed == 2400) return B2400; else
+ if (speed == 1200) return B1200; else {
+ loge("Error setting baud rate: %d not recognised.", speed);
+ return B0;
+ }
+
+}
+
+port_t * serial_open(const char *name, int speed)
+{
+ port_t *pt = NULL;
+ int fd;
+
+ if ((fd = open(name, O_RDWR | O_NOCTTY))<0) {
+ loge("Error: opening %s: %s", name, strerror(errno));
+ return NULL;
+ }
+
+ struct termios adtio;
+ bzero(&adtio, sizeof(adtio));
+
+ tcgetattr(fd, &adtio);
+ adtio.c_cflag = CS8 | CLOCAL | CREAD;
+ adtio.c_iflag = IGNPAR | IGNBRK;
+ adtio.c_oflag = 0;
+ adtio.c_lflag = 0; // non-canon, no echo
+
+ cfmakeraw(&adtio);
+
+ adtio.c_cc[VTIME] = 0;
+ adtio.c_cc[VMIN] = 1;
+
+ cfsetispeed(&adtio, baud(speed));
+ cfsetospeed(&adtio, baud(speed));
+
+ tcsetattr(fd, TCSANOW, &adtio);
+
+ pt = malloc(sizeof(port_t));
+ pt->fd = fd;
+
+ return pt;
+
+}
+
+void serial_close(port_t * pt)
+{
+ if (pt == NULL) return;
+ if (pt->fd < 0) return;
+
+ close(pt->fd);
+ pt->fd = -1;
+
+ return;
+}
+
+int serial_read(port_t * pt, unsigned char * buff, size_t len)
+{
+ if (pt == NULL || pt->fd < 0) return -1;
+
+ int ret = 0;
+ int count = 0;
+ unsigned char * p = buff;
+ while (count < len) {
+ ret = read(pt->fd, p, len-count);
+ if (ret <= 0) return ret;
+ p += ret;
+ count += ret;
+ }
+ return count;
+}
+
+int serial_write(port_t * pt, unsigned char * buff, size_t len)
+{
+ if (pt == NULL || pt->fd < 0) return -1;
+
+ return write(pt->fd, buff, len);
+}
+
+int serial_break(port_t * pt, int set)
+{
+ if (pt == NULL || pt->fd < 0) return -1;
+
+ if (set)
+ ioctl(pt->fd, TIOCSBRK, 0);
+ else
+ ioctl(pt->fd, TIOCCBRK, 0);
+
+ return 0;
+}
+
--- /dev/null
+/* Serial port controls */
+
+struct serial_port;
+typedef struct serial_port port_t;
+
+#define ACK 0x06
+#define NACK 0x15
+
+/* serial.c */
+port_t *serial_open(const char *name, int speed);
+void serial_close(port_t *pt);
+int serial_read(port_t *pt, unsigned char *buff, size_t len);
+int serial_write(port_t *pt, unsigned char *buff, size_t len);
+int serial_break(port_t *pt, int set);
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+
+/* return 0 for end of file. -1 for error */
+int parse_ihex16(const char *line, uint8_t *bytes, int *addr, int *code)
+{
+ unsigned int sum, len, cksum;
+ unsigned int laddr, lcode;
+ int i;
+ const char *p;
+
+ if (line[0] != ':') return -1;
+ if (strlen(line) < 11) return -1;
+ p = &line[1];
+ if (!sscanf(p, "%02x", &len)) return -1;
+ p+=2;
+ if (strlen(line) < (11 + (len * 2))) return -1;
+ if (!sscanf(p, "%04x", &laddr)) return -1;
+ p += 4;
+ *addr = laddr; // little endian address record
+ if (!sscanf(p, "%02x", &lcode)) return -1;
+ p+=2;
+ *code = lcode & 0xFF;
+
+ /* end of file record */
+ if (*code == 1) return 0;
+
+ sum = (len & 0xFF) + ((*addr >> 8) & 0xFF) + (*addr & 0xFF) + (*code & 0xFF);
+
+ i = 0;
+ while (i < len) {
+ unsigned int byte;
+ if (!sscanf(p, "%02x", &byte)) return -1;
+ bytes[i++] = byte & 0xFF;
+ sum += byte & 0xFF;
+ p += 2;
+ }
+ if (!sscanf(p, "%02x", &cksum)) return -1;
+ if ( ((sum & 0xFF) + (cksum & 0xFF)) & 0xFF ) return -1;
+ return len;
+}
+
+int main(int argc, char **argv)
+{
+ FILE *in;
+
+ if (argc < 2) return 1;
+
+ if ((in=fopen(argv[1], "r"))==NULL) {
+ fprintf(stderr, "Failed opening %s: %s\n", argv[1], strerror(errno));
+ return 1;
+ }
+
+ char buff[1024];
+
+ while (!feof(in) && fgets(buff, sizeof(buff), in)!=NULL) {
+ if (buff[0] == '#') continue;
+
+ unsigned char bytes[80];
+ int len, addr, code;
+
+ if ((len=parse_ihex16(buff, bytes, &addr, &code)) <= 0) {
+ if (len < 0) fprintf(stderr, "Bad line: %s\n", buff);
+ continue;
+ }
+
+ printf("Addr: %04X +%2d code=%d :", addr, len, code);
+ for (int i=0; i<len; i++) printf(" %02X", bytes[i]);
+ printf("\n");
+ }
+
+ fclose(in);
+}
--- /dev/null
+#
+# There exist several targets which are by default empty and which can be
+# used for execution of your targets. These targets are usually executed
+# before and after some main targets. They are:
+#
+# .build-pre: called before 'build' target
+# .build-post: called after 'build' target
+# .clean-pre: called before 'clean' target
+# .clean-post: called after 'clean' target
+# .clobber-pre: called before 'clobber' target
+# .clobber-post: called after 'clobber' target
+# .all-pre: called before 'all' target
+# .all-post: called after 'all' target
+# .help-pre: called before 'help' target
+# .help-post: called after 'help' target
+#
+# Targets beginning with '.' are not intended to be called on their own.
+#
+# Main targets can be executed directly, and they are:
+#
+# build build a specific configuration
+# clean remove built files from a configuration
+# clobber remove all built files
+# all build all configurations
+# help print help mesage
+#
+# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
+# .help-impl are implemented in nbproject/makefile-impl.mk.
+#
+# Available make variables:
+#
+# CND_BASEDIR base directory for relative paths
+# CND_DISTDIR default top distribution directory (build artifacts)
+# CND_BUILDDIR default top build directory (object files, ...)
+# CONF name of current configuration
+# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
+# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
+# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
+# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
+# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
+# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
+#
+# NOCDDL
+
+
+# Environment
+MKDIR=mkdir
+CP=cp
+CCADMIN=CCadmin
+RANLIB=ranlib
+
+
+# build
+build: .build-post
+
+.build-pre:
+# Add your pre 'build' code here...
+
+.build-post: .build-impl
+# Add your post 'build' code here...
+
+
+# clean
+clean: .clean-post
+
+.clean-pre:
+# Add your pre 'clean' code here...
+
+.clean-post: .clean-impl
+# Add your post 'clean' code here...
+
+
+# clobber
+clobber: .clobber-post
+
+.clobber-pre:
+# Add your pre 'clobber' code here...
+
+.clobber-post: .clobber-impl
+# Add your post 'clobber' code here...
+
+
+# all
+all: .all-post
+
+.all-pre:
+# Add your pre 'all' code here...
+
+.all-post: .all-impl
+# Add your post 'all' code here...
+
+
+# help
+help: .help-post
+
+.help-pre:
+# Add your pre 'help' code here...
+
+.help-post: .help-impl
+# Add your post 'help' code here...
+
+
+
+# include project implementation makefile
+include nbproject/Makefile-impl.mk
+
+# include project make variables
+include nbproject/Makefile-variables.mk
--- /dev/null
+ radix dec
+
+ errorlevel -302
+
+#include "p16f1455.inc"
+
+; CONFIG1
+ __config _CONFIG1, 0xFCC
+;; __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_SWDTEN & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
+; CONFIG2
+ __config _CONFIG2, 0x16CF
+; __CONFIG _CONFIG2, _WRT_OFF & _CPUDIV_NOCLKDIV & _USBLSCLK_48MHz & _PLLMULT_3x & _PLLEN_DISABLED & _STVREN_ON & _BORV_LO & _LPBOR_ON & _LVP_OFF
+
+
+#define max_flash 0x2000
+#define row_size 32
+
+; 16F1455 errata says self-program only works <= 4MHz clock
+xtal EQU 4000000
+baud EQU 19200
+
+#include "spbrgselect.inc"
+
+; This is the smallest multiple of 32 that the bootloader
+; code fits into (minus the 4 for the remapped section)
+loader_size set 224
+
+; fit remap section in end of previous page
+; so we dont need to rewrite the bootloader page
+remap_addr set max_flash - loader_size - 4
+
+; Variables
+ cblock 0x20
+ buffer:80
+ endc
+
+ ; common ram section
+ cblock 0x70
+ cmd
+ crc
+ i
+ tmp
+ endc
+
+; ############ RESET ############
+; This is the normal reset vector
+; when a program is loaded, its version of these 4 will be moved
+; and replaced with our code to jump to the bootloader
+
+Start CODE 0x0000
+ MOVLP high(StartBoot)
+ GOTO StartBoot
+ NOP
+ NOP
+; after this is the normal reset vector and rest of the loaded program
+
+
+; simple test program
+Main
+ banksel ANSELA
+ CLRF ANSELA
+ banksel TRISA
+ CLRF TRISA
+ CLRF TRISC
+ banksel PORTA
+ BSF PORTA,5 ; green on
+ BCF PORTA,4 ; red off
+ SLEEP
+
+
+; At the far end of memory...
+; this is the relocated boot sector
+ ORG remap_addr
+AppVector
+; NOP
+ MOVLP high(Main)
+ GOTO Main ; pretend program loaded
+ NOP
+ NOP
+
+; immediately followed by out bootloader
+ ORG remap_addr+4
+StartBoot
+
+ ; First configure the pin
+ ; 16f1455 RX=RC5 TX=RC4
+; banksel TRISC
+; BSF TRISC,5 ; RC5 as input
+; BCF TRISC,4 ; RC4 as output
+ banksel PORTC
+ CLRF PORTC
+
+ BTFSC PORTC,5 ; RC5 is Clear (break state) carry on
+ BRA AppVector ; Was not clear, launch app instead
+
+ ; Lets start the bootloader properly
+ banksel OSCCON
+ MOVLW b'00110100'
+ MOVWF OSCCON ; 4Mhz clock mode
+ BTFSS OSCSTAT,HFIOFR
+ BRA $-1 ; wait until oscillator is ready
+ MOVLW b'00011001' ; Activate watchdog, 4 seconds
+ MOVWF WDTCON
+
+SetBaud
+ ; Set the baud rate and enable uart
+ banksel TXSTA
+ MOVLW b'00100100' ; TXEN=1 SYNC=0 BRGH=1
+ MOVWF TXSTA
+ banksel SPBRGL
+ MOVLW spbrg_value
+ MOVWF SPBRGL
+ CLRF SPBRGH
+ banksel RCSTA
+ MOVLW b'10010000' ; SPEN CREN
+ MOVWF RCSTA
+
+; debug lights
+; debug RA5 green, RA4 red
+ banksel ANSELA
+ CLRF ANSELA
+ banksel TRISA
+ CLRF TRISA
+ banksel PORTA
+ BCF PORTA,5 ; green off
+ BSF PORTA,4 ; red on
+
+ ; Send the 'we heard you' ACK symbol
+ CLRF crc
+ MOVLW 0x06
+ CALL SendByte
+ MOVLW 'B'
+ CALL SendByte
+ MOVLW 'L'
+ CALL SendByte
+
+ ; Wait for PC to drop the break condition
+ banksel PORTC
+ BTFSS PORTC,5
+ BRA $-1
+
+ ; Transmit device ID
+ banksel PMADRL
+ MOVLW 0x06 ; 0x8006 Device ID
+ MOVWF PMADRL
+ CLRF PMADRH
+ BSF PMCON1,CFGS
+ BSF PMCON1,RD
+ NOP
+ NOP
+ MOVF PMDATH,W
+ CALL SendByte
+ banksel PMDATL
+ MOVF PMDATL,W
+ CALL SendByte
+
+ ; Transmit location of bootloader, and thus top of flash
+ MOVLW high(remap_addr)
+ CALL SendByte
+
+ MOVLW low(remap_addr)
+ CALL SendByte
+
+ ; transmit csum to complete the welcome message
+ CALL SendCRC
+
+ ; Wait here for instructions
+CmdLoop
+ CLRWDT
+ CLRF crc
+ CALL ReadByte
+ MOVWF cmd ; keep it to re-examine
+
+ ; command 'R' read a row (32 words)
+ SUBLW 'R'
+ SKPNZ
+ BRA ReadLine
+
+ ; command 'W' write a row (32 words)
+ MOVFW cmd
+ SUBLW 'W'
+ SKPNZ
+ BRA WriteLine
+
+ ; command 'B' reboot
+ MOVFW cmd
+ SUBLW 'B'
+ SKPNZ
+ BRA DoBoot
+
+ BRA CmdLoop
+
+ReadByte ; put it in W
+ banksel PIR1
+ BTFSS PIR1, RCIF
+ BRA $-1
+ banksel RCREG
+ MOVF RCREG,W
+ ADDWF crc,F
+ RETURN
+
+ReadCRC
+ banksel PIR1
+ BTFSS PIR1, RCIF
+ BRA $-1
+ banksel RCREG
+ MOVF RCREG,W
+ RETURN
+
+
+SendCRC ; copy the crc in as the thing to send
+ MOVF crc,W
+SendByte ; that is in W
+ ADDWF crc,F
+ banksel PIR1
+ BTFSS PIR1, TXIF
+ BRA $-1
+ banksel TXREG
+ MOVWF TXREG
+ RETURN
+
+SendError ; Say there was an error (must be an in subr)
+ MOVLW 'E'
+ CALL SendByte
+ BRA CmdLoop
+
+ReadLine ; read a row
+ CALL ReadByte
+ banksel PMADRH
+ MOVWF PMADRH ; store the high byte
+ CALL ReadByte
+ banksel PMADRL
+ ANDLW 0xE0 ; align to 32 word
+ MOVWF PMADRL ; store the low byte
+ CALL ReadCRC ; read the checksum
+ SUBWF crc,W
+ SKPZ ; if crc-checksum !=0 goto Error
+ BRA SendError
+; now lets send a record back to the host
+ MOVLW row_size ; 32 words
+ MOVWF i
+ CLRF crc ; reset crc for outgoing message
+ MOVLW 'R' ; warn that we are writing
+ CALL SendByte
+ banksel PMADRH
+ MOVF PMADRH,W ; say what the start address is
+ ANDLW 0x7F ; top bit is always set, duh
+ CALL SendByte
+ banksel PMADRL
+ MOVF PMADRL,W
+ CALL SendByte
+
+ReadLoop
+ banksel PMCON1
+ BCF PMCON1,CFGS ; read program not config
+ BSF PMCON1,RD
+ NOP
+ NOP
+ MOVF PMDATH,W ; send high byte
+ CALL SendByte
+ banksel PMDATL
+ MOVF PMDATL,W ; send low byte
+ CALL SendByte
+ banksel PMADRL
+ ; Assumption: this is 32 word aligned, will never cross boundary
+ INCF PMADRL,F ; increment address
+ DECFSZ i,F ; i--
+ BRA ReadLoop ; go around again
+ ; finished sending program words
+ CALL SendCRC ; send the crc
+ ; done, go back for next command
+ BRA CmdLoop
+
+WriteLine ; write a row
+ CALL ReadByte
+ banksel PMADRH
+ MOVWF PMADRH ; store the high byte
+ CALL ReadByte
+ banksel PMADRL
+ ANDLW 0xE0 ; align to 32 word
+ MOVWF PMADRL ; store the low byte
+ ; lets just store the bytes in buff until we are sure the checksum is good
+ banksel FSR0L
+ MOVLW high(buffer)
+ MOVWF FSR0H
+ MOVLW low(buffer)
+ MOVWF FSR0L
+ ; read row_size * 2 bytes
+ MOVLW row_size * 2
+ MOVWF i
+WriteLineRead
+ CALL ReadByte
+ MOVWI FSR0++
+ DECFSZ i,F
+ BRA WriteLineRead
+ ; now read the crc and test
+ CALL ReadCRC ; read the checksum
+ SUBWF crc,W
+ SKPZ ; if crc-checksum !=0 goto Error
+ BRA SendError
+ ; everything is fine, commit to memory
+ ; first we have to erase the row
+ banksel PMCON1
+ BCF PMCON1,CFGS ; program
+ BSF PMCON1,FREE ; erase
+ BSF PMCON1,WREN ; enable writes
+ MOVLW 0x55
+ MOVWF PMCON2
+ MOVLW 0xAA
+ MOVWF PMCON2
+ BSF PMCON1,WR ; commit
+ NOP
+ NOP ; CPU goes to sleep for 2mS
+ BCF PMCON1,WREN ; disable writes
+ ; now move the FSR back to the start
+ banksel FSR0L
+ MOVLW high(buffer)
+ MOVWF FSR0H
+ MOVLW low(buffer)
+ MOVWF FSR0L
+ MOVLW row_size ; need to do this once per word
+ MOVWF i
+
+ ; setup for writing to latches
+ banksel PMCON1
+ BSF PMCON1,WREN ; enable writes
+ BCF PMCON1,CFGS ; program
+ BCF PMCON1,FREE ; write not erase this time
+ BSF PMCON1,LWLO ; into the latches
+
+LatchWord
+ MOVIW FSR0++
+ MOVWF PMDATH
+ MOVIW FSR0++
+ MOVWF PMDATL
+ DECFSZ i,F
+ BRA LatchWrite
+ BRA CommitWrite
+ ; just a latching write
+LatchWrite
+ MOVLW 0x55
+ MOVWF PMCON2
+ MOVLW 0xAA
+ MOVWF PMCON2
+ BSF PMCON1,WR ; commit
+ NOP
+ NOP
+ INCF PMADRL,F ; move along
+ BRA LatchWord
+CommitWrite
+ BCF PMCON1,LWLO ; real thing this time
+ MOVLW 0x55
+ MOVWF PMCON2
+ MOVLW 0xAA
+ MOVWF PMCON2
+ BSF PMCON1,WR ; commit
+ NOP
+ NOP ; cpu stalls for 2mS
+ ; and we are finished
+ BCF PMCON1,WREN ; disable writes
+ ; tell the other end we finished
+ CLRF crc ; reset crc for outgoing message
+ MOVLW 'W' ; confirm the write command
+ CALL SendByte
+ banksel PMADRH
+ MOVF PMADRH,W ; say what the start address is
+ ANDLW 0x7F ; top bit is always set, duh
+ CALL SendByte
+ banksel PMADRL
+ MOVF PMADRL,W
+ ANDLW 0xE0 ; align to 32 word
+ CALL SendByte
+ CALL SendCRC
+ ; finished writing
+ BRA CmdLoop
+
+DoBoot
+ RESET
+
+EndBoot
+ END
+
--- /dev/null
+#
+# Generated Makefile - do not edit!
+#
+# Edit the Makefile in the project folder instead (../Makefile). Each target
+# has a -pre and a -post target defined where you can add customized code.
+#
+# This makefile implements configuration specific macros and targets.
+
+
+# Include project Makefile
+ifeq "${IGNORE_LOCAL}" "TRUE"
+# do not include local makefile. User is passing all local related variables already
+else
+include Makefile
+# Include makefile containing local settings
+ifeq "$(wildcard nbproject/Makefile-local-default.mk)" "nbproject/Makefile-local-default.mk"
+include nbproject/Makefile-local-default.mk
+endif
+endif
+
+# Environment
+MKDIR=mkdir -p
+RM=rm -f
+MV=mv
+CP=cp
+
+# Macros
+CND_CONF=default
+ifeq ($(TYPE_IMAGE), DEBUG_RUN)
+IMAGE_TYPE=debug
+OUTPUT_SUFFIX=cof
+DEBUGGABLE_SUFFIX=cof
+FINAL_IMAGE=dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}
+else
+IMAGE_TYPE=production
+OUTPUT_SUFFIX=hex
+DEBUGGABLE_SUFFIX=cof
+FINAL_IMAGE=dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}
+endif
+
+# Object Directory
+OBJECTDIR=build/${CND_CONF}/${IMAGE_TYPE}
+
+# Distribution Directory
+DISTDIR=dist/${CND_CONF}/${IMAGE_TYPE}
+
+# Source Files Quoted if spaced
+SOURCEFILES_QUOTED_IF_SPACED=main.asm
+
+# Object Files Quoted if spaced
+OBJECTFILES_QUOTED_IF_SPACED=${OBJECTDIR}/main.o
+POSSIBLE_DEPFILES=${OBJECTDIR}/main.o.d
+
+# Object Files
+OBJECTFILES=${OBJECTDIR}/main.o
+
+# Source Files
+SOURCEFILES=main.asm
+
+
+CFLAGS=
+ASFLAGS=
+LDLIBSOPTIONS=
+
+############# Tool locations ##########################################
+# If you copy a project from one host to another, the path where the #
+# compiler is installed may be different. #
+# If you open this project with MPLAB X in the new host, this #
+# makefile will be regenerated and the paths will be corrected. #
+#######################################################################
+# fixDeps replaces a bunch of sed/cat/printf statements that slow down the build
+FIXDEPS=fixDeps
+
+.build-conf: ${BUILD_SUBPROJECTS}
+ ${MAKE} -f nbproject/Makefile-default.mk dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}
+
+MP_PROCESSOR_OPTION=16f1455
+MP_LINKER_DEBUG_OPTION=
+# ------------------------------------------------------------------------------------
+# Rules for buildStep: assemble
+ifeq ($(TYPE_IMAGE), DEBUG_RUN)
+${OBJECTDIR}/main.o: main.asm nbproject/Makefile-${CND_CONF}.mk
+ @${MKDIR} ${OBJECTDIR}
+ @${RM} ${OBJECTDIR}/main.o.d
+ @${RM} ${OBJECTDIR}/main.o
+ @${FIXDEPS} dummy.d -e "${OBJECTDIR}/main.err" $(SILENT) -c ${MP_AS} $(MP_EXTRA_AS_PRE) -d__DEBUG -d__MPLAB_DEBUGGER_ICD3=1 -q -p$(MP_PROCESSOR_OPTION) -u -l\\\"${OBJECTDIR}/main.lst\\\" -e\\\"${OBJECTDIR}/main.err\\\" $(ASM_OPTIONS) -o\\\"${OBJECTDIR}/main.o\\\" \\\"main.asm\\\"
+ @${DEP_GEN} -d "${OBJECTDIR}/main.o"
+ @${FIXDEPS} "${OBJECTDIR}/main.o.d" $(SILENT) -rsi ${MP_AS_DIR} -c18
+
+else
+${OBJECTDIR}/main.o: main.asm nbproject/Makefile-${CND_CONF}.mk
+ @${MKDIR} ${OBJECTDIR}
+ @${RM} ${OBJECTDIR}/main.o.d
+ @${RM} ${OBJECTDIR}/main.o
+ @${FIXDEPS} dummy.d -e "${OBJECTDIR}/main.err" $(SILENT) -c ${MP_AS} $(MP_EXTRA_AS_PRE) -q -p$(MP_PROCESSOR_OPTION) -u -l\\\"${OBJECTDIR}/main.lst\\\" -e\\\"${OBJECTDIR}/main.err\\\" $(ASM_OPTIONS) -o\\\"${OBJECTDIR}/main.o\\\" \\\"main.asm\\\"
+ @${DEP_GEN} -d "${OBJECTDIR}/main.o"
+ @${FIXDEPS} "${OBJECTDIR}/main.o.d" $(SILENT) -rsi ${MP_AS_DIR} -c18
+
+endif
+
+# ------------------------------------------------------------------------------------
+# Rules for buildStep: link
+ifeq ($(TYPE_IMAGE), DEBUG_RUN)
+dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}: ${OBJECTFILES} nbproject/Makefile-${CND_CONF}.mk
+ @${MKDIR} dist/${CND_CONF}/${IMAGE_TYPE}
+ ${MP_LD} $(MP_EXTRA_LD_PRE) -p$(MP_PROCESSOR_OPTION) -w -x -u_DEBUG -z__ICD2RAM=1 -m"${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map" -z__MPLAB_BUILD=1 -z__MPLAB_DEBUG=1 -z__MPLAB_DEBUGGER_ICD3=1 $(MP_LINKER_DEBUG_OPTION) -odist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX} ${OBJECTFILES_QUOTED_IF_SPACED}
+else
+dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}: ${OBJECTFILES} nbproject/Makefile-${CND_CONF}.mk
+ @${MKDIR} dist/${CND_CONF}/${IMAGE_TYPE}
+ ${MP_LD} $(MP_EXTRA_LD_PRE) -p$(MP_PROCESSOR_OPTION) -w -m"${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map" -z__MPLAB_BUILD=1 -odist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${DEBUGGABLE_SUFFIX} ${OBJECTFILES_QUOTED_IF_SPACED}
+endif
+
+
+# Subprojects
+.build-subprojects:
+
+
+# Subprojects
+.clean-subprojects:
+
+# Clean Targets
+.clean-conf: ${CLEAN_SUBPROJECTS}
+ ${RM} -r build/default
+ ${RM} -r dist/default
+
+# Enable dependency checking
+.dep.inc: .depcheck-impl
+
+DEPFILES=$(shell "${PATH_TO_IDE_BIN}"mplabwildcard ${POSSIBLE_DEPFILES})
+ifneq (${DEPFILES},)
+include ${DEPFILES}
+endif
--- /dev/null
+#
+#Fri Sep 27 11:45:23 BST 2013
+default.languagetoolchain.dir=/opt/microchip/mplabx/mpasmx
+com-microchip-mplab-nbide-embedded-makeproject-MakeProject.md5=0d2b1469ad71adb787c711a416386331
+default.languagetoolchain.version=5.52
+host.platform=linux
+conf.ids=default
+default.com-microchip-mplab-nbide-toolchainMPASMWIN-MPASMWINLanguageToolchain.md5=dc1e238caba4e98e3e2f2da7006384df
--- /dev/null
+#
+# Generated Makefile - do not edit!
+#
+# Edit the Makefile in the project folder instead (../Makefile). Each target
+# has a pre- and a post- target defined where you can add customization code.
+#
+# This makefile implements macros and targets common to all configurations.
+#
+# NOCDDL
+
+
+# Building and Cleaning subprojects are done by default, but can be controlled with the SUB
+# macro. If SUB=no, subprojects will not be built or cleaned. The following macro
+# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf
+# and .clean-reqprojects-conf unless SUB has the value 'no'
+SUB_no=NO
+SUBPROJECTS=${SUB_${SUB}}
+BUILD_SUBPROJECTS_=.build-subprojects
+BUILD_SUBPROJECTS_NO=
+BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}}
+CLEAN_SUBPROJECTS_=.clean-subprojects
+CLEAN_SUBPROJECTS_NO=
+CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}}
+
+
+# Project Name
+PROJECTNAME=mybootload.X
+
+# Active Configuration
+DEFAULTCONF=default
+CONF=${DEFAULTCONF}
+
+# All Configurations
+ALLCONFS=default
+
+
+# build
+.build-impl: .build-pre
+ ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf
+
+
+# clean
+.clean-impl: .clean-pre
+ ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf
+
+# clobber
+.clobber-impl: .clobber-pre .depcheck-impl
+ ${MAKE} SUBPROJECTS=${SUBPROJECTS} CONF=default clean
+
+
+
+# all
+.all-impl: .all-pre .depcheck-impl
+ ${MAKE} SUBPROJECTS=${SUBPROJECTS} CONF=default build
+
+
+
+# dependency checking support
+.depcheck-impl:
+# @echo "# This code depends on make tool being used" >.dep.inc
+# @if [ -n "${MAKE_VERSION}" ]; then \
+# echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES}))" >>.dep.inc; \
+# echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \
+# echo "include \$${DEPFILES}" >>.dep.inc; \
+# echo "endif" >>.dep.inc; \
+# else \
+# echo ".KEEP_STATE:" >>.dep.inc; \
+# echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \
+# fi
--- /dev/null
+#
+# Generated Makefile - do not edit!
+#
+#
+# This file contains information about the location of compilers and other tools.
+# If you commmit this file into your revision control server, you will be able to
+# to checkout the project and build it from the command line with make. However,
+# if more than one person works on the same project, then this file might show
+# conflicts since different users are bound to have compilers in different places.
+# In that case you might choose to not commit this file and let MPLAB X recreate this file
+# for each user. The disadvantage of not commiting this file is that you must run MPLAB X at
+# least once so the file gets created and the project can be built. Finally, you can also
+# avoid using this file at all if you are only building from the command line with make.
+# You can invoke make with the values of the macros:
+# $ makeMP_CC="/opt/microchip/mplabc30/v3.30c/bin/pic30-gcc" ...
+#
+PATH_TO_IDE_BIN=/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/
+# Adding MPLAB X bin directory to path.
+PATH:=/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/:$(PATH)
+# Path to java used to run MPLAB X when this makefile was created
+MP_JAVA_PATH="/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/jre/bin/"
+OS_CURRENT="$(shell uname -s)"
+# MP_CC is not defined
+# MP_CPPC is not defined
+# MP_BC is not defined
+MP_AS="/opt/microchip/mplabx/mpasmx/mpasmx"
+MP_LD="/opt/microchip/mplabx/mpasmx/mplink"
+MP_AR="/opt/microchip/mplabx/mpasmx/mplib"
+DEP_GEN=${MP_JAVA_PATH}java -jar "/opt/microchip/mplabx/mplab_ide/mplab_ide/modules/../../bin/extractobjectdependencies.jar"
+# MP_CC_DIR is not defined
+# MP_CPPC_DIR is not defined
+# MP_BC_DIR is not defined
+MP_AS_DIR="/opt/microchip/mplabx/mpasmx"
+MP_LD_DIR="/opt/microchip/mplabx/mpasmx"
+MP_AR_DIR="/opt/microchip/mplabx/mpasmx"
+# MP_BC_DIR is not defined
--- /dev/null
+#
+# Generated - do not edit!
+#
+# NOCDDL
+#
+CND_BASEDIR=`pwd`
+# default configuration
+CND_ARTIFACT_DIR_default=dist/default/production
+CND_ARTIFACT_NAME_default=mybootload.X.production.hex
+CND_ARTIFACT_PATH_default=dist/default/production/mybootload.X.production.hex
+CND_PACKAGE_DIR_default=${CND_DISTDIR}/default/package
+CND_PACKAGE_NAME_default=mybootload.x.tar
+CND_PACKAGE_PATH_default=${CND_DISTDIR}/default/package/mybootload.x.tar
--- /dev/null
+#!/bin/bash -x
+
+#
+# Generated - do not edit!
+#
+
+# Macros
+TOP=`pwd`
+CND_CONF=default
+CND_DISTDIR=dist
+TMPDIR=build/${CND_CONF}/${IMAGE_TYPE}/tmp-packaging
+TMPDIRNAME=tmp-packaging
+OUTPUT_PATH=dist/${CND_CONF}/${IMAGE_TYPE}/mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}
+OUTPUT_BASENAME=mybootload.X.${IMAGE_TYPE}.${OUTPUT_SUFFIX}
+PACKAGE_TOP_DIR=mybootload.x/
+
+# Functions
+function checkReturnCode
+{
+ rc=$?
+ if [ $rc != 0 ]
+ then
+ exit $rc
+ fi
+}
+function makeDirectory
+# $1 directory path
+# $2 permission (optional)
+{
+ mkdir -p "$1"
+ checkReturnCode
+ if [ "$2" != "" ]
+ then
+ chmod $2 "$1"
+ checkReturnCode
+ fi
+}
+function copyFileToTmpDir
+# $1 from-file path
+# $2 to-file path
+# $3 permission
+{
+ cp "$1" "$2"
+ checkReturnCode
+ if [ "$3" != "" ]
+ then
+ chmod $3 "$2"
+ checkReturnCode
+ fi
+}
+
+# Setup
+cd "${TOP}"
+mkdir -p ${CND_DISTDIR}/${CND_CONF}/package
+rm -rf ${TMPDIR}
+mkdir -p ${TMPDIR}
+
+# Copy files and create directories and links
+cd "${TOP}"
+makeDirectory ${TMPDIR}/mybootload.x/bin
+copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
+
+
+# Generate tar file
+cd "${TOP}"
+rm -f ${CND_DISTDIR}/${CND_CONF}/package/mybootload.x.tar
+cd ${TMPDIR}
+tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/package/mybootload.x.tar *
+checkReturnCode
+
+# Cleanup
+cd "${TOP}"
+rm -rf ${TMPDIR}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<configurationDescriptor version="62">
+ <logicalFolder name="root" displayName="root" projectFiles="true">
+ <logicalFolder name="HeaderFiles"
+ displayName="Header Files"
+ projectFiles="true">
+ <itemPath>spbrgselect.inc</itemPath>
+ </logicalFolder>
+ <logicalFolder name="LinkerScript"
+ displayName="Linker Files"
+ projectFiles="true">
+ </logicalFolder>
+ <logicalFolder name="SourceFiles"
+ displayName="Source Files"
+ projectFiles="true">
+ <itemPath>main.asm</itemPath>
+ </logicalFolder>
+ <logicalFolder name="ExternalFiles"
+ displayName="Important Files"
+ projectFiles="false">
+ <itemPath>Makefile</itemPath>
+ </logicalFolder>
+ </logicalFolder>
+ <projectmakefile>Makefile</projectmakefile>
+ <confs>
+ <conf name="default" type="2">
+ <toolsSet>
+ <developmentServer>localhost</developmentServer>
+ <targetDevice>PIC16F1455</targetDevice>
+ <targetHeader></targetHeader>
+ <targetPluginBoard></targetPluginBoard>
+ <platformTool>ICD3PlatformTool</platformTool>
+ <languageToolchain>MPASMWIN</languageToolchain>
+ <languageToolchainVersion>5.52</languageToolchainVersion>
+ <platform>2</platform>
+ </toolsSet>
+ <compileType>
+ <linkerTool>
+ <linkerLibItems>
+ </linkerLibItems>
+ </linkerTool>
+ <loading>
+ <useAlternateLoadableFile>false</useAlternateLoadableFile>
+ <alternateLoadableFile></alternateLoadableFile>
+ </loading>
+ </compileType>
+ <makeCustomizationType>
+ <makeCustomizationPreStepEnabled>false</makeCustomizationPreStepEnabled>
+ <makeCustomizationPreStep></makeCustomizationPreStep>
+ <makeCustomizationPostStepEnabled>false</makeCustomizationPostStepEnabled>
+ <makeCustomizationPostStep></makeCustomizationPostStep>
+ <makeCustomizationPutChecksumInUserID>false</makeCustomizationPutChecksumInUserID>
+ <makeCustomizationEnableLongLines>false</makeCustomizationEnableLongLines>
+ <makeCustomizationNormalizeHexFile>false</makeCustomizationNormalizeHexFile>
+ </makeCustomizationType>
+ <ICD3PlatformTool>
+ <property key="AutoSelectMemRanges" value="auto"/>
+ <property key="Freeze Peripherals" value="true"/>
+ <property key="SecureSegment.SegmentProgramming" value="FullChipProgramming"/>
+ <property key="ToolFirmwareFilePath"
+ value="Press to browse for a specific firmware version"/>
+ <property key="ToolFirmwareOption.UseLatestFirmware" value="true"/>
+ <property key="debugoptions.useswbreakpoints" value="false"/>
+ <property key="hwtoolclock.frcindebug" value="false"/>
+ <property key="memories.aux" value="false"/>
+ <property key="memories.bootflash" value="false"/>
+ <property key="memories.configurationmemory" value="false"/>
+ <property key="memories.eeprom" value="true"/>
+ <property key="memories.flashdata" value="true"/>
+ <property key="memories.id" value="true"/>
+ <property key="memories.programmemory" value="true"/>
+ <property key="memories.programmemory.end" value="0x1fff"/>
+ <property key="memories.programmemory.start" value="0x0"/>
+ <property key="poweroptions.powerenable" value="false"/>
+ <property key="programoptions.eraseb4program" value="true"/>
+ <property key="programoptions.preserveeeprom" value="false"/>
+ <property key="programoptions.preserveprogramrange" value="false"/>
+ <property key="programoptions.preserveprogramrange.end" value="0x1fff"/>
+ <property key="programoptions.preserveprogramrange.start" value="0x0"/>
+ <property key="programoptions.preserveuserid" value="false"/>
+ <property key="programoptions.testmodeentrymethod" value="VPPFirst"/>
+ <property key="programoptions.usehighvoltageonmclr" value="false"/>
+ <property key="programoptions.uselvpprogramming" value="false"/>
+ <property key="voltagevalue" value="5.0"/>
+ </ICD3PlatformTool>
+ <MPASMWIN-AS>
+ <property key="cross.reference.file" value=""/>
+ <property key="default.radix" value="HEX"/>
+ <property key="enable.case.sensitivity" value="true"/>
+ <property key="hex.output.format" value="INHX32"/>
+ <property key="preprocessor.macros" value=""/>
+ <property key="warning.level" value="0"/>
+ </MPASMWIN-AS>
+ <MPASMWIN-LD>
+ <property key="cod-file" value="false"/>
+ <property key="extra-lib-directories" value=""/>
+ <property key="hex-output-format" value="INHX32"/>
+ <property key="map-file" value="${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map"/>
+ </MPASMWIN-LD>
+ <PICkit2PlatformTool>
+ <property key="pk2settings.3state" value="false"/>
+ <property key="pk2settings.preserveee" value="false"/>
+ <property key="pk2settings.setvddvoltage" value=""/>
+ <property key="pk2settings.userpgmexec" value="true"/>
+ <property key="pk2settings.usetargetpower" value="true"/>
+ </PICkit2PlatformTool>
+ <mpasmsuite>
+ <property key="absolute-mode" value="false"/>
+ <property key="eeprom-width" value="8"/>
+ <property key="extended-mode" value="false"/>
+ <property key="extended-mode-mpasm" value="false"/>
+ <property key="extended-mode-mplink" value="false"/>
+ </mpasmsuite>
+ </conf>
+ </confs>
+</configurationDescriptor>
--- /dev/null
+#
+#Fri Sep 27 11:32:28 BST 2013
+mdbDebugger/MEMORY_VIEW_LAST_HW_BP_RESOURCE_WARN=false
+pkobskde/CHECK_4_HIGH_VOLTAGE_VPP=false
+pk3/DEVID_MISMATCH=false
+mdbDebugger/NO_HW_COMBINER_RESOURCES_WARNING=false
+mdbDebugger/NO_HW_BP_RESOURCES_WARN=false
+mdbDebugger/MEMORY_VIEW_NO_HW_BP_RESOURCES_WARN=false
+pk3/CHECK_CLOCK=false
+mdbDebugger/LAST_HW_BP_RESOURCE_WARN=false
+pk3/CHECK_4_HIGH_VOLTAGE_VPP=false
+icd3/DEVID_MISMATCH=false
+realice/DEVID_MISMATCH=false
+realice/CHECK_CLOCK=false
+pkoblicdbgr/DEVID_MISMATCH=false
+pkoblicdbgr/CHECK_CLOCK=false
+pkobskde/DEVID_MISMATCH=false
+icd3/CHECK_CLOCK=false
+realice/CHECK_4_HIGH_VOLTAGE_VPP=false
+pkoblicdbgr/CHECK_4_HIGH_VOLTAGE_VPP=false
+pkobskde/CHECK_CLOCK=false
+icd3/CHECK_4_HIGH_VOLTAGE_VPP=true
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<configurationDescriptor version="62">
+ <projectmakefile>Makefile</projectmakefile>
+ <defaultConf>0</defaultConf>
+ <confs>
+ <conf name="default" type="2">
+ <platformToolSN>:=MPLABCommUSB:=04D8:=9009:=0100:=Microchip Technology, Inc. (www.microchip.com):=MPLAB ICD3 tm (www.microchip.com):=JIT123410560:=x:=en</platformToolSN>
+ <languageToolchainDir>/opt/microchip/mplabx/mpasmx</languageToolchainDir>
+ <mdbdebugger version="1">
+ <placeholder1>place holder 1</placeholder1>
+ <placeholder2>place holder 2</placeholder2>
+ </mdbdebugger>
+ <runprofile version="6">
+ <args></args>
+ <rundir></rundir>
+ <buildfirst>true</buildfirst>
+ <console-type>0</console-type>
+ <terminal-type>0</terminal-type>
+ <remove-instrumentation>0</remove-instrumentation>
+ <environment>
+ </environment>
+ </runprofile>
+ </conf>
+ </confs>
+</configurationDescriptor>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><project-private xmlns="http://www.netbeans.org/ns/project-private/1">
+ <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
+</project-private>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://www.netbeans.org/ns/project/1">
+ <type>com.microchip.mplab.nbide.embedded.makeproject</type>
+ <configuration>
+ <data xmlns="http://www.netbeans.org/ns/make-project/1">
+ <name>mybootload</name>
+ <creation-uuid>dc4e0df1-dbee-4df1-977e-9dfb5bf3e19a</creation-uuid>
+ <make-project-type>0</make-project-type>
+ <c-extensions/>
+ <cpp-extensions/>
+ <header-extensions/>
+ <sourceEncoding>UTF-8</sourceEncoding>
+ <make-dep-projects/>
+ </data>
+ </configuration>
+</project>
--- /dev/null
+RoundResult SET 0 ; Rounding function. RoundResult = Round(aa/bb)\r
+Round macro aa,bb\r
+ LOCAL rr = aa/bb\r
+ LOCAL d1 = aa - rr*bb\r
+ LOCAL d2 = (rr+1)*bb - aa\r
+RoundResult = rr\r
+ if d1 >= d2\r
+RoundResult++\r
+ endif\r
+ endm\r
+\r
+AbsResult SET 0\r
+Abs macro nr\r
+ if nr>=0\r
+AbsResult = nr\r
+ else\r
+AbsResult = -nr\r
+ endif\r
+ endm\r
+ \r
+ Round xtal,(16*baud)\r
+spbrg_value EQU RoundResult-1\r
+\r
+ Round xtal,(16*(spbrg_value+1))\r
+baud_real EQU RoundResult\r
+ Abs(baud_real-baud)\r
+errpercent EQU AbsResult*100/baud\r
+ if errpercent > 4\r
+ ERROR big error in baudrate: #v(errpercent)%\r
+ endif\r
+ if errpercent >= 2\r
+ messg baudrate not exact: #v(errpercent)%\r
+ endif
\ No newline at end of file