\ -*- forth -*- \ Boot code for PIC18 chips. \ Misc stuff to remember when configuring chip \ - disable watchdog timer if the code does not use CLWDT \ - set power up timer (or use capacitor + reset enabled) \ - disable MCLR pin, or use a reset switch with pullup resistor \ Data memory \ Note that the extended 18f instruction set allows the use of indexed \ addressing relative to FSR2, which can enable cheap structs/objects. \ however, it disables global (access bank) variables for the region \ 0x000-0x05F, which makes that region better suited for stack memory \ if the extensions are used, so the contiguous space after 0x80 could \ be used as object memory, leaving the space 0x60-7F for global \ variables. \ in short, indexed addressing? \ no -> stacks in 0x80 - 0xFF, globals in 0x00 - 0x7F \ yes -> stacks in 0x00 - 0x5F, globals in 0x60 - 0x7F \ you'll have to configure this in a config seed, values are used below \ note that bank selecting is not used. it sucks, one can do without \ * INDF0 the data stack \ * INDF1 the control/temp stack (x) \ * STKPTR the hardware return stack (r) \ redefine these: \ : stack-data #x80 ; \ : stack-control #x90 ; \ stack init code macro : init-rs 0 movlw STKPTR movwf ; \ RS : init-ds stack-data 1 - 0 lfsr ; \ DS : init-xs stack-control 1 - 1 lfsr ; \ CS : init-stacks init-ds init-xs init-rs ; forth \ util macro : kHz 1000 * ; : MHz kHz kHz ; forth \ macros for chip setup. this needs to be cleaned up a bit.. but maybe \ this approach is better even? all the setup code is defined in \ macros, and you simply instantiate the macro in your boot code. all \ nice and explicit. \ these default to all output, which is good enough for testing. macro \ will be redefined when the correct machine is loaded \ : TRISA undefined ; \ : TRISB undefined ; \ : TRISC undefined ; \ : TRISD undefined ; \ : TRISE undefined ; : 2-output 0 TRISA ! 0 TRISB ! ; : 3-output 2-output 0 TRISC ! ; : 5-output 3-output 0 TRISD ! 0 TRISE ! ; forth \ The main idea of a boot loader during development is that it is \ robust: it should be impossible to mess up the boot process while \ poking around; it should always be possible to gain access to the \ device through the built-in interpreter. \ On the other hand, d\uring deployment, it should be possible to \ erase or fuse the boot block to disable all access to the \ interpreter. \ The boot block should be universal enough so that it has to be \ flashed only once. All unnecessary features need to be moved to \ the application (or os kernel) source. \ These requirements lead to the following solutions: \ - booting never bypasses the debug check (serial idle / break) \ - ISRs are passed to the block following the boot block \ - first 64 K are clean of core code (to enable fusing) \ - boot code is strictly read-only \ Jump to boot loader, and install ISR patched to block at app-boot app-boot org : application app-boot #x08 + org : isr-high app-boot #x18 + org : isr-low #x0000 org : boot boot-40 ; #x0008 org : boot-isr-high isr-high ; #x0018 org : boot-isr-low isr-low ; \ It is possible to install a custom boot loader by overwriting block \ 0. For robustness, it is allowed for block 0 (the first 64 bytes == \ first flash erase unit) to be empty, meaning it contains only #xFFFF \ NOP instructions. the code will fall into this word, at the start of \ block 1. #x0040 org : boot-40 warm ; \ Boot loader code starts here. \ Set the ram allocation pointer. \ allot-ram dict ram