--- /dev/null
+; -*- fundamental -*-
+
+; This program sets the LED Green and then
+; responds to instructions on the serial port
+;
+; state kept
+; E current entry
+; A current address
+;
+; prompt is `>'
+;
+; data entry
+; 0-9a-f hex digit E := E<<4 | (digit value)
+;
+; byte operations
+; CR enter address A := E
+; = confirm value print E
+; @ confirm address print A
+; ? read and display print *A
+; ! set whole byte *A := E
+; bitwise operations
+; SPC read and mask print (*A & E)
+; + bitwise or (set bits) *A := *A | E
+; - bitwise and-not (clear bits) *A := *A & ~E
+; ^ bitwise xor (toggle bits) *A := *A ^ E
+
+ include /usr/share/gputils/header/p18f458.inc
+ include insn-aliases.inc
+ radix dec
+
+e equ 0x70
+a equ FSR1L
+star_a equ INDF1
+hex_temp equ 0x72
+
+ code
+
+start
+ rcall led_green
+ rcall serial_setup
+ set_f FSR1H
+command_loop
+ mov_lw '>'
+ rcall serial_write_char
+ rcall serial_read_char
+
+check_last set 0
+checkequal macro value, label
+ add_lw check_last-value
+ bra_z label
+check_last set value
+ endm
+
+checkatleast macro minvalue, label ; if it takes, W gets char-minvalue
+ add_lw check_last-minvalue
+ bra_nn label
+check_last set minvalue
+ endm
+
+ checkequal 10, command_return
+ checkequal 13, command_return
+ checkequal '=', command_confirm_entry
+ checkequal '@', command_confirm_address
+ checkequal '?', command_byte_read
+ checkequal '!', command_byte_write
+ checkequal ' ', command_bitwise_read_mask
+ checkequal '+', command_bitwise_or
+ checkequal '-', command_bitwise_and_not
+ checkequal '^', command_bitwise_xor
+
+ checkatleast 'f'+1, command_wrong
+ checkatleast 'a', command_letterhexdigit
+ checkatleast '9'+1, command_wrong
+ checkatleast '0', command_digit
+
+command_wrong
+ mov_lw '?'
+ rcall serial_write_char
+command_endswitch
+ bra command_loop
+
+command_letterhexdigit
+ add_lw 10
+command_digit
+ mov_wf hex_temp
+ swap_fw e
+ and_lw 0xf0
+ ior_wfw hex_temp
+ mov_wf e
+ bra command_loop
+
+command_endswitch_phex
+ rcall serial_write_hex
+ bra command_endswitch
+
+command_return
+ mov_ff a,e
+ bra command_endswitch
+
+command_confirm_entry
+ mov_fw e
+ bra command_endswitch_phex
+
+command_confirm_address
+ mov_fw a
+ bra command_endswitch_phex
+
+command_byte_read
+ mov_fw star_a
+ bra command_endswitch_phex
+
+command_byte_write
+ mov_fw e
+ mov_wf star_a
+ bra command_endswitch
+
+command_bitwise_read_mask
+ mov_fw e
+ and_wfw star_a
+ bra command_endswitch_phex
+
+command_bitwise_or
+ mov_fw e
+ ior_wff star_a
+ bra command_endswitch
+
+command_bitwise_xor
+ mov_fw e
+ xor_wff star_a
+ bra command_endswitch
+
+command_bitwise_and_not
+ mov_fw e
+ com_w
+ and_wff e
+ bra command_endswitch
+
+;----------------------------------------
+led_green
+ bc_f TRISD, 2 ; enable per-pic led output
+ bs_f LATD, 2 ; set per-pic led output
+ return
+
+
+;----------------------------------------
+serial_setup
+; W undefined undefined
+; TXSTA undefined }
+ mov_lw 0x26 ; asynch xmit enabled, high baud rate, 8-bit,
+ mov_wf TXSTA ;
+ mov_lw 129 ; 9600bps (with BRGH)
+ mov_wf SPBRG
+serial_receive_reset ;from serial_read_if_error
+ mov_lw 0x90 ; enable serial port, continuous rx, 8-bit,
+ mov_wf RCSTA ; no pending errors etc.
+ return
+
+;----------------------------------------
+serial_write_char
+; W character undefined
+serial_write_char_loop
+ bt_f_if0 PIR1,TXIF
+ bra serial_write_char_loop
+ mov_wf TXREG
+ return
+
+;----------------------------------------
+serial_read_char
+; on errors, sets LED red and transmits *
+; W undefined character read
+serial_read_char_loop
+ bt_f_if0 PIR1,RCIF
+ bra serial_read_char_loop
+ mov_fw RCSTA
+ and_lw CREN | FERR | OERR
+ xor_lw CREN
+ bra_nz serial_read_if_error
+ mov_fw RCREG
+ return
+
+serial_read_if_error
+ mov_lw '*'
+ rcall serial_write_char
+ rcall serial_receive_reset
+ bra serial_read_char_loop
+
+;----------------------------------------
+serial_write_hex
+; transmits W in hex through serial port
+; Before After
+; W value undefined
+; hex_temp undefined undefined
+ mov_wf hex_temp
+ rcall serial_write_hex_digit
+ rcall serial_write_hex_digit
+ return
+
+;--------------------
+serial_write_hex_digit
+; transmits top nybble of hex_temp in hex
+; through serial port, as above, and swaps nybbles
+; Before After
+; W any undefined
+; hex_temp BBBBaaaa aaaaBBBB (BBBB was sent)
+ swap_f hex_temp
+ mov_fw hex_temp
+ and_lw 0x0f
+ sub_lw 10
+ sub_lw 0
+ bra_n serial_write_hex_digit_ifnot_ge10
+ add_lw 'a'-('0'+10)
+serial_write_hex_digit_ifnot_ge10
+ add_lw '0'+10
+ rcall serial_write_char
+
+ end
+
+
+ end
+
+ add_lw -13
+ bra_z
+ ; '2' '0'-1 '9'+1
+ add_lw -('9'+1) ; 256-C 256-11 0C
+ bra_c command_ifgtdecdigit
+ add_lw ('9'+1)-('0') ; 2
+ bra_nc command_ifltdecdigit
+
+
+ bcf TRISC, 6, 0 ; enable TXD output (RC6)
+
+
+
+ bcf TRISC, 5, 0 ; enable FCO output (RC5)
+
+
+loop
+
+ ; set a bit which says how fast the led
+ ; should flash and count down from 2^(that bit)
+ bsf COUNTOUTER, OUTEREXP, 0
+delayouter_loop
+
+delayinner_loop
+ copybit PORTB, 3, LATA, 0x08 ; A data
+ copybiti PORTD, 7, TRISA, 0x08 ; A enable
+ copybiti PORTA, 6, LATD, 0x10 ; D
+ copybit PORTB, 4, LATC, 0x20 ; serial FC
+ copybit PORTC, 7, LATC, 0x40 ; serial data
+ ; 6 x copybit @6 = 24cy
+
+ decfsz COUNTINNER, 1, 0 ; 1 cycle
+ goto delayinner_loop ; 2 cycles (skipped or not)
+; exited delayinner_loop ; total: 27cy * 256 = 6912cy
+
+ ; each cycle 0.2us
+ ; so each inner loop is ~1.4ms
+
+ decfsz COUNTOUTER, 1, 0
+ goto delayouter_loop
+; exited delayouter_loop
+
+ goto loop
+
+ end