201303110835


Содержание.

  0. Введение
  1. Эллочка-людоедка
  2. Nomen est Omen
  3. Где заканчивается предложение?
  4. Операции
  5. Сленг
  6. Что делает компилятор?
  7. Функция задержки delay_ms()
  8. Прерывания (руководство пользователя MikroC v.6)
  9. Литература
  Приложение А. Некоторые типы переменных в C.
  Приложение Б. Некоторые операции с числами в C.
  Приложение В. Шаблоны для copy-paste в исходник программы, 
                P16F676, PicKit Classic 1
  Appendix G.   Prehistory


0. Введение

Дальнейшее изучение микропроцессорной техники связано с поиском ответа на вопрос "Как это работает?". Для этого предлагается пройти через несколько этапов (уровней).

Можно, оставаясь на начальном уровне, изучать симуляции (в среде симулятора Siemens Logo!) составных частей электронно- вычислительной машины и структур данных: АЛУ, ОЗУ, аппаратные стек, очередь, связанный список, двоичное дерево и так далее. Можно поискать прямой ответ разобрав контроллер. Сразу оговорюсь, что внутри мы увидим микросхему микроконтроллера - например:
 
Microchip PIC - он прежде всего интересен простотой изучения, обилием симуляторов: 

  - AQA (softwareforeducation.com/wikileki)
  - PicSimulatorIDE (oshonsoft.com)
  - Proteus (www.labcenter.com), 
  
поддержка HID USB (серия 945, не требует установки драйверов).
 
Аtmel AVR - высокая популярность, проект Arduino (arduino.cc), проект с открытыми исходными кодами - V-USB (www.obdev.at/products/vusb)

STM - дешевые средства разработки 32-х разрядных схем, перспективная платформа ARM (Cortex-M3,M4).


0.1 Программирование микроконтроллеров на языке C.

В статье "Микропроцессоры. Level 1" мы познакомились с упрощенным вариантом PIC процессора на примере симулятора AQA. Реально выпускаемые чипы намного сложнее, их наборы команд содержат десятки а то и сотни инструкций, и если это вас не останавливает, то процессоров с разными наборами команд много, очень много - сотни.
 
К счастью человечество не в первый раз сталкивается с явлением фрагментации - "мы понаделаем огромное количество весьма разных решений почти одной и той же задачи. Одна из доминирующих целей - не дать одному человеку откусить слишком большой кусок пирога". В 60е годы 20-го столетия понаделали столько разных компьютеров, что не хватало программистов, согласных писать для них программы.

К счастью нашлась тройка смельчаков, создавших язык C и операционную систему (программу для запуска и выполнения других программ) UNIX, которые можно было с легкостью (за недели) переносить на новые платформы (Кто в 1970 году слышал об iPhone или роботах-андроидах Asimo от Honda? Сегодня программное обеспечение этих и многих других устройств выполнено на языке C в Unix-подобных системах.).
 
В данной серии занятий мы, на примере микроконтроллера Microchip PIC P16F676 напишем несколько примеров программ на ограниченном подмножестве языка С. Если под рукой нет чипа и программатора, можно поиграть с симуляторами, например подойдут связки программ
  
  1. - mikroC (www.mikroe.com, Белград, Сербия)
     - picsimulatoride (oshonsoft.com, Владимир Сосо, Земун,
       Сербия)
     - disasm104 (www.hagi-online.org, Norbert Hagemann, 
                  Berlin, Deutchland)
     (подойдут системы windows или wine/unix);
      
  2. gputils, gpsim - sdcc (больше подходит Unix);
   
  3. MPLabX/C - Proteus (для знатоков).
  
В дальнейшем можно будет безболезненно переити к чипу STM32 (ARM, Cortex), а оттуда к более массовым ARM или x86 устройствам (дигибоксы, смартофоны, планшеты, автоэлектроника, робототехника и т.д.).

В примерах используется связка 1, установленная на виртуальной машине VirtualaBox - Fedora LXDE v.18, выложенной для скачивания на сайте http://nelus.tpt.edu.ee. Несколько слов о том, как создать среду для программирования микроконтроллеров PIC на ее основе.

  1. Устанавливаем нужные пакеты

     sudo yum update
     sudo yum install make automake gcc-c++ kernel-devel
     sudo yum install wine

  2. Устанавливаем VirtualBox Guest Additions

     Devices -> Install Guest Additions

     sudo -s
     mkdir -p /mnt/cdrom
     mkdir -p /mnt/vbox
     mount -o ro /dev/cdrom /mnt/cdrom
     cd /mnt/cdrom
     ./VBoxLinuxAdditions
     umount /dev/cdrom

     Проверяем

     Devices -> Shared Folders -> Add

        x:\tmp name tmp

     mount -t vboxsf tmp /mnt/vbox

  3. Скачиваем mikroC (mikroE.com), picsimulatoride (oshonsoft.com) и Disassembler 104.zip (www.talkingelectronics.com/Download/picdisasm104.zip) и устанвливаем:

       wine setup-mikroc-600.exe
       wine picsimulatoride.exe
       unzip picdisasm104.zip; wine PicDisasm.exe

  4. В папку /home/virtu/.wine/drive_c/windows/system32/ распаковываем архив vb6sp6-wine.tar.bz2 доступный на сайте nelus.tpt.edu.ee (при желании можете сделать его сами - распакуйте например winrar-ом vbrun6sp6.exe, добавьте в папку comdlg32.ocx)

       cd /home/virtu/.wine/drive_c/windows/system32
       tar xvf /home/virtu/Downloads/vb6sp6-wine.tar.bz2

Пришло время перезагрузить виртуальную машину: 

  sudo init 6
  заходим руто'м

Стереть все, что связано с устаревшим ядром

  rpm -qa | grep kernel
  yum remove kernel-...
  rm -rf /lib/modules/kernel...
  yum autoremove
  yum clean all

забить нулями свободное пространство на виртуальном жестком диске

  dd if=/dev/zero of=biig
  rm -f biig

и выключить виртуальную машину

  init 0

В хосте желательно сделать резервную копию с архивом жесткого диска виртуальной машины либо ova-файл (стандартная миграция всей виртуальной машины одним щелчком, export appliance).

Наконец мы начинаем то, что хотели - программировать микроконтроллер на C.


1. Эллочка-людоедка
   ----------------

          Словарь Вильяма Шекспира, по подсчету исследователей,
          составляет 12 000 слов. Словарь негра из людоедского
          племени "Мумбо-Юмбо" составляет 300 слов. Эллочка 
          Щукина легко и свободно обходилась тридцатью.
          
                Илья Ильф и Евгений Петров. Двенадцать стульев
                
Для того, чтобы написать на незнакомом языке что-нибудь полезное не нужно знать весь язык. Аудитория языка C это по-крайней мере трое - компьютерное устройство, на котором будет исполнятся ваша программа, программа-переводчик с человеческого (C) языка на машинный (двоичные коды), и программист (включая автора программы через некоторый промежуток времени, достаточный для того, чтобы забыть, что эта программа делает и как она работает).

Вторая половина фразы - это  _к_о_м_м_е_н_т_а_р_и_и_,  все, написанное правее символов // и до конца строки - предназначено людям, читающим эту программу, машина этот текст не воспринимает. Тут уместно сказать, что часто, после ряда изменений в тексте программы комментарий оказывается никак не связанным, или хуже того, противоречащим тексту программы. Поэтому лишние комментарии - это зло.

В языки, предназначенные для общения человека с человеком, почти всегда "зашиты" пространство и время: "Справа вдалеке виднелась опушка липовой рощи. Летом она зазеленеет и воздух наполнится благоуханиями цветущих деревьев (если, конечно к тому времени ее не спилят).". В языке C мы можем объединить части кода в пространстве с помощью комбинации слова struct и фигурных скобок {}, например так

  struct empty {
    // Я помню чудное мгновенье: 
    // Передо мной явилась ты, 
    // Как мимолетное виденье, 
    // Как гений чистой красоты.
  } 

или во времени - задав последовательность выполнения фрагментов программы с помощью _б_л_о_к_а_ {}:

  void main() {
  }
  
слово main - это функция, которая в простейшем случае выполняется первой, void означает, что она ничего не возвращает, а (), что ничего не спрашивает на входе (аргументы отсутствуют). Вот примеры на разных языках:

  русский:  Возьмите морковку и натрите ее теркой
  english:  Take a carrot and grate it
  C:        salad = grater( carrot)
  
  электротехника
  
     +--------------------+
     |     GND            |
  +-(+)----(-)-+          |
  | 1.5 вольта |        +-+-+
  +------------+  GND o-+  1|
   вход 1 Вольт         |   o-- Выход (1 Вольт)
     +------------------+   |
     |     GND          +-+-+
  +-(+)----(-)-+          |
  |   1 Вольт  |         GND (земля, заземление)
  +------------+


2. Nomen est Omen
   --------------
   
В компьютере есть множество ячеек памяти, хранящих биты (0 или 1). Обращение к ним может иметь целью запись, либо чтение. При этом мы должны знать адрес ячейки, например

  10001110101010100011100 бит 101011

от LSB. Человеку иметь дело с таким адресом неудобно, поэтому везде, где это возможно программа-переводчик ставит некоторую цифру в соответствие некоторому имени (простейший пример - телефонная книга).

Если по этому адресу в памяти расположены данные - то это переменная, если исполнимый код - метка либо функция (так называемая точка входа). В примере с морковкой grater - имя функции (программа-переводчик, она же компилятор, позаботится о том, чтобы ей был назначен адрес точки входа в памяти устройства), carrot, salad - имена переменных (опять-же компилятор снабдит все переменные адресами в памяти устройства).

Что еще, из того что мы знаем (помимо русского языка) пригодится для изучения программирования? Правильно, арифметика. Пометив адреса в памяти именами мы подошли к понятию переменных. 

Помимо имени еще неплохо знать какой объем памяти нужно отвести для переменной, или как говорят, ее тип. Поначалу будем считать все переменные длиной в один байт (8 бит). Знать кому? Если это C, то программисту. Если Python, Perl или PHP, наш помошник (программа-переводчик, в данном случае она называется интерпретатор) может вполне с этим справиться ... если в нашем устройстве много памяти. Впрочем, сегодня не 1969 год и на двух килобайтах перепрограммируемой памяти никто на Луну не летает (туда вообще никто не летает).

Третье, что важно при работе с переменной, это значение хранимой в ней информации. Используем для записи информации в переменную символ "=", не забывая о том, что его смысл не тот, что в математике, например:

  x = x + 1
  
означает прибавь к числу хранящемуся по адресу x единицу и запиши его обратно.


3. Где заканчивается предложение?
   ------------------------------

В С это не точка, а точка с запятой, например:

  x = x + 1;
  
Итак изучение подмножества языка С (диалект Эллочки Щукиной) подходит к концу. Попробуем вычислить факториал, ограничив язык рассмотренной частью:

  #include <stdio.h>

  char fact(char ax) {
    char y = 1;
    (ax <= 1) || (y = ax * fact(ax - 1));
    return y;
  }

  void main() {
    printf("%d\n", fact(4));
  }                                    

незнакомые слова:
  
  char     - тип переменной или возвращаемое значение функции ограничено одним байтом.
  
  return f - значение функции, возвращаемое при ее вызове.


4. Операции
   --------

Операции с переменными удобно разбить по категориям. Для числовых данных это арифметика, логика, операции сравнения и операции с отдельными битами. В вычислениях при помощи операций важно знать:

  - как читать выражение - слева направо, справа налево или как-нибудь иначе (например снизу вверх).
    
  - стоит ли вообще просматривать (parse) выражение до конца если результат уже ясен (lazy evaluation).
    
  - порядок выполнения операций (priority table), не столь существенно, поскольку мы можем изменить порядок выполнения с помощью скобок.


5. Сленг
   -----
                           Да пошел ты ... (Da poshel ty ...)
                           Da, ya posol.   (Да, я посол.)

Язык mikroC не вполне C. Вначале стандартный язык упрощается, на полученный скелет (рыбу) навешиваются новые украшения, облегчающие программирование именно _м_и_к_р_о_ - систем (не случайно такое название). Поскольку желающих говорить на C языком Шекспира меньше, чем тех, кто просто хочет свой труд автоматизировать - не будем останавливаться на изучении тех тонкостей языка, которые нам не нужны здесь и немедленно.

Пример с факториалом выше работает и написан на стандартном диалоге языка C, но не работает в mikroC. И дело тут вовсе не в таинственной функции printf, описанной в заголовочном файле stdio.h. Попытка построить проект приводит к совсем другим ошибкам:
 
  Line          Message Nr Message text
  -------------------------------------------------------------
  char fact( .. 364        Recursion or cross-calling of 'fact'
                433        Not enough RAM for call stack
                      
Ясно - рекурсия, генераторы, итераторы и прочие модные штучки здесь не в почёте. 
          
Вернемся назад лет на шестьдесят. До боли знакомый по level 1 оператор goto c метками по тем же правилам:

                goto   label_0123
                . . .
  label_0123:   return 45;

Выбрать, куда пойти, поможет операция "?":

                 2 > 3 ? goto YES_TRUE : goto NO_FALSE ;
                 ...
    YES_TRUE:    ...
                 ...
    NO_FALSE:    ...
 
Теперь в языке достаточно выразительных средств для того, чтобы изучать блок схемы: 193x годы, механические компьютеры Конрада Цузе (Konrad Zuse), Алонзо Чёрч (Alonzo Church) с его лямбда-исчислением (lambda calculus). Классика.


6. Что делает компилятор?
   ----------------------

Забудем на время нехорошую фразу - "компилятор делает простое сложным". Не всегда нужно разбираться в сложной части проекта. Так называемый подход "скрытой сложности" Гради Буча - "Нажми на кнопку - получишь результат". 

Пример 1.

  mikroC -> New Project -> MyProject:
  
  processsor PIC p16f676
  include all
  do not add any files
  
  MyProject.c:
  
  void main() {
    TRISB = 0xF8;
    PORTB = 0x07;
  }
  
  picsimulatoride -> load program (MyProject.hex)
                  -> disassembler
                  
  -----------------------------------
  PIC DISASSEMBLER LISTING
  Address Opcode  Instruction
  -----------------------------------
  0000    2815        GOTO L1
  0001    3FFF        ADDLW 0xFF
  0002    3FFF        ADDLW 0xFF
  0003    1283    L2: BCF STATUS,RP0
  0004    0821        MOVF 0x21,W
  0005    008A        MOVWF PCLATH
  0006    0820        MOVF 0x20,W
  0007    0082        MOVWF PCL
  0008    0008        RETURN
  0009    2003    L3: CALL L2
  000A    118A        BCF PCLATH,3
  000B    120A        BCF PCLATH,4
  000C    0080        MOVWF INDF
  000D    0A84        INCF FSR,F
  000E    0AA0        INCF 0x20,F
  000F    1903        BTFSC STATUS,Z
  0010    0AA1        INCF 0x21,F
  0011    03D0        DECF 0x50,F
  0012    1D03        BTFSS STATUS,Z
  0013    2809        GOTO L3
  0014    0008        RETURN
  0015    30F8    L1: MOVLW 0xF8
  0016    1683        BSF STATUS,RP0
  0017    0085        MOVWF 0x05
  0018    3007        MOVLW 0x07
  0019    1283        BCF STATUS,RP0
  001A    0085        MOVWF 0x05
  001B    281B    L4: GOTO L4
  
Программа не может вернуть имена меток, переменных, точек входа. Читается с трудом (надо иметь под рукой заголовочный файл p16f676.h). Более мощный дизассемблер 104 дает нам следующий результат. Вот тут уже интересно будет откомментировать этот файл вручную.

  PicDisasm.exe (disassembler 104)
  
  ; original File = Z:\home\virtu
  ; \.wine\drive_c\Program Files\disasm104\MyProject.hex

    processor 16F676
    #include <P16F676.INC>
    __config 0x31F2
  ;   _CPD_OFF & 
  ;   _CP_OFF & 
  ;   _BODEN_ON & 
  ;   _MCLRE_ON & 
  ;   _PWRTE_OFF & 
  ;   _WDT_OFF &
  ;   _HS_OSC 

  ; RAM-Variable
  LRAM_0x20 equ 0x20
  LRAM_0x21 equ 0x21
  LRAM_0x50 equ 0x50

  ; Program

      Org 0x0000

  ;   Reset-Vector
      GOTO LADR_0x0015

      Org 0x0003

  LADR_0x0003
      BCF STATUS,RP0       ; BANK0
  ;   Interrupt-Vector     
      MOVF LRAM_0x21,W     
      MOVWF PCLATH         ; PCLATH = LRAM_0x21
      MOVF LRAM_0x20,W     
      MOVWF PCL            ; PCL    = LRAM_0x20
      RETURN
      
  LADR_0x0009
      CALL LADR_0x0003
      BCF PCLATH,3         ; PCLATH.3 = 0 (MSB76543210LSB)
      BCF PCLATH,4         ; PCLATH.4 = 0 (MSB76543210LSB)
      MOVWF INDF           ; W = INDF
      INCF FSR,F           ; [FSR] = [FSR] + 1
      INCF LRAM_0x20,F     ; [LRAM_0x20] = [LRAM_0x20] + 1
      BTFSC STATUS,Z       ; skip if ([LRAM_0x20] != 0) yet
      INCF LRAM_0x21,F     ; [LRAM_0x21] = [LRAM_0x21] + 1
      DECF LRAM_0x50,F     ; [LRAM_0x50] = [LRAM_0x50] - 1
      BTFSS STATUS,Z       ; skip if [LRAM_0x50] == 0 yet
      GOTO LADR_0x0009
      RETURN
      
  LADR_0x0015              ; main()
      MOVLW 0xF8
      BSF STATUS,RP0       ; BANK1
      MOVWF PORTA          ; TRISA = 0xF8
      MOVLW 0x07
      BCF STATUS,RP0       ; BANK0
      MOVWF PORTA          ; PORTA = 0x07
      
  LADR_0x001B
      GOTO LADR_0x001B     ; infinite loop

      End
      
Даже если учесть, что все, начиная с LADR_0x0003 по LADR_0x0015 нам сейчас никак не пригодится, с роботом в паре работать гораздо быстрее и легче, чем все это писать вручную, особенно колонку Opcode в листинге дизассемблера от picsimulatoride. А ведь это и есть то что мы только что написали, но на языке микроконтроллера p16f676:

  2815 3FFF 3FFF 1283 0821 008A 0820 0082 0008 2003 118A 120A
  0080 0A84 0AA0 1903 0AA1 03D0 1D03 2809 0008 30F8 1683 0085
  3007 1283 0085 281B


7. Функция задержки delay_ms()

В среде mikroC для замедления переключения периферийных устройств, удобно воспользоваться функцией задержки delay_ms. Проделаем ту-же работу, что и в предыдущей главе, скомпилировав а затем дизассемблировав файл, содержащий обращение к данной функции: 

                mikroC v6               disasm 104
    myproject.c --------> myproject.hex ---------> myproject.asm
    
  ;  delay_ms(100)
  ;  delay_ms(1000)

  ; DELAY_MS 100
      MOVLW 0x21
      MOVWF LRAM_0x5C
      MOVLW 0x76
      MOVWF LRAM_0x5D
  LADR_0x001F
      DECFSZ LRAM_0x5D,F
      GOTO LADR_0x001F
      DECFSZ LRAM_0x5C,F
      GOTO LADR_0x001F

      NOP
      
  ; DELAY_MS 1000    
      MOVLW 0x02
      MOVWF LRAM_0x5B
      MOVLW 0x45
      MOVWF LRAM_0x5C
      MOVLW 0xA9
      MOVWF LRAM_0x5D
  LADR_0x002A
      DECFSZ LRAM_0x5D,F
      GOTO LADR_0x002A
      DECFSZ LRAM_0x5C,F
      GOTO LADR_0x002A
      DECFSZ LRAM_0x5B,F
      GOTO LADR_0x002A
        
Видим, что в hex файле функции delay_ms как таковой не существует, в стандарте языка С++ такого эффекта можно добиться указав слева от имени функции префикс inline. Если функция будет вызвана 10 раз, то в каждое место вызова будет подставлено тело inline функции, удесятерив при этом длину созданного кода.


8. Прерывания (руководство пользователя MikroC v.6).

Прерывания могут быть легко обработаны с помощью зарезервированного слова interrupt. MikroC PRO для PIC неявно объявляет функцию interrupt, которая не может быть повторно объявлена (redeclared). Ее прототипом является:

  void interrupt(void);
  
MikroC PRO для PIC сохраняет следующие SFR (special function register) в стек, когда осуществляется вход в код прерывания и извлекает их по возвращении:

  - PIC12 family: W, STATUS, FSR, PCLATH
  - PIC16 family: W, STATUS, FSR, PCLATH 
  
Используйте #pragma disable context saving чтобы поручить компилятору не осуществлять автоматического переключения контекста. Это означает, что регистры не будут сохранены / восстановлены на входе в / выходе из прерывания. Это позволяет пользователю вручную написать код для сохранения регистров на входе и восстановить их до выхода из прерывания.


Вызовы функций из прерывания

В новой версии возможны вызовы функций в теле interrupt(). Компилятор заботится о сохранении и восстановлении состояния используемых регистров, как внутри прерывания, так и в основном потоке, и выполняет "умное" (smart) переключение контекста между ними, сохраняя только те регистры, которые были использованы в обоих потоках. Проверьте генерируемый код функций на реентерабельность (Check functions reentrancy).


Прерывания. Примеры

Вот простой пример обработки прерывания от TMR0 (если нет других прерываний):

  void interrupt() {
    counter++;
    TMR0 = 96;
    INTCON = $20;
  }
  
В случае множественных прерываний, необходимо проверить, какое прерывание произошло, а затем приступить к исполнению соответствующего кода (обработка прерываний):

  void interrupt() {
    if (INTCON.T0IF) {
      counter++;
      TMR0 = 96;
      INTCON.TMR0F = 0;
    }
    else if (INTCON.RBIF) {
      counter++;
      TMR0 = 96;
      INTCON.RBIF = 0;
    }
  }


9. Литература

  1. Брайан Керниган, Денис Ритчи.  Язык С.  1978

  2. Гради Буч.  Объектно-ориентированный анализ и проектирование с примерами приложений, 3-е издание, 2008

----------

Приложение А. Некоторые типы переменных в C.

  тип              длина переменной   диапазон значений
  --------------------------------------------------------
  char             1 байт                 -128 .. +127
  short            2 байта              -32768 .. +32568
  long             4 байта            -2**31+1 .. +2**31-1
  long long        8 байт             -2**63+1 .. +2**63-1
   
  Примечание: ** в степени.
   
----------

Приложение Б. Некоторые операции с числами в C.

Общее

  Операция   Описание                       Примеры     Ответ
  -----------------------------------------------------------
  =          присваивание                   x = 0xFF
                                            y = 0x01
  ()         изменение порядка вычисления   (2 + 3) * 4
  []         индекс массива                 w[1] = w[0]
                                            
Арифметика                                  
                                            
  Операция   Описание                       Примеры  
  -----------------------------------------------------------
  +          сложение                       a = 3 + a
  -          вычитание                      b = 5 - 2
  *          умножение                      c = 3 * 4
  /          деление                        d = 9 / 3
  %          остаток от деления нацело      e = 7 % 4   3
  
Логика

  Операция   Описание (true 0x1 false 0x0)  Примеры  
  -----------------------------------------------------------
  ||         или                            2 || 3      1
  &&         и                              2 && 0      0
  !          не                             !!99        1
  
Сравнения

  Операция   Описание                       Примеры  
  -----------------------------------------------------------
  <          меньше                         2 <  3      1
  <=         меньше либо равно              2 <= 3      1
  ==         равно ли ?                     4 == 5      0
  >=         больше либо равно              2 >= 3      0
  >          больше                         2 >  3      0
  
Побитные операции

  Операция   Описание                       Примеры     char
  -----------------------------------------------------------
  <<         сдвиг влево                    127 << 2    252
  >>         сдвиг вправо                   7 >> 1      3
  ~          побитная инверсия              ~0xf8       7
  &          побитное "И"                   6 & 10      2
  |          побитное "ИЛИ"                 6 | 10      14
  ^          побитное "исключающее или"     6 ^ 15      9

----------

Приложение В. Шаблоны для copy-paste, P16F676, PicKit Classic 1

Cut-Paste Source Templates (PIC16F676)

----------

  STATUS -- STATUS REGISTER (ADDRESS: 03h OR 83h)

  7------- IRP: This bit is reserved. Read as '0'
  |6------ RP1: This bit is reserved, read as '0'
  ||5----- RP0: Bank Select: 0 Bank 0 (0-7F) 1 Bank 1 (7F-FF)
  |||4---- !TO: Time-out: 1 Power-up, CLRWDT / SLEEP. 0 WDT
  ||||3--- !PD: Power-Down: 1 Power-up / CLRWDT. 0 SLEEP
  |||||2-- Z: Zero (1 - result is 0)
  ||||||1- DC: Digit carry/!borrow (ADDWF,ADDLW,SUBLW,SUBWF)
  76543210 C: Carry/!borrow (ADDWF,ADDLW,SUBLW,SUBWF)
                 
  ----------

  OPTION_REG -- OPTION REGISTER (ADDRESS: 81h)

  7        !RAPU: PORTA Pull-up Enable: 1 - disabled 0 - enabled
  |6       INTEDG: Interrupt Edge Select: 1. 0->1  2. 1->0
  ||5      T0CS: TMR0 Clock Source: 1. RA2/T0CKI  0. CLKOUT
  |||4     T0SE: TMR0 Source Edge 1. 1->0  0. 0->1 on RA2/T0CKI
  ||||3    PSA: Prescaler Assignment: 1. WDT  0. Timer0
  |||||2   PS2: Prescaler Rate Select bits:
  ||||||1  PS1:   TMR0: 000 1:2. 001 1:4 ... 111 1:256
  76543210 PS0:   WDT:  000 1:1. 001 1:2 ... 111 1:128

  ----------

  INTCON -- INTERRUPT CONTROL REGISTER (ADDRESS: 0Bh OR 8Bh)

  *)  T0IF bit is set when Timer0 rolls over. Timer0 is unchanged 
      on RESET and should be initialized before clearing T0IF bit
  **) The RA2/INT external interrupt must be cleared in software
  *+) When at least one of the PORTA <5:0> pins changed state 
     (must be cleared in software)

  7        GIE: Global Interrupt Enable: 1 Enable. 0 Disable
  |6       PEIE: Peripheral IE: 1 Enable. 0 Disable
  ||5      T0IE: TMR0 Overflow IE: 1 Enable. 0 Disable
  |||4     INTE: RA2/INT External IE: 1 Enable. 0 Disable
  ||||3    RAIE: Port Change IE: 1 Enable. 0 Disable. Enable IOCA
  |||||2   T0IF: TMR0 Overflow Interrupt Flag*: 1 TMR0 overflowed
  ||||||1  INTF: RA2/INT External Interrupt Flag: 1 occured**
  76543210 RAIF: Port Change Interrupt Flag: 1 *+

  ----------

  PIE1 -- PERIPHERAL INTERRUPT ENABLE REGISTER 1 (ADDRESS: 8Ch)

  7        EEIE: EE Write Complete Interrupt Enable: 1 En. 0 Dis.
  |6       ADIE: A/D Converter Interrupt Enable: 1 En. 0 Dis.
  ||5      Unimplemented: Read as '0'
  |||4     Unimplemented: Read as '0'
  ||||3    CMIE: Comparator Interrupt Enable: 1 En. 0 Dis.
  |||||2   Unimplemented: Read as '0'
  ||||||1  Unimplemented: Read as '0'
  |||||||0 TMR1IE: TMR1 Overflow Interrupt Enable: 1 En. 0 Dis.

  ----------

  PIR1 -- PERIPHERAL INTERRUPT REGISTER 1 (ADDRESS: 0Ch)

  *) must be cleared in software
         
  7        EEIF: EEPROM Write Op. Interrupt Flag: 1 Completed*
  |6       ADIF: A/D Converter Interrupt Flag: 1 Complete  0 No
  ||5      Unimplemented: Read as '0'
  |||4     Unimplemented: Read as '0'
  ||||3    CMIF: Comparator Interrupt Flag: 1 input changed* 0 No
  |||||2   Unimplemented: Read as '0'
  ||||||1  Unimplemented: Read as '0'
  76543210 TMR1IF: TMR1 Overflow Int-pt Flag: 1 TMR1 overflowed*

  ----------

  PCON -- POWER CONTROL REGISTER (ADDRESS: 8Eh)

  *)  must be cleared in software
  **) must be set in software

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5      Unimplemented: Read as '0'
  |||4     Unimplemented: Read as '0'
  ||||3    Unimplemented: Read as '0'
  |||||2   Unimplemented: Read as '0'
  ||||||1  !POR: PowerOn Reset STATUS bit: 1 No  0 POR occurred*
  76543210 !BOD: BrownOut Detect STATUS bit: 1 No 0 BOD occured**

  ----------

  OSCCAL -- INTERNAL OSCILLATOR CALIBRATION (ADDRESS: 90h)

  7         CAL5: 6-bit Signed Oscillator Calibration bits
  |6        CAL4:
  ||5       CAL3:   111111 = Maximum frequency 
  |||4      CAL2:   100000 = Center frequency
  ||||3     CAL1:   000000 = Minimum frequency
  |||||2    CAL0: 
  ||||||1   Unimplemented: Read as '0'
  76543210  Unimplemented: Read as '0'

  ----------

  PORTA -- PORTA REGISTER (ADDRESS: 05h)

  7         Unimplemented: Read as '0'
  |6        Unimplemented: Read as '0'
  ||5
  |||4      PORTA<5:0>
  ||||3     
  |||||2    PORTA I/O pin: 1 Port pin is >VIH 0  Port pin is <VIL
  ||||||1
  76543210 

  ----------

  TRISA -- PORTA TRISTATE REGISTER (ADDRESS: 85h)

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5
  |||4     TRISA<5:0>
  ||||3    PORTA Tri-State Control bit: 1 PORTA pin configured as
  |||||2   an input (tri-stated) 0 PORTA pin configured as an 
  ||||||1  output
  76543210 Note:     TRISA<3> always reads 1. 
           
  ----------

  WPUA -- WEAK PULL-UP REGISTER (ADDRESS: 95h)

  Note 1: Global RAPU must be enabled for individual pull-ups to
          be enabled.
       2: The weak pull-up device is automatically disabled if 
          the pin is in Output mode (TRISA = 0).

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5      WPUA<5:4>: Weak Pull-up Register bit
  |||4       1 = Pull-up enabled  0 = Pull-up disabled
  ||||3    Unimplemented: Read as '0'
  |||||2   WPUA<2:0>: Weak Pull-up Register bit
  ||||||1    1 Pull-up enabled 0 Pull-up disabled
  76543210 

  ----------

  IOCA -- INTERRUPT-ON-CHANGE PORTA REGISTER (ADDRESS: 96h)

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5      IOCA<5:0>: Interrupt-on-Change PORTA Control bit
  |||4       1 Interrupt-on-change enabled
  ||||3      0 Interrupt-on-change disabled
  |||||2   
  ||||||1  Note: Global interrupt enable (GIE) must be 
  76543210 enabled for individual interrupts to be recognized.

  ----------

  PORTC -- PORTC REGISTER (ADDRESS: 07h)

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5     
  |||4     PORTC<5:0>: General Purpose I/O pin
  ||||3      1 Port pin is >VIH
  |||||2     0 Port pin is <VIL
  ||||||1
  76543210

  ----------

  TRISC -- PORTC TRISTATE REGISTER (ADDRESS: 87h)

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5      TRISC<5:0>: PORTC Tri-State Control bit
  |||4       
  ||||3      1 PORTC pin configured as an input (tri-stated)
  |||||2     0 = PORTC pin configured as an output                   
  ||||||1
  76543210

  ----------

  T1CON -- TIMER1 CONTROL REGISTER (ADDRESS: 10h)

  7       Unimplemented: Read as '0'
  |6      TMR1GE: Timer1 Gate Enable bit
  ||              If TMR1ON = 0:
  ||              This bit is ignored
  ||              If TMR1ON = 1:
  ||              1 = Timer1 is on if T1G pin is low
  ||              0 = Timer1 is on
  ||5     |T1CKPS1:T1CKPS0: Timer1 Input Clock Prescale Select
  |||4    |Prescale Value, 11 = 1:8  10 = 1:4  01 = 1:2  00 = 1:1 
  ||||3    T1OSCEN: LP Oscillator Enable Control bit
  |||||           If INTOSC without CLKOUT oscillator is active:
  |||||           1 = LP oscillator is enabled for Timer1 clock
  |||||           0 = LP oscillator is off
  |||||           Else:
  |||||           This bit is ignored
  |||||2   T1SYNC: Timer1 External Clock Input Synchronization
  ||||||          Control bit
  ||||||          TMR1CS = 1:
  ||||||          1 = Do not synchronize external clock input
  ||||||          0 = Synchronize external clock input
  ||||||          TMR1CS = 0:
  ||||||          This bit is ignored. 
  ||||||          Timer1 uses the internal clock.
  ||||||1  TMR1CS: Timer1 Clock Source Select bit
  |||||||         1 = External clock from T1OSO/T1CKI pin (on the 
  |||||||             rising edge)
  |||||||         0 = Internal clock (FOSC/4)
  |||||||0 TMR1ON: Timer1 On bit
  ||||||||        1 = Enables Timer1
  76543210        0 = Stops Timer1

  ----------

  CMCON -- COMPARATOR CONTROL REGISTER (ADDRESS: 19h)

  *)   CINV?(COUT?VIN+>VIN-:VIN+<VIN-):(COUT?VIN+>VIN-:VIN+<VIN-)
  **)  CIS?(CM2:CM0==110||101: VIN- connects to CIN+):(VIN- CIN-)
  ***) 000 Comparator Reset (POR Default Value - low power), 
       001 Comparator with Output on RA2/COUT, 
       010 Comparator without Output, 
       011 With Output and internal reference from CVREF module,
       100 Without Output but with internal reference,
       101 Multiplexed Input with Internal Reference and Output
       110 Multiplexed Input with Internal Reference no Output 
       111 Comparator Off (lowest power)                       

  7        Unimplemented: Read as '0'
  |6       COUT: Comparator output*
  ||5      Unimplemented: Read as '0'
  |||4     CINV: Comparator Output Inversion: 1 output inverted
  ||||3    CIS: Comparator Input Switch** 
  |||||2   
  ||||||1  CM2:CM0: Comparator Mode bits***
  76543210 

  ----------

  VRCON -- VOLTAGE REFERENCE CONTROL REGISTER (ADDRESS: 99h)

  7         VREN: CVREF Enable bit: 1 CVREF powered on 0 off
  |6        Unimplemented: Read as '0'
  ||5       VRR: CVREF Range Selection: 1 Low range  0 High range
  |||4      Unimplemented: Read as '0'
  ||||3     VR3:VR0: CVREF value selection 0 VR [3:0] 15
  |||||2    
  ||||||1     When VRR = 1: CVREF = (VR3:VR0/24)*VDD
  76543210    When VRR = 0: CVREF = VDD/4+(VR3:VR0/32)*VDD
                 
  ----------

  ADCON0 -- A/D CONTROL REGISTER (ADDRESS: 1Fh)

  *) Setting this bit starts an A/D conversion cycle. This bit is 
     automatically cleared by hardware when the A/D conversion 
     has completed.

  7        ADFM: A/D Result Formed Sel.: 1 Right 0 Left justified
  |6       VCFG: Voltage Reference: 1 VREF pin  0 VDD
  ||5      Unimplemented: Read as '0'
  |||4     CHS2:CHS0: Analog Channel Select bits:
  ||||3    000 AN0, 001 AN1, 010 AN2, 011 AN3, 100 AN4, 101 AN5
  |||||2   110 AN6, 111 AN7
  ||||||1  GO/!DONE: A/D Conversion STATUS bit: 0 completed*
  76543210 ADON: A/D Conversion STATUS: 1 A/D on  0 A/D shut-off

  ----------

  ADCON1 -- A/D CONTROL REGISTER 1 (ADRESS: 9Fh)

  7        Unimplemented: Read as '0'.
  |6      |ADCS<2:0>: A/D Conversion Clock Select bits
  ||5     |000 = FOSC/2  001 =   FOSC/8   010 =   FOSC/32
  |||4    |x11 =   FRC (clock derived from a dedicated internal 
  ||||3            oscillator = 500 kHz max)         
  |||||2   100 = FOSC/4  101 =   FOSC/16  110 =   FOSC/64
  ||||||1 
  76543210 3-0:     Unimplemented: Read as '0'.

  ----------

  ANSEL -- ANALOG SELECT REGISTER (ADRESS: 91h) (PIC16F676 ONLY)

  *) Setting a pin to an analog input automatically disables the 
     digital input circuitry, weak pull-ups and interrupt-on-
     -change if available. The corresponding TRIS bit must be set
     to Input mode in order to allow external control of the 
     voltage on the pin.
     
  7        ANS<7:0>: Analog Select between analog or digital
  |6       function on pins AN<7:0>, respectively.
  ||5        
  |||4       1 Analog input. Pin is assigned as analog input*.
  ||||3      0 Digital I/O. Pin is assigned to port or special
  |||||2       function.                                      
  ||||||1  
  76543210 

  ----------

  EEDAT -- EEPROM DATA REGISTER (ADDRESS: 9Ah)

  7        |
  |6       |
  ||5      |
  |||4     |EEDATn: Byte value to write to or read 
  ||||3    |from Data EEPROM
  |||||2   |
  ||||||1  |
  |||||||0 |                      

  ----------

  EEADR -- EEPROM ADDRESS REGISTER (ADDRESS: 9Bh)

  7        Unimplemented: Should be set to '0'
  |6       |
  ||5      |
  |||4     |
  ||||3    |EEADR: Specifies one of 128 locations for EEPROM
  |||||2   |             Read/Write Operation               
  ||||||1  |
  76543210 |

  ----------

  EECON1 -- EEPROM CONTROL REGISTER (ADDRESS: 9Ch)

  7        Unimplemented: Read as '0'
  |6       Unimplemented: Read as '0'
  ||5      Unimplemented: Read as '0'
  |||4     Unimplemented: Read as '0'
  ||||3    WRERR: EEPROM Error Flag bit:
  |||||      1 = A write operation is prematurely terminated 
  |||||          (any MCLR Reset, any WDT Reset during normal 
  |||||          operation or BOD detect)
  |||||      0 = The write operation completed
  |||||2   WREN: EEPROM Write Enable
  ||||||     1 = Allows write cycles
  ||||||     0 = Inhibits write to the data EEPROM
  ||||||1  WR: Write Control bit
  |||||||    1 = Initiates a write cycle (The bit is cleared 
  |||||||        by hardware once write is complete. The WR 
  |||||||        bit can only be set, not cleared, in software.)
  |||||||    0 = Write cycle to the data EEPROM is complete
  |||||||0 RD: Read Control bit
  ||||||||   1 = Initiates an EEPROM read (Read takes one cycle.
  ||||||||       RD is cleared in hardware. The RD bit can only 
  ||||||||       be set, not cleared, in software.)
  76543210   0 = Does not initiate an EEPROM read
                        
----------

PIC16F676

                            +--U--+
                     VDD > [| 1 14|] < VSS
      RA5/T1CKI/OSC1/CLKIN [| 2 13|] RA0/AN0/CIN+/ICSPDAT
  RA4/!T1G/OSC2/AN3/CLKOUT [| 3 12|] RA1/AN1/CIN-/VREF/ICSPCLK
           RA3/!MCLR/VPP > [| 4 11|] RA2/AN2/COUT/TOCKI/INT
                       RC5 [| 5 10|] RC0/AN4
                       RC4 [| 6  9|] RC1/AN5
                   RC3/AN7 [| 5 10|] RC2/AN6
                            +-----+
                            
TABLE 1-1: PIC16F630/676 PINOUT DESCRIPTION
  ----------
  Name             Function Input Output Description
                   Type     Type
  ----------
  RA0/AN0/CIN+/ICSPDAT RA0     TTL  CMOS Bi-directional I/O w/ 
                                         programmable pull-up and
                                         Interrupt-on-change
                       AN0     AN   -    A/D Channel 0 input
                       CIN+    AN        Comparator input
                       ICSPDAT TTL  CMOS Serial Programming 
                                         Data I/O
                                         
  RA1/AN1/CIN-/VREF/   RA1     TTL  CMOS Bi-directional I/O w/ 
  ICSPCLK                                programmable pull-up 
                                         and Interrupt-on-change
                       AN1     AN   -    A/D Channel 1 input
                       CIN-    AN   -    Comparator input
                       VREF    AN   -    External Voltage 
                                         reference
                       ICSPCLK ST   -    Serial Programming Clock
                       
  RA2/AN2/COUT/T0CKI/  RA2     ST   CMOS Bi-directional I/O w/ 
  INT                                    programmable pull-up and
                                         Interrupt-on-change
                       AN2     AN   -    A/D Channel 2 input
                       COUT    -    CMOS Comparator output
                       T0CKI   ST   -    Timer0 clock input
                       INT     ST   -    External Interrupt
                       
  RA3/!MCLR/VPP        RA3     TTL  -    Input port with 
                                         Interrupt-on-change
                       !MCLR   ST   -    Master Clear
                       VPP     HV   -    Programming voltage
                       
  RA4/!T1G/AN3/OSC2/   RA4     TTL  CMOS Bi-directional I/O w/ 
  CLKOUT                                 programmable pull-up and
                                         Interrupt-on-change
                       T1G     ST   -    Timer1 gate
                       AN3     AN3  -    A/D Channel 3 input
                       OSC2    -    XTAL Crystal/Resonator
                       CLKOUT  -    CMOS FOSC/4 output
                        
  RA5/T1CKI/OSC1/CLKIN RA5     TTL  CMOS Bi-directional I/O w/ 
                                         programmable pull-up and 
                                         Interrupt-on-change
                       T1CKI   ST   -    Timer1 clock
                       OSC1    XTAL -    Crystal/Resonator
                       CLKIN   ST   -    External clock input/RC 
                                         oscillator connection
                                         
  RC0/AN4              RC0     TTL  CMOS Bi-directional I/O
                       AN4     AN4  -    A/D Channel 4 input
                       
  RC1/AN5              RC1     TTL  CMOS Bi-directional I/O
                       AN5     AN5  -    A/D Channel 5 input
                       
  RC2/AN6              RC2     TTL  CMOS Bi-directional I/O
                       AN6     AN6  -    A/D Channel 6 input
                       
  RC3/AN7              RC3     TTL  CMOS Bi-directional I/O
                       AN7     AN7  -    A/D Channel 7 input
                       
  RC4                  RC4     TTL  CMOS Bi-directional I/O

  RC5                  RC5     TTL  CMOS Bi-directional I/O

  VSS                  VSS     Power -   Ground reference

  VDD                  VDD     Power -   Positive supply
  ----------
  Legend: Shade = PIC16F676 only               
          TTL = TTL input buffer               
          ST = Schmitt Trigger input buffer
          
  ----------
        
  PIC16F676 BLOCK DIAGRAM                       RA0..RA5 RC0..RC5
                                                Port A   Port C   
                                                    ^        ^ 
                                                    |        |
  +-------------+        [INT]   ==== Data bus =8===+========+=== 
  |Configuration|          |    |                   |            |
  +-------------+          v    v                   v            |
  +-------------+       +-------+-------+  +-------------------+ |
  |FLASH 1K x 14|<==13==|Program counter|  | RAM 64 bytes File | |
  |   Program   |       +---------------+  +-------------------+ |
  |   Memory    |               ^                   ^            |
  +-----+++-----+               |          RAM Addr 9            |
        |D|                     v              +----+-----+      |
        \ /          +----------------------+  | Addr MUX |      |
         v           |8-level stack (13-bit)|  +--+---+---+      |
  +---------------+  +----------------------+     |   8 Indirect |
  |Instruction reg|====7=>Direct Addr=============^   ^ addr     |
  +---------------+                              +----------+    |
        | |                                      | FSR Reg  |<===+
        | |                                      +----------+    |
        | |                                      +----------+    |
        | |                                    ->|STATUS Reg|<===+
        | |                                   |  +----------+    |
        | +==8>===============================)=======+   +======+
        | |                                   |       v   v      |
        \ /            +----------+           |      +-----+     |
   +------------+      |Power-up  |           ^      | MUX |     |
   | Instruction|      |Timer     |           3      +--+--+     |
   | Decode &   |<---->|Oscillator|           |         |        |
   | Control    |      |Start-up  |<-[!MCLR]  | +-------+---+    |
   +------------+      |Timer     |            -| ALU/WREG  |<===+
                       |Power-on  |<-[VDD]      +-----------+    |
                       |Reset     |                              | 
  |Timing Generation|<>|Watchdog  |<-[VSS]       EEDATA          |
  [oSC1/CLKIN]  ^      |Timer     |              128 bytes   <-8-+
  [OSC2/CLKOUT] |      |Brown-out |              DATA EEPROM     |
                v      |Detect    |              EEADDR          |
     +------------+    +----------+                              |
     |Internal OSC|          Analog Comparator and Reference <---+
     +------------+          [CIN-] [CIN+] [COUT]                |
                                                                 |
          |ADC Analog to Digital Converter (PIC16F676 only)| <---+
          [VREF][AN0][AN1][AN2][AN3][AN4][AN5][AN6][AN7]       |
                                                                 |
                                            [T0CKI] |Timer0| <---+
                                                                 |
                                                    |Timer1| <---+
                                              [!T1G] [T1CKI] 

----------

DATA MEMORY MAP OF THE PIC16F676

      +------------+------------+
  00h |    INDF*   |     <-     | 80h
  01h |    TMR0    | OPTION_REG | 81h
  02h |    PCL     |     <-     | 82h
  03h |   STATUS   |     <-     | 83h
  04h |    FSR     |     <-     | 84h
  05h |   PORTA    |   TRISA    | 85h
  06h |  00000000  |  00000000  | 86h
  07h |   PORTC    |   TRISC    | 87h
  08h |  00000000  |  00000000  | 88h
  09h |  00000000  |  00000000  | 89h
  0Ah |   PCLATH   |     <-     | 8Ah
  0Bh |   INTCON   |     <-     | 8Bh
  0Ch |    PIR1    |    PIE1    | 8Ch
  0Dh |  00000000  |  00000000  | 8Dh
  0Eh |   TMR1L    |    PCON    | 8Eh
  0Fh |   TMR1H    |  00000000  | 8Fh
  10h |   T1CON    |   OSCCAL   | 90h
  11h |  00000000  |   ANSEL    | 91h
  12h |  00000000  |  00000000  | 92h
  13h |  00000000  |  00000000  | 93h
  14h |  00000000  |  00000000  | 94h
  15h |  00000000  |    WPUA    | 95h
  16h |  00000000  |    IOCA    | 96h
  17h |  00000000  |  00000000  | 97h
  18h |  00000000  |  00000000  | 98h
  19h |   CMCON    |   VRCON    | 99h
  1Ah |  00000000  |   EEDAT    | 9Ah
  1Bh |  00000000  |   EEADR    | 9Bh
  1Ch |  00000000  |   EECON1   | 9Ch
  1Dh |  00000000  |   EECON2   | 9Dh
  1Eh |   ADRESH   |   ADRESL   | 9Eh
  1Fh |   ADCOND   |   ADCON1   | 9Fh
      +------------+------------+
  20h | GPR 20h-50h (64 bytes)  | 20h
      +------------+------------+
  60h |  00000000  | 000000000  | E0h
  ... |  ........  | ........   | ...
  7Fh |  00000000  | 000000000  | FFh
      +------------+------------+

  *        Not a physical register    
  00000000 fields unimplemented, read as "0"

----------  

  PIC16F630/676 INSTRUCTION SET

  ------------------
  Mnemonic,    Description                 Cycles 14-Bit Opcode  Flag *
  Operands
  ------------------
    BYTE-ORIENTED FILE REGISTER OPERATIONS   
  ADDWF  f, d  Add W and f                    1   000111dfffffff CDZ  12
  ANDWF  f, d  AND W with f                   1   000101dfffffff Z    12
  CLRF     f   Clear f                        1   000001lfffffff Z    2
  CLRW     -   Clear W                        1   0000010xxxxxxx Z
  COMF   f, d  Complement f                   1   001001dfffffff Z    12
  DECF   f, d  Decrement f                    1   000011dfffffff Z    12
  DECFSZ f, d  Decrement f, Skip if 0        1(2) 001011dfffffff      123
  INCF   f, d  Increment f                    1   001010dfffffff Z    12
  INCFSZ f, d  Increment f, Skip if 0        1(2) 001111dfffffff      123
  IORWF  f, d  Inclusive OR W with f          1   000100dfffffff Z    12
  MOVF   f, d  Move f                         1   001000dfffffff Z    12
  MOVWF    f   Move W to f                    1   000000lfffffff
  NOP      -   No Operation                   1   0000000xx00000
  RLF    f, d  Rotate Left f through Carry    1   001101dfffffff C    12
  RRF    f, d  Rotate Right f through Carry   1   001100dfffffff C    12
  SUBWF  f, d  Subtract W from f              1   000010dfffffff CDZ  12
  SWAPF  f, d  Swap nibbles in f              1   001110dfffffff      12
  XORWF  f, d  Exclusive OR W with f          1   000110dfffffff Z    12
    BIT-ORIENTED FILE REGISTER OPERATIONS
  BCF    f, b  Bit Clear f                    1   0100bbbfffffff      12
  BSF    f, b  Bit Set f                      1   0101bbbfffffff      12
  BTFSC  f, b  Bit Test f, Skip if Clear     1(2) 0110bbbfffffff      3
  BTFSS  f, b  Bit Test f, Skip if Set       1(2) 0111bbbfffffff      3
    LITERAL AND CONTROL OPERATIONS
  ADDLW   k    Add literal and W              1   11111xkkkkkkkk CDZ
  ANDLW   k    AND literal with W             1   111001kkkkkkkk Z
  CALL    k    Call subroutine                2   100kkkkkkkkkkk
  CLRWDT  -    Clear Watchdog Timer           1   00000001100100 TO,PD
  GOTO    k    Go to address                  2   101kkkkkkkkkkk
  IORLW   k    Inclusive OR literal with W    1   111000kkkkkkkk Z
  MOVLW   k    Move literal to W              1   1100xxkkkkkkkk
  RETFIE  -    Return from interrupt          2   00000000001001
  RETLW   k    Return with literal in W       2   1101xxkkkkkkkk
  RETURN  -    Return from Subroutine         2   00000000001000
  SLEEP   -    Go into Standby mode           1   00000001100011 TO,PD
  SUBLW   k    Subtract W from literal        1   11110xkkkkkkkk CDZ
  XORLW   k    Exclusive OR literal with W    1   111010kkkkkkkk Z

  Note 1: When an I/O register is modified as a function of itself (e.g., 
          MOVF PORTA, 1), the value used will be that value present
          on the pins themselves. For example, if the data latch is '1' 
          for a pin configured as input and is driven low by an external
          device, the data will be written back with a '0'.
       2: If this instruction is executed on the TMR0 register (and, 
          where applicable, d = 1), the prescaler will be cleared if
          assigned to the Timer0 module.
       3: If Program Counter (PC) is modified, or a conditional test is 
          true, the instruction requires two cycles. The second cycle is
          executed as a NOP.

----------

  00 INDF*      Use contents of FSR to address data memory       xxxxxxxx
  01 TMR0       Timer0 Module's Register                         xxxxxxxx
  02 PCL        Program Counter's (PC) LSB                       00000000
  03 STATUS     IRP   RP1   RP0   !TO  !PD    Z     DC    C      00011xxx
  04 FSR        Indirect data memory address pointer             xxxxxxxx
  05 PORTA      ----- ----- [ I/O Control Registers            ] --xxxxxx
  06 PORTB      ----- Unimplemented  --                          
  07 PORTC      ----- ----- [ I/O Control Registers            ] --xxxxxx
  08 PORTD      --   Unimplemented  --
  09            --   Unimplemented  --
  0A PCLATH     ----- ----- ----- [Write buffer PC upper 5 bits] ---00000
  0B INTCON     GIE   PEIE  T0IE  INTE  RAIE  T0IF  INTF  RAIF   00000000
  0C PIR1       EEIF  ADIF  ----- ----- CMIF  ----- ----- TMR1IF 00--0--0
  0D            --   Unimplemented  --
  0E TMR1L      Holds LSByte of the 16-bit TMR1                  xxxxxxxx
  0F TMR1H      Holds MSByte of the 16-bit TMR1                  xxxxxxxx
  10 T1CON      ----- T1GE  CKPS1 CKPS0 OSCEN !SYNC T1CS  T1ON   -0000000
  11            --   Unimplemented  --
  12            --   Unimplemented  --
  13            --   Unimplemented  --
  14            --   Unimplemented  --
  15            --   Unimplemented  --
  16            --   Unimplemented  --
  17            --   Unimplemented  --
  18            --   Unimplemented  --
  19 CMCON      ----- COUT  ----- CINV  CIS   CM2   CM1   CM0    -0-00000
  1A            --   Unimplemented  --
  1B            --   Unimplemented  --
  1C            --   Unimplemented  --
  1D            --   Unimplemented  --
  1E ADRESH     MSByte A/D result << or 2 bits of A/D result >>  xxxxxxxx
  1F ADCON0     ADFM  VCFG  ----- CHS2  CHS1  CHS0 GO!DONE ADON  00-00000

  80 INDF*      Use contents of FSR to address data memory       xxxxxxxx
  81 OPTION_REG !RAPU INTEDG T0CS T0SE  PSA   PS2   PS1   PS0    11111111
  82 PCL        Program Counter's (PC) LSB                       00000000
  83 STATUS     IRP   RP1   RP0   !TO  !PD    Z     DC    C      00011xxx
  84 FSR        Indirect data memory address pointer             xxxxxxxx
  85 TRISA      ----- ---- TRISA5 ..A4  ..A3  ..A2  ..A1  ..A0   --111111
  86            --  Unimplemented  --  
  87 TRISC      ----- ---- TRISC5 ..C4  ..C3  ..C2  ..C1  ..C0   --111111
  88            --  Unimplemented  --  
  89            --  Unimplemented  --  
  8A PCLATH     ----- ----- ----- [Write buffer PC upper 5 bits] ---00000
  0B INTCON     GIE   PEIE  T0IE  INTE  RAIE  T0IF  INTF  RAIF   00000000
  8C PIE1       EEIE  ADIE  ----- ----- CMIE  ----- ----- TMR1IE 00--0--0
  8D            --  Unimplemented  --  
  8E PCON       ----- ----- ----- ----- ----- ----- PO    BOD    ------qq
  8F            -- ?????????????? --
  90 OSCCAL     CAL5  CAL4  CAL3  CAL2  CAL1  CAL0  ----- -----  100000--
  91 ANSEL(3)   ANS7  ANS6  ANS5  ANS4  ANS3  ANS2  ANS1  ANS0   11111111
  92            --  Unimplemented  --   
  93            --  Unimplemented  --  
  94            --  Unimplemented  --  
  95 WPUA       ----- ----- WPUA5 WPUA4 ----- WPUA2 WPUA1 WPUA0  --11-111
  96 IOCA       ----- ----- IOCA5 IOCA4 IOCA3 IOCA2 IOCA1 IOCA0  --000000
  97            --  Unimplemented  --  
  98            --  Unimplemented  --  
  99 VRCON      VREN  ----- VRR   ----- VR3   VR2   VR1   VR0    0-0-0000
  9A EEDAT      EEPROM data register                             00000000
  9B EEADR      ----- [ EEPROM address register                ] 00000000
  9C EECON1     ----- ----- ----- ----- WRERR WREN  WR    RD     ----x000
  9D EECON2     EEPROM control register 2 (not a physical one)   --------
  9E ADRESL     LSB+1,LSB result << or BYTE of the result >>     xxxxxxxx
  9F ADCON1     ----- ADCS2 ADCS1 ADCS0 ----- ----- ----- -----  -000----

  Legend:    ­ = Unimplemented locations read as '0', 
             u = unchanged, x = unknown, q = value depends on 
             condition, shaded = unimplemented
             
  *) Other (non Power-up) Resets include MCLR Reset, Brown-out 
     Detect and Watchdog Timer Reset during normal operation.
       2: IRP & RP1 bits are reserved, always maintain these bits 
          clear.

----------

ADC no interrupts, mikroC version, tested with p16f676, p12f675

  // config 0x3184
  // Oscillator Selection
  // INTOSC oscillator:      I/O function on RA4/OSC2/CLKOUT pin,
  //                         I/O function on RA5/OSC1/CLKIN
  // Watchdog Timer:         Disabled
  // Power Up Timer:         Enabled
  // RA3/MCLR pin func.sel.: Disabled
  // Brown-out Detect:       Disabled
  // Code protection:        Program Memory code protection disabled
  // Data Code Protection:   Data memory code protection disabled

  void low_init()
  {
    CMCON=0x07; // Comparator off -lowest power
    ADCON1=0b00110000; // x11 =   FRC (clock derived from a dedicated
                       // internal oscillator = 500 kHz max)
    ADCON0=0b10000001; // Right justified, A/D-On
    ANSEL = 1;         // AD0 active
    TRISA =0b11001001;
  }

  void D0_UP() {
    TRISA = 0b11001111;
    PORTA = 0b00010000;
  }

  void D1_UP() {
    TRISA = 0b11001111;
    PORTA = 0b00100000;
  }

  void D2_UP() {
    TRISA = 0b11101011;
    PORTA = 0b00010000;
  }

  void D3_UP() {
    TRISA = 0b11101011;
    PORTA = 0b00000100;
  }

  void D4_UP() {
    TRISA = 0b11011011;
    PORTA = 0b00100000;
  }

  void D5_UP() {
    TRISA = 0b11011011;
    PORTA = 0b00000100;
  }

  void D6_UP() {
    TRISA = 0b11111001;
    PORTA = 0b00000100;
  }

  void D7_UP() {
    TRISA = 0b11111001;
    PORTA = 0b00000010;
  }

  void main() {
    char x;
    low_init();
  loop:
    ADCON0.GO = 1;
    while (ADCON0.GO) {}
    x = ADRESH << 6 | ADRESL >> 2;
    if (x < 0x20) D0_UP(); else
    if (x < 0x40) D1_UP(); else
    if (x < 0x60) D2_UP(); else
    if (x < 0x80) D3_UP(); else
    if (x < 0xA0) D4_UP(); else
    if (x < 0xC0) D5_UP(); else
    if (x < 0xE0) D6_UP(); else
    D7_UP();
    goto loop;
  }

----------

  // C version for defaultdemonstration
  //
  // config 0x3184
  // Oscillator Selection
  // INTOSC oscillator:     I/O function on RA4/OSC2/CLKOUT pin,
  //                        I/O function on RA5/OSC1/CLKIN
  // Watchdog Timer:        Disabled
  // Power Up Timer:        Enabled
  // RA3/MCLR pin function: MUST BE DISABLED !
  // Brown-out Detect:      Disabled
  // Code protection:       Program Mem. code protection disabled
  // Data Code Protection:  Data memory code protection disabled

  unsigned char gcnt = 0;
  unsigned char gbutton = 1;

  void init() {
      OSCCAL = 0x34;
      VRCON  = 0;
      OPTION_REG = 0x87;

      IOCA   = 0x08; // IOCA,IOC3 - Interrupt on change bits 5:0
      PIE1   = 0x40; // PIE1:ADIE - A/D Converter Interrupt Enable
      CMCON  = 0x07; // Comparator Off
      TMR0   = 0;    // CLRF  TMR0
      ADCON0 = 0x01; // A/D channel 000 ON
      PIR1   = 0x40; // The A/D conversion is not complete
      INTCON = 0xE8; // GIE  x  T0IE  x  RAIE  !T0IF  x  !RAIF

      TRISA = 0xFF;
      PORTA = 0;
  }

  void D0_UP() {
    TRISA = 0b11001111;
    PORTA = 0b00010000;
  }

  void D1_UP() {
    TRISA = 0b11001111;
    PORTA = 0b00100000;
  }

  void D2_UP() {
    TRISA = 0b11101011;
    PORTA = 0b00010000;
  }

  void D3_UP() {
    TRISA = 0b11101011;
    PORTA = 0b00000100;
  }

  void D4_UP() {
    TRISA = 0b11011011;
    PORTA = 0b00100000;
  }

  void D5_UP() {
    TRISA = 0b11011011;
    PORTA = 0b00000100;
  }

  void D6_UP() {
    TRISA = 0b11111001;
    PORTA = 0b00000100;
  }

  void D7_UP() {
    TRISA = 0b11111001;
    PORTA = 0b00000010;
  }

  // Prescaler (find some shit here)
  void prescalebyadc() {
  asm {
      BCF STATUS,RP0       ; Bank 0

      MOVLW 0x20
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER7

      MOVLW 0x40
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER6

      MOVLW 0x60
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER5

      MOVLW 0x80
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER4

      MOVLW 0xA0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER3

      MOVLW 0xC0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER2

      MOVLW 0xE0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER1
      GOTO PRESCALER0

  PRESCALER0:
      MOVLW 0x80
      GOTO PRESCALER

  PRESCALER1:
      MOVLW 0x81
      GOTO PRESCALER

  PRESCALER2:
      MOVLW 0x82
      GOTO PRESCALER

  PRESCALER3:
      MOVLW 0x83
      GOTO PRESCALER

  PRESCALER4:
      MOVLW 0x84
      GOTO PRESCALER

  PRESCALER5:
      MOVLW 0x85
      GOTO PRESCALER

  PRESCALER6:
      MOVLW 0x86
      GOTO PRESCALER

  PRESCALER7:
      MOVLW 0x87
      GOTO PRESCALER

  PRESCALER:
      BSF STATUS,RP0       ; BANK 1
      MOVWF OPTION_REG     ; OPTION_REG - Set Prescaler 10000xxx
      }
  }

  void interrupt() {
    char x;
    if (INTCON.T0IF) {
      PIE1.ADIE = 0;
      // if (!(x = gcnt++)) gbutton = !gbutton;
      x = gcnt++ >> 5;
      prescalebyadc();
      
      switch (x) {
      // {} this is such funny C
          case 0: { gbutton ? D0_UP() : D7_UP(); } break;
          case 1: { gbutton ? D1_UP() : D6_UP(); } break;
          case 2: { gbutton ? D2_UP() : D5_UP(); } break;
          case 3: { gbutton ? D3_UP() : D4_UP(); } break;
          case 4: { gbutton ? D4_UP() : D3_UP(); } break;
          case 5: { gbutton ? D5_UP() : D2_UP(); } break;
          case 6: { gbutton ? D6_UP() : D1_UP(); } break;
          case 7: { gbutton ? D7_UP() : D0_UP(); } break;
      }

      if (!ADCON0.GO) ADCON0.GO = 1;
      TMR0 = 0xf0; // 0 slowest 0xFF fastest
      INTCON.T0IF = 0;
      PIE1.ADIE = 1;
    }
    else if (INTCON.RAIF) {
      delay_ms(10);
      gbutton = !gbutton;
      INTCON.RAIF = 0;
    }
    else if (PIR1.ADIF) {
      // hurry up here
      // On IRQ ADC operates in 8-bit mode
      PIR1.ADIF = 0;
    }
  }

  void main() {
      char x;
      init();
      while(1);
  }

----------

  ; Variation, Pickit 1, PIC16F676, 2013, Based on default code
  ;
  ; Configuration bits
  ; 
  ; Address Value Category              Setting
  ; --------------------------------------------------------
  ; 2007    3F84  Oscillator            Internal RC No Clock
  ;               Watching Timer        Off
  ;               Power Up Timer        On
  ;               Master Clear Enable   Internal
  ;               Brown Out Detect      Off
  ;               Code Protect          Off
  ;               Data EE Read Protect  Off
  ;    
  ; Pickit 1 Schematics                
  ; -------------------
  ;
  ; CONNECTOR:
  ;
  ; J3:   1  RA5         PIN
  ;       2  RA4         Sequence 
  ;       3  RA3         As
  ;       4  RC5         PINs
  ;       5  RC4         ON
  ;       6  RC3         CHIP
  ;       7  RA0
  ;       8  RA1
  ;       9  RA2
  ;      10  RC0
  ;      11  RC1
  ;      12  RC2          C8 0.1uF
  ;      13  +5_SWITCHED  ---||--+
  ;      14  GND          -------+
  ;      
  ; BUTTON:
  ; 
  ;          D12       R3 1K       R2 10K
  ; VPP o---|>|---+---\/\/\---+---\/\/\---o +5_SWITCHED
  ;               |           o
  ;               |        --|   
  ;               |           o
  ;               o           |
  ;              RA3         -+-
  ;
  ; POTENTIOMETER:
  ;
  ; +5_SWITCHED o---\/\/\/\---o GND
  ;                    ^
  ;             R4 1K  |  C2 1000pF
  ;     RA0 o---\/\/\--+--||--o GND
  ;
  ; LEDS
  ; 
  ;   |       D11       |        
  ;   +-------|<|-------+
  ;   |                 |        (DB)(DA)(D9)(D8)
  ;   |       D10       |        (D7)(D6)(D5)(D4)
  ;   +-------|>|-------+        (D3)(D2)(D1)(DO) 
  ;   |                 |    
  ;   |          D9     |    
  ;   |     +----|<|----+        Sequence follows:
  ;   |     |           |        6 0 7 3 5 4 2 1
  ;   |     |    D8     |        
  ;   |     +----|>|----+        LADR_0x033C  D6 UP
  ;   |     |           |        LADR_0x0343  D0 UP
  ;   |     | D3        |        LADR_0x034A  D7 UP
  ;   +-------|<|-+     |        LADR_0x0351  D3 UP
  ;   |     |     |     |        LADR_0x0358  D5 UP
  ;   | D2  |     |     |        LADR_0x035F  D4 UP
  ;   +-|>|-------+     |        LADR_0x0366  D2 UP
  ;   |     |     |     |        LADR_0x036D  D1 UP
  ;   | D1  | D5  | D7  |    
  ;   +-|<|-+-|<|-+-|<|-+
  ;   |     |     |     |    
  ;   | D0  | D4  | D6  |    
  ;   +-|>|-+-|>|-+-|>|-+
  ;   |     |     |     |
  ; R5|   R6|   R7|   R8|
  ; [150] [150] [150] [150]
  ;   |     |     |     |
  ;   RA4   RA5   RA2   RA1
  ;   
  ; .............................................................
  ;
  ; original File = defaultdemonstration.hex
  ;
  #include <P16F676.INC>

      processor 16F676
      __config 0x3F84 ; _CPD_OFF & _CP_OFF & _BODEN_OFF & 
                      ; _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & 
                      ; _INTRC_OSC_NOCLKOUT 

  ; RAM-Variables
  LRAM_0x20 EQU 0x20
  LRAM_0x21 EQU 0x21
  LRAM_0x22 EQU 0x22
  LRAM_0x23 EQU 0x23
  LRAM_0x24 EQU 0x24
  LRAM_0x25 EQU 0x25
  LRAM_0x26 EQU 0x26
  LRAM_0x27 EQU 0x27
  LRAM_0x28 EQU 0x28
  LRAM_0x2A EQU 0x2A
  LRAM_0x2B EQU 0x2B
  LRAM_0x2C EQU 0x2C
  LRAM_0x2D EQU 0x2D
  LRAM_0x2E EQU 0x2E
  LRAM_0x2F EQU 0x2F

  TDELAY    EQU 0xFF       ; ~ 1 sec

  ; Program

      Org 0x0000

  ;   Reset-Vector
      CLRF STATUS
      MOVLW 0x00
      MOVWF PCLATH         ; PCLATH = 0
      GOTO LAMPS
      
  LAMPS
      MOVLW TDELAY
      CALL LADR_0x0374
      CLRF 0x28
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      CLRF 0x28
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      MOVLW TDELAY
      CALL LADR_0x0374
      INCF 0x28, F
      INCF 0x28, F
      CALL LADR_0x038D
      GOTO LAMPS
      
  LADR_0x033C              ; D6 UP
      MOVLW 0xF9           ; iiiiiooi
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11111001
      MOVLW 0x04           ; 00000100  V2=HI V1=LO  D6
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN
      
  LADR_0x0343              ; D0 UP
      MOVLW 0xCF           ; ii00iiii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11001111
      MOVLW 0x10           ; 00010000  V4=HI V5=LO  D0
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00010000       
      RETURN
      
  LADR_0x034A              ; D7 UP
      MOVLW 0xF9           ; iiiiiooi
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11111001
      MOVLW 0x02           ; 00000010  V1=HI V2=LO  D7
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000010       
      RETURN

  LADR_0x0351              ; D3 UP
      MOVLW 0xEB           ; iiioioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11101011
      MOVLW 0x04           ; 00000100  V2=HI V4=LO  D3
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN
      
  LADR_0x0358              ; D5 UP
      MOVLW 0xDB           ; iioiioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11011011
      MOVLW 0x04           ; 00000100  V2=HI V5=LO  D5
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN
      
  LADR_0x035F              ; D4 UP
      MOVLW 0xDB           ; iioiioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11011011
      MOVLW 0x20           ; 00100000  V5=HI V2=LO  D4
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00100000       
      RETURN
      
  LADR_0x0366              ; D2 UP
      MOVLW 0xEB           ; iiioioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11101011
      MOVLW 0x10           ; 00010000  V4=HI V2=LO  D2
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00010000       
      RETURN              
      
  LADR_0x036D              ; D1 UP
      MOVLW 0xCF           ; iiooiiii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11001111
      MOVLW 0x20           ; 00100000  V5=HI V4=LO  D1
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00100000
      RETURN

-----------

  ; original File = defaultdemonstration.hex (renamed labels 
  ; and calls in cracked part, cracked part shifted down, 
  ; chip P12F675, header improvements, 20130311)
  ;
  ; Assembly generated with picdisasm104, last row (at 0x3ff)
  ; manually added. Recompiled with MPLAB 6.60 (2004)
  ; original File = defaultdemonstration.hex from pickit 1 setup.

  #include <P12F675.INC>

      processor 12F675
      __config 0x3F84 ; _CPD_OFF & _CP_OFF & _BODEN_OFF & 
                      ; _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & 
                      ; _INTRC_OSC_NOCLKOUT

  TRISA     EQU 0x85
  PORTA     EQU 0x05
  IOCA      EQU 0x96
  ; INTCON Bits
  GIE       EQU 7
  PEIE      EQU 6
  T0IE      EQU 5
  INTE      EQU 4
  RAIE      EQU 3
  T0IF      EQU 2
  INTF      EQU 1
  RAIF      EQU 0

  ; RAM-Variables
  LRAM_0x21 EQU 0x21
  LRAM_0x22 EQU 0x22
  LRAM_0x24 EQU 0x24
  LRAM_0x25 EQU 0x25
  LRAM_0x27 EQU 0x27
  LRAM_0x28 EQU 0x28
  LRAM_0x2B EQU 0x2B

  SAVE_W      EQU 0x20
  SAVE_STATUS EQU 0x2C
  SAVE_FSR    EQU 0x2D
  SAVE_PCLATH EQU 0x2E
  SAVE_2B     EQU 0x2F

  DELAY_C2  EQU 0x23
  DELAY_C1  EQU 0x26
  DELAY_C0  EQU 0x2A

  ; Program

      Org 0x0000

  ;   Reset-Vector
      CLRF STATUS
      MOVLW 0x00           ; Write buffer for upper 5 bits of 
      MOVWF PCLATH         ; program counter PCLATH = 0 
      GOTO LADR_0x0063
      
  ; .............................................................
  ;
  ;   Interrupt-Vector
  SAVE_PSW
      MOVWF SAVE_W         ; SAVE_W = W  Save W
      MOVF STATUS,W        ; W = STATUS
      CLRF STATUS          ; STATUS = 0
      MOVWF SAVE_STATUS    ; SAVE_STATUS = W  Save STATUS
      MOVF FSR,W           ; W = FSR
      MOVWF SAVE_FSR       ; SAVE_FSR = W  Save FSR
      MOVF PCLATH,W        ; W = PCLATH (PCOUNTER BITS 12..9)
      MOVWF SAVE_PCLATH    ; SAVE_PCLATH = W  Save PCLATH
      CLRF PCLATH          ; PCLATH = 0
      MOVF LRAM_0x2B,W     ; W = 0x2B 
      MOVWF SAVE_2B        ; SAVE_2B = 0x2B
      
  IRQ_TIMER
      BTFSC INTCON,T0IF    ; Skip if TMR0 is not overflowed
      BTFSS INTCON,T0IE    ; Skip if TMR0 interrupt enabled
      GOTO IRQ_BUTTON
      BCF STATUS,RP0       ; BANK 0
      CALL LADR_0x03CD     ; ?
      BSF ADCON0,1         ; A/D converter module is operating
      BCF INTCON,T0IF      ; TMR0 register has overflowed 
                           ; (must be cleared in software)
                           
  IRQ_BUTTON
      BTFSC INTCON,RAIF    ; Skip if none of porta 5:0 pins
                           ; have changed state 
      BTFSS INTCON,RAIE    ; Skip if port change interrupt is
                           ; enabled
      GOTO IRQ_ADC         ; A/D converter ----------------------
      BCF STATUS,RP0       ; Bank 0
      CALL DELAY_WRAP      ; Was button pressed (with delay) ----
      XORLW 0x01           ; W was 1 ? 
      BTFSS STATUS,Z       ; skip if W was 1
      GOTO CLEAR_RAIF_FLAG
      MOVLW 0x01           ; W = 1
      XORWF LRAM_0x21,F    ; LRAM_0x21 = W xor LRAM_0x21
  CLEAR_RAIF_FLAG
      BCF INTCON,RAIF      ; Clear "port have changed state" flag
      
  IRQ_ADC
      BCF STATUS,RP0       ; Bank 0
      BTFSS PIR1,ADIF      ; ADIF A/D conversion complete (1)
      GOTO RESTORE_PSW
      BSF STATUS,RP0       ; Bank 1
      BTFSS PIE1,ADIE      ; ADIE A/D coversion enabled (1)
      GOTO RESTORE_PSW
      
      MOVLW 0x7F           ; W = 0x7F
      BCF STATUS,RP0       ; Bank 0
      SUBWF ADRESL,W       ; W = ADRESL - W
      BTFSC STATUS,C       ; CARRY ? 
      GOTO LADR_0x0040
      
      MOVLW 0x40           ; W = 0x40
      SUBWF ADRESL,W       ; W = ADRESL - W
      BTFSS STATUS,C       ; CARRY ? 
      GOTO LADR_0x0038
      
      MOVLW 0x5F           ; W = 0x5F
      SUBWF ADRESL,W       ; W = ADRESL - W
      BTFSS STATUS,C       ; CARRY ? 
      GOTO PRESCALER5
      GOTO PRESCALER4

  ; .............................................................
      
  LADR_0x0038
      MOVLW 0x20
      BCF STATUS,RP0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER7
      GOTO PRESCALER6
      
  LADR_0x0040
      MOVLW 0xBF
      BCF STATUS,RP0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO NEARHERE
      MOVLW 0xDE
      BCF STATUS,RP0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER1
      GOTO PRESCALER0
  NEARHERE
      MOVLW 0xA0
      BCF STATUS,RP0
      SUBWF ADRESL,W
      BTFSS STATUS,C
      GOTO PRESCALER3
      GOTO PRESCALER2
      
  ; .............................................................
      
  PRESCALER0
      MOVLW 0x80
      GOTO PRESCALER

  PRESCALER1
      MOVLW 0x81
      GOTO PRESCALER
      
  PRESCALER2
      MOVLW 0x82
      GOTO PRESCALER
      
  PRESCALER3
      MOVLW 0x83
      GOTO PRESCALER
      
  PRESCALER4    
      MOVLW 0x84           ; W = 0x84
      GOTO PRESCALER

  PRESCALER5
      MOVLW 0x85
      GOTO PRESCALER

  PRESCALER6
      MOVLW 0x86
      GOTO PRESCALER
      
  PRESCALER7
      MOVLW 0x87
      GOTO PRESCALER
      
  PRESCALER
      BSF STATUS,RP0       ; BANK 1
      MOVWF TMR0           ; OPTION_REG - Set Prescaler 10000xxx
      BCF STATUS,RP0       ; BANK 0
      BCF PIR1,ADIF        ; AD conversion complete, clear flag
      
  RESTORE_PSW
      BCF   STATUS,RP0     ; Bank 0
      MOVF  SAVE_2B,W
      MOVWF LRAM_0x2B      ; [0x2b] =   [0x2f]
      MOVF  SAVE_FSR,W
      MOVWF FSR            ; [FSR] =    [0x2d]
      MOVF  SAVE_PCLATH,W
      MOVWF PCLATH         ; [PCLATH] = [0x2e]
      MOVF  SAVE_STATUS,W
      MOVWF STATUS         ; [STATUS] = [0x2c]
      SWAPF SAVE_W,F       ; swap nibbles in [0x20] 
      SWAPF SAVE_W,W       ; [W] = [0x20]
      RETFIE
      
  ; .............................................................

  LADR_0x0063
      MOVLW 0x21
      MOVWF FSR           ; FSR = 0x21
      MOVLW 0x22          ; W   = 0x22
      CALL LADR_0x0070
      
      MOVLW 0x22
      MOVWF FSR           ; FSR = 0x22
      MOVLW 0x2B          ; W   = 0x2B
      CALL LADR_0x0070
      
      CLRF STATUS
      
      GOTO LADR_0x0331
      
  LADR_0x006D
      XORWF FSR,W
      CLRF INDF           ; clear memory pointed by FSR
      INCF FSR,F          ; FSR++
  LADR_0x0070
      XORWF FSR,W
      BTFSC STATUS,Z
      RETLW 0x00          ; return with W = 0
      GOTO LADR_0x006D

  ; .............................................................

      Org 0x0331

  LADR_0x0331
      BCF STATUS,RP0      ; BANK 0
      CALL SETUP_CHIP     ; SETUP
  LADR_0x0333
      MOVLW 0xFF
      MOVWF LRAM_0x24     ; LRAM_0x24 = 0xFF
      GOTO LADR_0x0333    ; loop forever !
      
  ; .............................................................

  LADR_0x03CD
      BCF STATUS,RP0      ; BANK 0
      MOVF LRAM_0x25,F
      BTFSS STATUS,Z
      GOTO LADR_0x03D4
      MOVF LRAM_0x24,W
      MOVWF LRAM_0x25
      CLRF LRAM_0x28
  LADR_0x03D4
      MOVF LRAM_0x25,W
      MOVWF LRAM_0x27
      INCF LRAM_0x28,W
      MOVWF LRAM_0x2B
      GOTO LADR_0x03DB
  LADR_0x03D9
      BCF STATUS,C
      RRF LRAM_0x25,F
  LADR_0x03DB
      DECFSZ LRAM_0x2B,F
      GOTO LADR_0x03D9
      MOVLW 0x01
      BCF STATUS,RP0      ; BANK 0
      ANDWF LRAM_0x25,F
      DECFSZ LRAM_0x25,W
      GOTO LADR_0x03E3
      CALL WHAT_LED_UP    ; NEVER
  LADR_0x03E3
      MOVF LRAM_0x28,W
      XORLW 0x07
      BTFSC STATUS,Z
      BTFSC LRAM_0x21,0
      GOTO LADR_0x03EC
      CLRF LRAM_0x28
      MOVF LRAM_0x24,W
      MOVWF LRAM_0x25
      RETURN
  LADR_0x03EC
      MOVF LRAM_0x28,F
      BTFSC STATUS,Z
      BTFSS LRAM_0x21,0
      GOTO LADR_0x03F5
      MOVLW 0x07
      MOVWF LRAM_0x28
      MOVF LRAM_0x24,W
      MOVWF LRAM_0x25
      RETURN
  LADR_0x03F5
      BTFSC LRAM_0x21,0
      GOTO LADR_0x03FB
      INCF LRAM_0x28,F
      MOVF LRAM_0x27,W
      MOVWF LRAM_0x25
      RETURN
  LADR_0x03FB
      DECF LRAM_0x28,F
      MOVF LRAM_0x27,W
      MOVWF LRAM_0x25
      RETURN
      
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ;
  ; cracked part :
  ;
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ; Configuration bits
  ; 
  ; Address Value Category              Setting
  ; --------------------------------------------------------
  ; 2007    3F84  Oscillator            Internal RC No Clock
  ;               Watching Timer        Off
  ;               Power Up Timer        On
  ;               Master Clear Enable   Internal
  ;               Brown Out Detect      Off
  ;               Code Protect          Off
  ;               Data EE Read Protect  Off
  ;    
  ; Pickit 1 Schematics                
  ; -------------------
  ;
  ; CONNECTOR:
  ;
  ; J3:   1  RA5         PIN
  ;       2  RA4         Sequence 
  ;       3  RA3         As
  ;       4  RC5         PINs
  ;       5  RC4         ON
  ;       6  RC3         CHIP
  ;       7  RA0
  ;       8  RA1
  ;       9  RA2
  ;      10  RC0
  ;      11  RC1
  ;      12  RC2          C8 0.1uF
  ;      13  +5_SWITCHED  ---||--+
  ;      14  GND          -------+
  ;      
  ; BUTTON:
  ; 
  ;          D12       R3 1K       R2 10K
  ; VPP o---|>|---+---\/\/\---+---\/\/\---o +5_SWITCHED
  ;               |           o
  ;               |        --|   
  ;               |           o
  ;               o           |
  ;              RA3         -+-
  ;
  ; POTENTIOMETER:
  ;
  ; +5_SWITCHED o---\/\/\/\---o GND
  ;                    ^
  ;             R4 1K  |  C2 1000pF
  ;     RA0 o---\/\/\--+--||--o GND
  ;
  ; LEDS
  ; 
  ;   |       D11       |        
  ;   +-------|<|-------+
  ;   |                 |        (DB)(DA)(D9)(D8)
  ;   |       D10       |        (D7)(D6)(D5)(D4)
  ;   +-------|>|-------+        (D3)(D2)(D1)(DO) 
  ;   |                 |    
  ;   |          D9     |    
  ;   |     +----|<|----+        Sequence follows:
  ;   |     |           |        6 0 7 3 5 4 2 1
  ;   |     |    D8     |        
  ;   |     +----|>|----+        D6_UP  D6 UP
  ;   |     |           |        D0_UP  D0 UP
  ;   |     | D3        |        D7_UP  D7 UP
  ;   +-------|<|-+     |        D3_UP  D3 UP
  ;   |     |     |     |        D5_UP  D5 UP
  ;   | D2  |     |     |        D4_UP  D4 UP
  ;   +-|>|-------+     |        D2_UP  D2 UP
  ;   |     |     |     |        D1_UP  D1 UP
  ;   | D1  | D5  | D7  |    
  ;   +-|<|-+-|<|-+-|<|-+
  ;   |     |     |     |    
  ;   | D0  | D4  | D6  |    
  ;   +-|>|-+-|>|-+-|>|-+
  ;   |     |     |     |
  ; R5|   R6|   R7|   R8|
  ; [150] [150] [150] [150]
  ;   |     |     |     |
  ;   RA4   RA5   RA2   RA1
  ;
  ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  SETUP_CHIP               ; Setup

      MOVLW 0x34           ; bit 7-2: (CAL5-CAL0) 6-bit Signed 
                           ; Oscillator Calibration bits 111111
                           ; max frequency 000000 min frequency
      BSF   STATUS,RP0     ; BANK 1
      MOVWF OSCCAL         ; OSCCAL = W
      CLRF  VRCON          ; VRCON = 0 (Vref = 0 for comparator)
      MOVLW 0x80
      MOVWF TMR0           ; OPTION_REG = W
      BSF   IOCA,IOC3      ; Interrupt on change control bits 5:0
                           ; IOCA register must also be enabled.
      BSF   PIE1,ADIE      ; A/D Converter Interrupt Enable bit

      BCF   STATUS,RP0     ; BANK 0
      BSF   INTCON,GIE     ; Enable all unmasked interrupts
      BSF   INTCON,RAIE    ; Enables the PORTA change interrupt
      BSF   INTCON,T0IE    ; TMR0 Overflow Interrupt Enable bit
      MOVLW 7
      MOVWF CMCON          ; Comparator Control Register: 
                           ; Comparator Off
      CLRF  TMR0           ; TMR0 = 0
      MOVLW 0x01
      MOVWF ADCON0         ; ADCON0 = 0x01 A/D channel 000 ON
      BCF   PIR1,ADIF      ; The A/D conversion is not complete
      BCF   INTCON,T0IF    ; TMR0 register did not overflow
      BCF   INTCON,RAIF    ; None of the PORTA <5:0> pins have 
                           ; changed state

      BSF   STATUS,RP0     ; BANK 1
      MOVLW 0xFF
      MOVWF TRISA          ; TRISA = 0xFF
      BCF   STATUS,RP0     ; BANK 0
      CLRF  PORTA          ; PORTA = 0
   
  ; INIT VARIABLES

      BCF   STATUS,RP0     ; BANK 0
      BCF   LRAM_0x21,0
      CLRF  LRAM_0x28      ; LRAM_0x28 = 0
      MOVLW 0x03
      MOVWF LRAM_0x22      ; LRAM_0x22 = 3

      RETURN
      
  ; .............................................................

  DELAY_WRAP
      BCF   STATUS,RP0     ; BANK 0
      MOVF  LRAM_0x22, W   ; LRAM_0x22 = W
      CALL  DELAY_WBYW     ; just wait W * W loops
      BTFSC PORTA,3        ; Bit test A:3 skip if clear
      RETLW 0x00           ; returns 0 if not pressed
      RETLW 0x01           ; returns 1 if pressed
      
  ; .............................................................

  D0_UP                    ; D0 UP
      MOVLW 0xCF           ; ii00iiii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11001111
      MOVLW 0x10           ; 00010000  V4=HI V5=LO  D0
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00010000       
      RETURN

  D1_UP                    ; D1 UP
      MOVLW 0xCF           ; iiooiiii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11001111
      MOVLW 0x20           ; 00100000  V5=HI V4=LO  D1
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00100000
      RETURN

  D2_UP                    ; D2 UP
      MOVLW 0xEB           ; iiioioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11101011
      MOVLW 0x10           ; 00010000  V4=HI V2=LO  D2
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00010000       
      RETURN              

  D3_UP                    ; D3 UP
      MOVLW 0xEB           ; iiioioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11101011
      MOVLW 0x04           ; 00000100  V2=HI V4=LO  D3
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN
      
  D4_UP                    ; D4 UP
      MOVLW 0xDB           ; iioiioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11011011
      MOVLW 0x20           ; 00100000  V5=HI V2=LO  D4
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00100000       
      RETURN

  D5_UP                    ; D5 UP
      MOVLW 0xDB           ; iioiioii
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11011011
      MOVLW 0x04           ; 00000100  V2=HI V5=LO  D5
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN

  D6_UP                    ; D6 UP
      MOVLW 0xF9           ; iiiiiooi
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11111001
      MOVLW 0x04           ; 00000100  V2=HI V1=LO  D6
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000100       
      RETURN
      
  D7_UP                    ; D7 UP
      MOVLW 0xF9           ; iiiiiooi
      BSF STATUS,RP0       ; Bank 1
      MOVWF PORTA          ; TRISA = 0b11111001
      MOVLW 0x02           ; 00000010  V1=HI V2=LO  D7
      BCF STATUS,RP0       ; Bank 0
      MOVWF PORTA          ; PORTA = 0b00000010       
      RETURN

  ; .............................................................

  DELAY_WBYW               ; DELAY BY w * w (DOUBLELOOP)
      BCF STATUS,RP0       ; BANK 0
      MOVWF DELAY_C0       ; DELAY_C0 = W
      MOVWF DELAY_C1       ; DELAY_C1 = W
      GOTO IS_C1_ZERO
      
  DLOOP_0
      MOVLW 0xFF           ; 
      MOVWF DELAY_C2       ; DELAY_C2 = 0xFF
  DLOOP_1
      MOVF DELAY_C2,F      ; is DELAY_C2 == 0 ?
      BTFSC STATUS,Z       ; 
      GOTO DECREMENT_C1    ; Yes Z=1, [DELAY_C1]--
      DECF DELAY_C2,F      ; [DELAY_C2]--
      GOTO DLOOP_1
  DECREMENT_C1              
      DECF DELAY_C1,F
      
  IS_C1_ZERO
      MOVF DELAY_C1,F      ; is DELAY_C1 == 0 ?
      BTFSC STATUS,Z       ;
      RETURN               ; Yes Z=1, [DELAY_C1] contains 0
      GOTO DLOOP_0         ; No, loop

  WHAT_LED_UP              ; WHAT_LED - decide with LRAM_0x28
      BCF STATUS,RP0       ; BANK 0
      MOVF LRAM_0x28,W     ; W = LRAM_0x28; Z affected by MOVF
  ;   XORLW 0x00           ; Z flag is set by XOR if result !0
      BTFSC STATUS,Z       ; W == 00000000 ? D0 : skip
      GOTO D0_UP           ; D0_UP                
      XORLW 0x01           ; invert bit 0:                    1         
      BTFSC STATUS,Z       ; W == 00000001 ? D1 : skip
      GOTO D1_UP           ; D1_UP                
      XORLW 0x03           ; invert bit 1 and bit 0 back:     2         
      BTFSC STATUS,Z       ; W == 00000101 ? D2 : skip
      GOTO D2_UP           ; D2_UP                
      XORLW 0x01           ; invert bit 0:                    3    
      BTFSC STATUS,Z       ; W == 00000100 ? D3 : skip
      GOTO D3_UP           ; D3_UP                
      XORLW 0x07           ; invert bit 2 and bits 1,0 back   4
      BTFSC STATUS,Z       ; W == 01000100 ? D4 : skip 
      GOTO D4_UP           ; D4_UP                
      XORLW 0x01           ; invert bit 0                     5         
      BTFSC STATUS,Z       ; W == 01000101 ? D5 : skip
      GOTO D5_UP           ; D5_UP                
      XORLW 0x03           ; invert bit 1 and bit 0 back      6
      BTFSC STATUS,Z       ; W == 01000001 ? D6 : skip
      GOTO D6_UP           ; D6_UP                
      XORLW 0x01           ; invert bit 0                     7    
      BTFSS STATUS,Z       ; W == 01000000 ? D7 : skip
      RETURN
      GOTO D7_UP           ; D7_UP
      
      END

----------

Appendix G. Prehistory

LEDS, P16F676, 2007

  L1:     BSF      STATUS,RP0
          CLRF     0x11
          BCF      STATUS,RP0
          MOVLW    7
          MOVWF    0x19

  XXX:    BSF      STATUS, RP0
          MOVLW    0xCF
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x10
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xCF
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x20
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xEB
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x10
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xEB
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x04
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xDB
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x20
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xDB
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x04
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xF9
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x04
          MOVWF    PORTA
          CALL     TAU

          BSF      STATUS, RP0
          MOVLW    0xF9
          MOVWF    TRISA
          BCF      STATUS, RP0

          MOVLW    0x02
          MOVWF    PORTA
          CALL     TAU
          GOTO     XXX

  TAU:    MOVLW 0x01
          MOVWF 0x20
  DELAY3: MOVLW 0xFF
          MOVWF 0x21
  DELAY2: MOVLW 0xFF
          MOVWF 0x22
  DELAY1: DECFSZ 0x22,1
          GOTO  DELAY1
          DECFSZ 0x21,1
          GOTO  DELAY2
          DECFSZ 0x20,1
          GOTO  DELAY3
          RETURN
        
----------

MOTOR P16F676, PICSIMULATORIDE, 2007

  COUNTER EQU   0x30
  MASK    EQU   7
  TOP     EQU   0x20
  SUUND   EQU   PORTA

  L1:     BSF   STATUS,RP0
          CLRF  0x11
          BCF   STATUS,RP0
          MOVLW 0x07
          MOVWF 0x19

          BSF   STATUS,RP0
          CLRF  TRISC
          MOVLW 0xFF
          MOVWF TRISA
          BCF   STATUS,RP0

          CALL  FILLF
          CLRF  COUNTER

  L2:     MOVF  COUNTER,W
          ANDLW MASK
          ADDLW TOP
          MOVWF FSR

          MOVF  INDF, W
          MOVWF PORTC

          BTFSS SUUND, 0
          INCF  COUNTER, F
          BTFSC SUUND, 0
          DECF  COUNTER, F
          CALL  DELAY
          GOTO  L2

  FILLF:  MOVLW 2
          MOVWF 0x20
          MOVLW 6
          MOVWF 0x21
          MOVLW 4
          MOVWF 0x22
          MOVLW 12
          MOVWF 0x23
          MOVLW 8
          MOVWF 0x24
          MOVLW 9
          MOVWF 0x25
          MOVLW 1
          MOVWF 0x26
          MOVLW 3
          MOVWF 0x27
          RETURN

  DELAY:  NOP
          NOP
          NOP
          NOP
          RETURN
        
----------

  ; Timer P16F676, 2008
  ; Fixed and tested with PIC KIT 1 
  ; compiled with MPLAB v.6

  INCLUDE "P16f676.INC"

          __CONFIG 0x3194

  TAU     EQU     0x00
  MEM     EQU     0x30

  ; RESET

        ORG     0
        GOTO    MAIN

  ; INTERRUPT VECTOR

        ORG     4
        INCF    MEM, F
        MOVF    MEM, W
        MOVWF   PORTA
        BCF     INTCON, T0IF     ; REENABLE INTERRUPT: TMR0 
                                 ; REGISTER HAS OVERFLOWED (MUST 
                                 ; BE CLEARED IN SOFTWARE)
        RETFIE
        
  MAIN:

  ; [ SETUP ]....................................................

        MOVLW   0x07             ; COMPARATOR OFF (LOWEST POWER)
        MOVWF   CMCON

        BSF     STATUS,RP0       ; BANK 1
        CLRF    ANSEL            ; ANS<7:0>: Analog Select 
                                 ; between analog or digital 
                                 ; function on pins AN<7:0>, 
                                 ; respectively: 1 = Analog 
                                 ; input. Pin is assigned as 
                                 ; analog input. 0 = Digital 
                                 ; I/O. Pin is assigned to port 
                                 ; or special function.
        MOVLW   0xCF             ; iiooiiii
        MOVWF   TRISA            ; configure 2 outputs
        BCF     STATUS,RP0       ; BANK 0

        CLRF    0x30             ; 0x30 = 0 
        CLRF    PORTA            ; PORTA = 0

        MOVLW   TAU
        MOVWF   TMR0             ; TMR0 = TAU

        BSF     STATUS, RP0      ; BANK 1

        BCF     OPTION_REG, PSA  ; PRESCALER ASSIGNED TO TIMER0
        BSF     OPTION_REG, PS2  ;
        BSF     OPTION_REG, PS1  ; TMR0 RATE 1 : 256
        BSF     OPTION_REG, PS0  ;
        BCF     OPTION_REG, T0CS ; INTERNAL INSTRUCTION CYCLE
                                 ; CLOCK (CLKOUT)
        BCF     STATUS, RP0      ; BANK 0

        BSF     INTCON, GIE      ; ENABLE ALL UNMASKED INTERRUPTS
        BSF     INTCON, T0IE     ; ENABLE TMR0 OVERFLOW INTERRUPT
        
  ; [ END SETUP ]................................................

  LOOP: GOTO LOOP                ; DO NOTHING

        END

  ----------

  PIC16F84A Pin Diagram


               ---- ----
        RA2 --|    V    |-- RA1       1024 x 14b Program memory
        RA3 --|         |-- RA0         68b      Data RAM
  RA4/TOCKI --|         |-- OSC1/CLKIN  64b      Data EEPROM
      !MCLR --|         |-- OSC2/CLKOUT  8 level hardware stack
        Vss --|         |-- Vdd         25 ma    Direct LED drive
    RB0/INT --|         |-- RB7       TMR0       8b timer/counter
        RB1 --|         |-- RB6
        RB2 --|         |-- RB5
        RB3 --|         |-- RB4
               ---------


  TABLE 7-2: PIC16CXXX INSTRUCTION SET   
  ---------------------------
  Mnemonic     14-bit Opcode      Status  Description                   Cyc- Notes
  Operands     Msb           Lsb                                        les     
  ---------------------------
  BYTE-ORIENTED FILE REGISTER OPERATIONS

  ADDWF  f, d  00 0111 dfff ffff  CDZ     Add W and f                   1    1,2
  ANDWF  f, d  00 0101 dfff ffff    Z     AND W with f                  1    1,2
  CLRF   f     00 0001 lfff ffff    Z     Clear f                       1    2
  CLRW         00 0001 0xxx xxxx    Z     Clear W                       1
  COMF   f, d  00 1001 dfff ffff    Z     Complement f                  1    1,2
  DECF   f, d  00 0011 dfff ffff    Z     Decrement f                   1    1,2
  DECFSZ f, d  00 1011 dfff ffff          Decrement f, Skip if 0        1(2) 1,2,3
  INCF   f, d  00 1010 dfff ffff    Z     Increment f                   1    1,2
  INCFSZ f, d  00 1111 dfff ffff          Increment f, Skip if 0        1(2) 1,2,3
  IORWF  f, d  00 0100 dfff ffff    Z     Inclusive OR W with f         1    1,2
  MOVF   f, d  00 1000 dfff ffff    Z     Move f                        1    1,2
  MOVWF  f     00 0000 lfff ffff          Move W to f                   1 
  NOP          00 0000 0xx0 0000          No Operation                  1 
  RLF    f, d  00 1101 dfff ffff  C       Rotate Left f through Carry   1    1,2
  RRF    f, d  00 1100 dfff ffff  C       Rotate Right f through Carry  1    1,2
  SUBWF  f, d  00 0010 dfff ffff  CDZ     Subtract W from f             1    1,2
  SWAPF  f, d  00 1110 dfff ffff          Swap nibbles in f             1    1,2
  XORWF  f, d  00 0110 dfff ffff    Z     Exclusive OR W with f         1    1,2

  BIT-ORIENTED FILE REGISTER OPERATIONS

  BCF    f, b  01 00bb bfff ffff          Bit Clear f                   1    1,2
  BSF    f, b  01 01bb bfff ffff          Bit Set f                     1    1,2
  BTFSC  f, b  01 10bb bfff ffff          Bit Test f, Skip if Clear     1(2)   3
  BTFSS  f, b  01 11bb bfff ffff          Bit Test f, Skip if Set       1(2)   3

  LITERAL AND CONTROL OPERATIONS

  ADDLW  k     11 111x kkkk kkkk  CDZ     Add literal and W             1
  ANDLW  k     11 1001 kkkk kkkk    Z     AND literal with W            1  
  CALL   k     10 0kkk kkkk kkkk          Call subroutine 2 
  CLRWDT       00 0000 0110 0100  !To,!Pd Clear Watchdog Timer          1  
  GOTO   k     10 1kkk kkkk kkkk          Go to address                 2 
  IORLW  k     11 1000 kkkk kkkk    Z     Inclusive OR literal with W   1  
  MOVLW  k     11 00xx kkkk kkkk          Move literal to W             1 
  RETFIE       00 0000 0000 1001          Return from interrupt         2 
  RETLW  k     11 01xx kkkk kkkk          Return with literal in W      2 
  RETURN       00 0000 0000 1000          Return from Subroutine        2 
  SLEEP        00 0000 0110 0011  !To!Pd  Go into standby mode          1
  SUBLW  k     11 110x kkkk kkkk  CDZ     Subtract W from literal       1 
  XORLW  k     11 1010 kkkk kkkk    Z     Exclusive OR literal with W   1

  Note 1: When an I/O register is modified as a function of itself 
          (e.g., MOVF PORTB, 1), the value used will be that value 
          present on the pins themselves. For example, if the data 
          latch is '1' for a pin configured as input and is driven 
          low by an external device, the data will be written back 
          with a '0'.

       2: If this instruction is executed on the TMR0 register 
          (and, where applicable, d = 1), the prescaler will be 
          cleared if assigned to the Timer0 Module.

       3: If Program Counter (PC) is modified or a conditional 
          test is true, the instruction requires two cycles. The 
          second cycle is executed as a NOP.


TABLE 2-1: SPECIAL FUNCTION REGISTER FILE SUMMARY
----------------------
                                                                    Value on
  Addr Name        Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Power-on
                                                                     RESET
  ----------------------
  Bank 0
  ----------------------
  00h  INDF        Uses contents of FSR to address Data Memory      ---- ----
  01h  TMR0        8-bit Real-Time Clock/Counter                    xxxx xxxx
  02h  PCL         Low Order 8 bits of the Program Counter (PC)     0000 0000 
  03h  STATUS (2)  IRP   RP1   RP0   !TO   !PD   Z     D     C      0001 1xxx 
  04h  FSR         Indirect Data Memory Address Pointer 0           xxxx xxxx
  05h  PORTA (4)   -     -     -  RA4/T0CKI RA3  RA2  RA1    RA0    ---x xxxx
  06h  PORTB (5)   RB7   RB6   RB5   RB4   RB3   RB2  RB1  RB0/INT  xxxx xxxx
  07h  -           Unimplemented location, read as '0'              000000000
  08h  EEDATA      EEPROM Data Register                             xxxx xxxx
  09h  EEADR       EEPROM Address Register                          xxxx xxxx
  0Ah  PCLATH      --- Write Buffer for upper 5 bits of the PC (1)  ---0 0000
  0Bh  INTCON      GIE   EEIE  T0IE  INTE  RBIE  T0IF INTF   RBIF   0000 000x
  ----------------------
  Bank 1
  ----------------------
  80h  INDF        Uses Contents of FSR to address Data Memory      ---- ----
  81h  OPTION      RBPU  INTEDG T0CS T0SE  PSA   PS2   PS1   PS0    1111 1111
  82h  PCL         Low order 8 bits of Program Counter (PC)         0000 0000
  83h  STATUS (2)  IRP   RP1   RP0   TO    PD    Z     D     C      0001 1xxx
  84h  FSR         Indirect data memory address pointer 0           xxxx xxxx
  85h  TRISA       -     -     -     PORTA Data Direction Register  ---1 1111
  86h  TRISB       PORTB Data Direction Register                    1111 1111
  87h  -           Unimplemented location, read as '0'              0000 0000
  88h  EECON1      -     -     -     EEIF  WRERR WREN  WR    RD     ---0 x000
  89h  EECON2      EEPROM Control Register 2                        ---- ----
  0Ah  PCLATH      --- Write buffer for upper 5 bits of the PC (1)  ---0 0000
  0Bh  INTCON      GIE   EEIE  T0IE  INTE  RBIE  T0IF  INTF  RBIF   0000 000x

  Legend: x = unknown, u = unchanged. - = unimplemented, read as 
          '0', q = value depends on condition

  Note 1: The upper byte of the program counter is not directly 
          accessible. PCLATH is a slave register for PC<12:8>. 
          The contents of PCLATH can be transferred to the upper 
          byte of the program counter, but the contents of 
          PC<12:8> are never transferred to PCLATH.
       2: The TO and PD status bits in the STATUS register are 
          not affected by a MCLR Reset. 
       3: Other (non power-up) RESETS include: external RESET 
          through MCLR and the Watchdog Timer Reset.
       4: On any device RESET, these pins are configured as 
          inputs.
       5: This is the value that will be in the port output latch.

  REGISTER 2-1: STATUS REGISTER (ADDRESS 03h, 83h)                    
  ------------------------------------------------
  bit 7                                   bit 0
  ------------------------------------------------
  R/W-0 R/W-0 R/W-0 R-1   R-1 R/W-x R/W-x R/W-x
  IRP   RP1   RP0   !TO   !PD  Z     D     C
  ------------------------------------------------

  Legend:

  R   = Readable bit   
  W   = Writable bit   
  U   = Unimplemented bit, read as '0'
  !n  = Value at POR   
  '1' = Bit is set    
  '0' = Bit is cleared 
  x   = Bit is unknown

  bit 7-6     Unimplemented: Maintain as '0'

  bit 5  RP0: Register Bank Select bits (used for direct 
              addressing)
              01 = Bank 1 (80h - FFh)
              00 = Bank 0 (00h - 7Fh)

  bit 4  TO:  Time-out bit
              1 =  After power-up, CLRWDT instruction, or SLEEP 
                   instruction
              0 =  A WDT time-out occurred

  bit 3  PD:  Power-down bit
              1 =  After power-up or by the CLRWDT instruction
              0 =  By execution of the SLEEP instruction

  bit 2  Z:   Zero bit
              1 = The result of an arithmetic or logic operation 
                  is zero
              0 = The result of an arithmetic or logic operation 
                  is not zero

  bit 1  D:   Digit carry/borrow bit (ADDWF, ADDLW, SUBLW, SUBWF 
              instructions) for borrow, the polarity is reversed.
              1 = A carry-out from the 4th low order bit of the 
                  result occurred
              0 = No carry-out from the 4th low order bit of the 
                  result
  bit 0  C:   Carry/borrow bit (ADDWF, ADDLW, SUBLW, SUBWF 
              instructions) for borrow, the polarity is reversed.
              1 = A carry-out from the MSB of the result occurred
              0 = No carry-out from the MSB of the result occurred

  Note: A subtraction is executed by adding the two's complement 
        of the second operand. For rotate (RRF, RLF) instructions, 
        this bit is loaded with either the high or low order bit 
        of the source register.


Example
-------

  ---------------------------------------------
  PIC ASSEMBLER LISTING
  Line    Address Opcode  Instruction
  ---------------------------------------------
  0001    0000    1683       BSF   STATUS,RP0
  0002    0001    0186       CLRF  TRISB
  0003    0002    1283       BCF   STATUS,RP0
  0004    0003    3013       MOVLW 13h
  0005    0004    0086       MOVWF PORTB
  0006    0005    2805    A: GOTO  A
  0007    0006               END
  ---------------------------------------------
  Number of errors = 0

Hex file (produced by PicSimulatorIDE 5.83)

  :0C00000083168601831213308600052849
  :02400E00F13F80
  :00000001FF

Binary dump (produced with Hex 2 Bin)

  00000000:  83 16 86 01 83 12 13 30 ³ 86 00 05 28 00 00 00 00
