;    t1_test2.asm - 2nd test for 3niti alpha simu1 (updated 27 Nov 2009)
;    TERNARY CLOCK: HOURS - 4 TRITS, MINUTES - 4 TRITS, SECONDS - 4 TRITS
;
;    Part of NedoPC SDK (software development kit for simple devices)
;
;    Copyright (C) 2009, Alexander A. Shabarshin <ashabarshin@gmail.com>
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	processor pic16f870
	radix dec
	include "p16f870.inc"
	__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
	include "shaos-p16.inc"

; PORTA - outputs to choose column (A0...A4) and direct LED (A5)
; PORTB - inputs for rows of switches (B0...B5) and I2C (B6,B7)
; PORTC - outputs for rows of LEDs (C0...C5) and RS232 (C6,C7)

BSIZE	EQU	27 ; -13...+13
INTCNT	EQU	3

; Specific vars 0x20...0x6F (banks 0 and 2)

c_base	EQU	32 ; ternary code segment 0x20...0x3A
d_base	EQU	59 ; ternary data segment 0x3B...0x55 (may be used as 2nd code segment)
e_base	EQU	86 ; end of segments (0x56)
c_addr	EQU	0x57
d_addr	EQU	0x58
CA_m	EQU	0x59 ; current code segment address (middle and high parts)
CA_h	EQU	0x5A
DA_m	EQU	0x5B ; current data segment address (middle and high parts)
DA_h	EQU	0x5C
PC_l	EQU	0x5D ; PC
PC_m	EQU	0x5E
PC_h	EQU	0x5F
DPn_l	EQU	0x60 ; DPn
DPn_m	EQU	0x61
DPn_h	EQU	0x62
DPo_l	EQU	0x63 ; DPo
DPo_m	EQU	0x64
DPo_h	EQU	0x65
DPp_l	EQU	0x66 ; DPp
DPp_m	EQU	0x67
DPp_h	EQU	0x68
F_reg	EQU	0x69 ; Register F (RSF,DPF,BCF)
A_reg	EQU	0x6A ; Register A
B_reg	EQU	0x6B ; Register B
C_reg	EQU	0x6C ; ???
D_reg	EQU	0x6D ; Data to display on LEDs 10,11,12

; Specific vars 0xA0...0xBF (banks 1 and 3)

; Global vars 0x70...0x7F (all banks)

swit0	EQU	0x70 ; copy of switch row 0
swit1	EQU	0x71 ; copy of switch row 1
swit2	EQU	0x72 ; copy of switch row 2
swit3	EQU	0x73 ; copy of switch row 3
swit4	EQU	0x74 ; copy of switch row 4
cnt1	EQU	0x75
cnt2	EQU	0x76
tmp0	EQU	0x77
tmp1	EQU	0x78
tmp2	EQU	0x79
tmp3	EQU	0x7A
mask	EQU	0x7B
count	EQU	0x7C
savedT	EQU	0x7D ; saved TMP
savedW	EQU	0x7E ; saved W
savedS	EQU	0x7F ; saved STATUS


; Reset vector
	ORG 00h
	goto Start

; Interrupt vector
	ORG 04h
	movwf	savedW
	_movrr	STATUS,savedS
	_bank0

	btfss	INTCON,T0IF
	goto	intend

;	_movrr	tmp1,savedT
	decfsz	tmp0,f
	goto	intend1
	_movlr	INTCNT,tmp0

	btfss	C_reg,5
	goto	ii_1
	bcf	C_reg,5
	bsf	C_reg,4
	goto	ii_2
ii_1:	btfss	C_reg,4
	bsf	C_reg,5
	bcf	C_reg,4
	goto	intend1
ii_2:	btfss	C_reg,3
	goto	ii_3
	bcf	C_reg,3
	bsf	C_reg,2
	goto	ii_4
ii_3:	btfss	C_reg,2
	bsf	C_reg,3
	bcf	C_reg,2
	goto	intend1
ii_4:	btfss	C_reg,1
	goto	ii_5
	bcf	C_reg,1
	bsf	C_reg,0
	goto	ii_6
ii_5:	btfss	C_reg,0
	bsf	C_reg,1
	bcf	C_reg,0
	goto	intend1
ii_6:
	btfss	D_reg,5
	goto	ii1
	bcf	D_reg,5
	bsf	D_reg,4
	goto	ii2
ii1:	btfss	D_reg,4
	bsf	D_reg,5
	bcf	D_reg,4
	goto	iiM
ii2:	btfss	D_reg,3
	goto	ii3
	bcf	D_reg,3
	bsf	D_reg,2
	goto	ii4
ii3:	btfss	D_reg,2
	bsf	D_reg,3
	bcf	D_reg,2
	goto	iiM
ii4:	btfss	D_reg,1
	goto	ii5
	bcf	D_reg,1
	bsf	D_reg,0
	goto	ii6
ii5:	btfss	D_reg,0
	bsf	D_reg,1
	bcf	D_reg,0
	goto	iiM
ii6:	btfss	PC_l,5
	goto	ii7
	bcf	PC_l,5
	bsf	PC_l,4
	goto	iiM
ii7:	btfss	PC_l,4
	bsf	PC_l,5
	bcf	PC_l,4

iiM:	movf	D_reg,w
	sublw	b'00001000'
	btfss	STATUS,Z
	goto	intend1
	btfsc	PC_l,4
	goto	intend1
	btfss	PC_l,5
	goto	intend1
	movlw	b'00000100'
	movwf	D_reg
	bsf	PC_l,4
	bcf	PC_l,5

	btfss	PC_l,3
	goto	ii8
	bcf	PC_l,3
	bsf	PC_l,2
	goto	ii9
ii8:	btfss	PC_l,2
	bsf	PC_l,3
	bcf	PC_l,2
	goto	iiH
ii9:	btfss	PC_l,1
	goto	ii10
	bcf	PC_l,1
	bsf	PC_l,0
	goto	ii11
ii10:	btfss	PC_l,0
	bsf	PC_l,1
	bcf	PC_l,0
	goto	iiH
ii11:	btfss	PC_m,5
	goto	ii12
	bcf	PC_m,5
	bsf	PC_m,4
	goto	ii13
ii12:	btfss	PC_m,4
	bsf	PC_m,5
	bcf	PC_m,4
	goto	iiH
ii13:	btfss	PC_m,3
	goto	ii14
	bcf	PC_m,3
	bsf	PC_m,2
	goto	iiH
ii14:	btfss	PC_m,2
	bsf	PC_m,3
	bcf	PC_m,2

iiH:	movf	PC_l,w
	andlw	b'00001111'
	sublw	b'00000010'
	btfss	STATUS,Z
	goto	intend1
	movf	PC_m,w
	andlw	b'00111100'
	sublw	b'00001000'
	btfss	STATUS,Z
	goto	intend1
	bsf	PC_l,0
	bcf	PC_l,1
	bsf	PC_m,2
	bcf	PC_m,3

	btfss	PC_m,1
	goto	ii15
	bcf	PC_m,1
	bsf	PC_m,0
	goto	ii16
ii15:	btfss	PC_m,0
	bsf	PC_m,1
	bcf	PC_m,0
	goto	iiD
ii16:	btfss	PC_h,5
	goto	ii17
	bcf	PC_h,5
	bsf	PC_h,4
	goto	ii18
ii17:	btfss	PC_h,4
	bsf	PC_h,5
	bcf	PC_h,4
	goto	iiD
ii18:	btfss	PC_h,3
	goto	ii19
	bcf	PC_h,3
	bsf	PC_h,2
	goto	ii20
ii19:	btfss	PC_h,2
	bsf	PC_h,3
	bcf	PC_h,2
	goto	iiM
ii20:	btfss	PC_h,1
	goto	ii21
	bcf	PC_h,1
	bsf	PC_h,0
	goto	iiD
ii21:	btfss	PC_h,0
	bsf	PC_h,1
	bcf	PC_h,0

iiD:	btfsc	PC_m,0
	goto	intend1
	btfsc	PC_m,1
	goto	intend1
	movf	PC_h,w
	sublw	b'00100010'
	btfss	STATUS,Z
	goto	intend1
	clrf	PC_h

intend1:
;	_movrr	savedT,tmp1
	_movlr	15,TMR0
	bcf	INTCON,T0IF
intend:
	_movrr	savedS,STATUS
	movf	savedW,w
	retfie

Start:

; Configure all I/O pins as digital
	_bank1
	_movlr 0x06,ADCON1

; Set direction of ports
	_bank1
	_movlr b'00000000',TRISA
	_movlr b'00111111',TRISB
	_movlr b'00000000',TRISC

; Initialize output ports
	_bank0
	_movlr b'11111111',PORTA
	_movlr b'11111111',PORTB
	_movlr b'11111111',PORTC

; Setup interrupts
	_bank1
	clrf	INTCON ; disable all interrupts and clear all flags
	bcf	OPTION_REG,NOT_RBPU ; enable pull-ups
	bsf	OPTION_REG,INTEDG ; interrupt on rising edge
	bcf	OPTION_REG,T0CS ; enable Timer0 in timer mode
	bcf	OPTION_REG,PSA ; assign prescaler to the Timer0 (1:256)
	bsf	INTCON,T0IE ; enable Timer0 interrupt
	bcf	INTCON,INTE ; disable RB0 port change interrupt
	bsf	INTCON,GIE ; enable interrupts

; Clear watch dog
	_bank0
	clrwdt

	goto	Main

; Ternary inversion (negation) of W (used tmp1,tmp2)
tri_neg: ; 14 cycles with call
	movwf	tmp1
	andlw	b'01010101'
	movwf	tmp2
	movf	tmp1,W
	andlw	b'10101010'
	movwf	tmp1
	bcf	STATUS,C
	rlf	tmp2,F
	rrf	tmp1,W
	iorwf	tmp2,W
	return
; P.S. it also works with inverted binary representation

; Ternary increment of W (used tmp1), C if overflow
tri_inc:
	bcf	STATUS,C
	movwf	tmp1
	btfss	tmp1,5
	goto	tri_i4
	bcf	tmp1,5
	bsf	tmp1,4
	goto	tri_i3
tri_i4:	btfss	tmp1,4
	bsf	tmp1,5
	bcf	tmp1,4
	movf	tmp1,w
	return
tri_i3:	btfss	tmp1,3
	goto	tri_i2
	bcf	tmp1,3
	bsf	tmp1,2
	goto	tri_i1
tri_i2:	btfss	tmp1,2
	bsf	tmp1,3
	bcf	tmp1,2
	movf	tmp1,w
	return
tri_i1:	btfss	tmp1,1
	goto	tri_i0
	bcf	tmp1,1
	bsf	tmp1,0
	goto	tri_ic
tri_i0:	btfss	tmp1,0
	bsf	tmp1,1
	bcf	tmp1,0
	movf	tmp1,w
	return
tri_ic: movf	tmp1,w
	bsf	STATUS,C
	return

Main:

; Initialize registers
	movlw	b'11111111'
	movwf	swit0
	movwf	swit1
	movwf	swit2
	movwf	swit3
	movwf	swit4
	clrf	PC_h
	clrf	PC_m
	clrf	PC_l
	clrf	A_reg
	clrf	B_reg
	clrf	C_reg
	clrf	D_reg
	clrf	F_reg
	_movlr	INTCNT,tmp0

	bsf	PORTA,5 ; fire LED

; Test program
loop:
	movlw	b'11111110'
	movwf	mask
	movlw	5
	movwf	count
	movlw	swit0
	movwf	FSR
loop0:	movf	mask,w
	movwf	PORTA
	_delay1 10,cnt1
	movf	PORTB,w
	call	tri_neg
	movwf	INDF
	incf	FSR,f
	btfsc	mask,0
	goto	loop1
	comf	PC_h,w
	goto	loop6
loop1:	btfsc	mask,1
	goto	loop2
	comf	PC_m,w
	goto	loop6
loop2:	btfsc	mask,2
	goto	loop3
	comf	PC_l,w
	goto	loop6
loop3:	btfsc	mask,3
	goto	loop4
	comf	D_reg,w
	goto	loop6
loop4:	comf	C_reg,w
loop6:	movwf	PORTC
	_delay1	0,cnt1
	bsf	STATUS,C
	rlf	mask,f
	decfsz	count,f
	goto	loop0
	movf	mask,w
	movwf	PORTA

	btfsc	swit4,1
	goto	loop
	comf	swit0,w
	movwf	PC_h
	comf	swit1,w
	movwf	PC_m
	comf	swit2,w
	movwf	PC_l
	comf	swit3,w
	movwf	D_reg

	goto	loop

	END
