; bfsim 2.0 ; ; http://www.robos.org ; ; BrainFuck system for pic16f84a ; ; Original version by Robert Östling, August 2003. ; Rewritten February 2004 - bug fixes. Lots of bug fixes. ; ; Note: Keep all the tables far away from any 256 words boundaries. ; ; Instructions: ; ; + 00 Increase value at pointer by one. ; - 01 Decrease value at pointer by one. ; > 02 Increase pointer by one. ; < 03 Decrease pointer by one. ; [ 04 Jump to next ] ; ] 05 Jump to previous [ unless value at pointer is zero. ; . 06 Output value at pointer to portb. ; , 07 Input value from porta (bits 1 to 3) and store to pointer. ; ; Program memory - 128 instructions (64 bytes) of EEPROM. ; RAM memory - 32 bytes (0x20 to 0x3f). ; Stack - 16 bytes (0x40 to 0x4f). ; ; I/O: ; ; porta0 - "enter" key. ; porta1 - porta3 - Input value (0 to 7). ; portb - Output (LEDs). ; ; 10000001 on the LEDs means: Input command. ; 11000011 on the LEDs means: Input data to user program. list p=PIC16F84A include "p16f84a.inc" cblock 0x0c iptr,ptr,sptr,cptr,nest,tmp endc page __config _CP_OFF & _LP_OSC & _PWRTE_ON & _WDT_OFF org 0 reset: bcf intcon,gie ; disable interrupts call initialize ; initialize vars, mem, i/o main_loop: movlw 0x81 movwf portb ; output 10000001 to portb call input clrf portb movfw tmp ; w = command andlw 0x03 addwf pcl ; execute command from keyboard: goto cmd_00 ; input opcode goto cmd_01 ; reset program pointer goto cmd_02 ; "backspace" goto cmd_03 ; run program ; input opcode cmd_00: call input ; input byte to tmp movfw cptr incf cptr movwf eeadr ; eeadr = cptr++ call nibble_write ; write to eeprom goto main_loop ; reset program pointer cmd_01: clrf cptr goto main_loop ; "backspace" cmd_02: decf cptr goto main_loop ; run program cmd_03: clrf iptr cmd_03_loop: call execute incf iptr goto cmd_03_loop ; execute one instruction execute: movfw iptr movwf eeadr ; read instruction from iptr call nibble_read addwf pcl ; execute instruction goto instr_00 ; + goto instr_01 ; - goto instr_02 ; > goto instr_03 ; < goto instr_04 ; [ goto instr_05 ; ] goto instr_06 ; . goto instr_07 ; , ; + instr_00: movfw ptr addlw 0x20 movwf fsr ; point to current memory location incf indf ; increase it return ; - instr_01: movfw ptr addlw 0x20 movwf fsr ; point to current memory location decf indf ; decrease it return ; > instr_02: incf ptr movlw 0x1f andwf ptr ; ptr = (ptr + 1) mod 0x20 return ; < instr_03: decf ptr movlw 0x1f andwf ptr ; ptr = (ptr - 1) mod 0x20 return ; [ instr_04: incf iptr ; iptr++ decf sptr movfw sptr movwf fsr movfw iptr movwf indf ; push iptr to stack movlw 0x01 movwf nest ; nest = 1 decf iptr ; now let's find the next ] instruction instr_04_find: incf iptr movfw iptr movwf eeadr call nibble_read ; read nest instruction sublw 0x05 ; is it "]" ? bz instr_04_end sublw 0x01 ; is it "[" ? btfsc status,z incf nest ; yes, increase nest goto instr_04_find instr_04_end: decf nest bnz instr_04_find ; if --nest != 0, continue decf iptr ; iptr-- return ; otherwise return to normal execution ; ] instr_05: movfw ptr addlw 0x20 movwf fsr movfw indf ; get value at current memory location sublw 0x00 bnz instr_05_loop ; is it 0? incf sptr return ; yes, drop value on stack and continue. instr_05_loop: movfw sptr movwf fsr movfw indf movwf iptr ; iptr = top of stack, don't change sptr decf iptr ; iptr-- return ; continue execution ; . instr_06: movfw ptr addlw 0x20 movwf fsr movfw indf movwf portb ; output value on current memory location to portb call input_wait ; wait for "enter" key return ; , instr_07: movlw 0xc3 movwf portb ; output 11000011 to portb movfw ptr addlw 0x20 movwf fsr ; point to current memory location call input ; read byte from keyboard movfw tmp movwf indf ; store to memory clrf portb ; clear portb return input: call input_wait ; wait for "enter" key movfw porta andlw 0x0e movwf tmp bcf status,c rrf tmp ; tmp = (byte >> 1) mod 8 return input_wait: btfss porta,0 goto input_wait ; wait for "enter" key clrf tmp input_wait1: incf tmp btfss tmp,3 goto input_wait1 ; short delay input_wait2: btfsc porta,0 goto input_wait2 ; wait for "enter" key to release return ; read nibble addressed by eeadr to w nibble_read: btfsc eeadr,0 goto nibble_read_odd ; check if we're reading an odd nibble bcf status,c rrf eeadr ; eeadr = eeadr / 2 call eeprom_read movfw eedata ; read byte to w andlw 0x0f ; mask out high 4 bits return nibble_read_odd: bcf status,c rrf eeadr ; eeadr = eeadr / 2 call eeprom_read swapf eedata ; swap high and low nibble movfw eedata andlw 0x0f ; mask out high 4 bits return ; read byte from eeadr to eedata eeprom_read: bsf status,rp0 bsf eecon1,rd bcf status,rp0 return ; write the nibble in tmp to the address in eeadr nibble_write: bcf status,c rrf eeadr ; eeadr = eeadr / 2 bc nibble_write_odd ; check if we're writing to an odd nibble call eeprom_read movfw eedata ; read byte andlw 0xf0 ; mask out low nibble addwf tmp,w ; fill it with our data goto nibble_write_done nibble_write_odd: call eeprom_read movfw eedata ; read byte andlw 0x0f ; mask out high nibble swapf tmp addwf tmp,w ; fill it with out data nibble_write_done: movwf eedata ; write the byte on eedata to the address in eeadr eeprom_write: bsf status,rp0 bsf eecon1,wren movlw 0x55 movwf eecon2 movlw 0xaa movwf eecon2 bsf eecon1,wr bcf status,rp0 return initialize: clrf porta clrf portb bsf status,rp0 movlw 0x1f movwf trisa ; set porta to input mode clrf trisb ; set portb to output mode bcf status,rp0 movlw 0x01 movwf portb demo_loop: bcf status,c rlf portb ; portb = portb << 1 btfsc status,c ; did we shift out the bit? incf portb ; yes, set portb to 1 again clrf tmp demo_delay: decfsz tmp goto demo_delay ; 10ms delay btfss porta,0 goto demo_loop ; if "enter" key is not pressed, loop call input_wait ; wait for its release clrf portb clrf iptr clrf ptr movlw 0x50 movwf sptr clrf cptr movlw 0x20 movwf fsr clear_ram: clrf indf incf fsr btfss fsr,6 goto clear_ram return end