;------------------------------------------------------------------------------
; LCDコントローラ
; Ver.0.36 2017/11/12 ノイズの対処がうまくいかなかったのでもう一度修正。
;                     LCDの温度によって他のラインにも問題が出るようだ。
; Ver.0.35 2017/11/07 イーサネットで表示すると、130,143,155ライン目の先頭8ドットにノイズが乗っていた。
;                     光を当てると脈打つ濃度むらが見えたので、COMWAITを1段階速くした。
; Ver.0.34 2017/05/09 イーサネットの画像表示ループを改良し、ループ内で35fps出るようになった。
; Ver.0.33 2017/05/01 DHCPの処理が終わったら送信と受信のバッファ割り当てを変更するようにした。
; Ver.0.32 2017/04/30 フォント修正
; Ver.0.31 2017/04/29 DHCPのタイマー作成。IP_XID更新漏れ修正。
; Ver.0.30 2017/04/27 BNRY更新をサブルーチン化し、ARPとDHCPの受信が終わったら即バッファを空けるようにした。
;		      不正な画像データを検出したフレームは破棄するように変更。
; Ver.0.29 2017/04/24 バッファサイズをケチったおかげで送信データが受信データに混入していた。
;		      正常に動作するようになったので、あとは最適化をかけるだけだ。
; Ver.0.28 2017/04/23 ICMP Reply実装
; Ver.0.27 2017/04/22 取得したアドレス類をできるようになった。
; Ver.0.26 2017/04/22 祝256ビルド、DHCPクライアントが完成。タイミングがめちゃくちゃなので整理が必要。
; Ver.0.25 2017/04/21 BNRYの計算が間違っていた。
;		      IPSTOPはやはり0x61以上を指定するとおかしい。ゴミが混じる。
;		      バッファオーバーランのスキップテスト。いじくりまわしたので、後から整理してね。
; Ver.0.24 2017/04/20 ダミー読み出しのnic_readを実装。31fpsでギリギリバッファオーバーしなくなった。
;		      イーサネットモードのUSBバッファフラッシュを実装。
; Ver.0.23 2017/04/19 DHCPのDISCOVERとREQUESTの送信ルーチン完成。
;		      フォント等の定数をページ1に移動。
; Ver.0.22 2017/04/18 IPアドレスと192.168.11.240に固定、ARPのレスポンスを実装。
; Ver.0.21 2017/04/16 オーバーフローのリセットを調整。オーバーフロー防止のパケット間ギャップは送信側で対応する。
; Ver.0.20 2017/04/16 ネットワーク経由の画像表示に成功。バッファがオーバーフローすると止まる。
; Ver.0.19 2017/04/15 イーサネットフレームの受信とダンプを作った。
; Ver.0.18 2017/04/12 USBとEtherモード切り替え。適当なパケットを送信できた。
; Ver.0.17 2017/04/09 TMR3新設。ネットワーク系の計算・送出ルーチンを追加。
; Ver.0.16 2017/04/02 無駄な部分を削除。その他整理。
; Ver.0.15 2017/04/01 文字表示ルーチンを作った。
; Ver.0.14 2017/03/16 適当にパケットを送信できるようになった。
; Ver.0.13 2017/03/12 NICの初期化ルーチンを付けた。動作は未確認。
; Ver.0.12 2017/02/19 USBモードルーチン完成。FT245の限界で最大fpsは33〜34となった。
; Ver.0.11 2017/02/17 USB受信LCD書き込みルーチンの最適タイミング版、SSPBUF間は11T以上空ける。
; Ver.0.10 2017/02/12 受信しながらダイレクトに書き込むと計算では23.6fps出るが、通信が途絶えるとLCDの書き込みも中断される。
; Ver.0.09 2017/02/12 USB経由でデータ表示ができるようになった。16.7fpsが精いっぱい。
; Ver.0.08 2017/02/04 LCD初期化ルーチン再作成、NICの検出とLAN接続の画面表示。
; Ver.0.07 2017/01/31 画像バッファを使った1ライン表示テスト。CLSルーチンの修正。
; Ver.0.06 2017/01/28 NICのネットワークリンク検出とLEDの点灯テスト。
;		      EagleのLANコネクタのライブラリが間違っていてランプがつかなかった。
;		       急遽470Ωをプルダウンに繋ぎかえて動くようになったが、表示論理が逆になった。悲しい。
; Ver.0.05 2017/01/09 LAN,USB,LCDの各ルーチンを作成、NICのID0/1の読み出しに成功。
; Ver.0.04 2017/01/08 TMR0の初期代入位置に問題があった。
;		      シリアルポートの入力を単純にエコーできるようになった。
; Ver.0.03 2017/01/03 1ラインごとの書き換えテスト。5MHzでは26fpsでほとんど変わらない。
;		      ICSPの時にDISPをGNDに落とさないと画像が表示される。
; Ver.0.02 2017/01/03 全画面一括書き換えのLCD駆動テスト。SPIクロック1.25MHzで8fps、5MHzで27fps達成。
;		      5MHzの時はBFチェックをかけずノーウエイトで実行した。
; Ver.0.01 2017/01/02 IO定義後の出力確認、SS用の端子が無効になっているか?
; Ver.0.00 2017/01/02 PICのみ実装した基板用の全出力導通検査
;------------------------------------------------------------------------------
; IRP,RP1,RP0を切り替える所で◆ RP=, ● IRP=をコメントに置く
; PCLATHを切り替える所で■ PCLATHをコメントに置く
; サブルーチンからの戻りの時、
;  RP1,RP0は0に戻してリターンする。
;  IRP,PCLATHは戻さずにリターンする。
; ルーチン呼び出しはRP=0を前提として記述する。
;------------------------------------------------------------------------------
; デバイス	PIC16F887
; 動作周波数	外部20MHz
;------------------------------------------------------------------------------
	LIST		P=PIC16F887,R=DEC,N=0;,ST=OFF
	INCLUDE		"P16F887.INC"
	ERRORLEVEL	0,-302,-306,-307
	__CONFIG _CONFIG1, 0x23C2	; OSC	= HS
					; WDTE	= DISABLE
					; PWRTE	= ENABLE
					; MCLRE	= I/O
					; CP	= DISABLE
					; CPD	= DISABLE
					; BOREN	= ENABLE
					; IESO	= DISABLE
					; FCMEN	= DISABLE
					; LVP	= I/O
					; DEBUG	= DISABLE
	__CONFIG _CONFIG2, 0x3FFF	; BOR4V	= 4.0V
					; WRT	= DISABLE
;------------------------------------------------------------------------------
MY_MAC		EQU	0x20		; 6
MY_UDP		EQU	0x26		; 2
MY_IP		EQU	0x28		; 4 Init
NETMASK		EQU	0x2C		; 4 Init
GW_IP		EQU	0x30		; 4 Init
IP_XID		EQU	0x34		; 2 Init
DHCP_XID	EQU	0x36		; 4
DHCP_STATE	EQU	0x3A		; 1 0=DHCP処理済 1=OFFER待ち 2=ACK待ち 3=バッファサイズ変更前でDHCP処理済へ遷移中
CKSUM_COUNT	EQU	0x3B		; 1
CKSUM_H		EQU	0x3C		; 1
CKSUM_L		EQU	0x3D		; 1
DST_MAC		EQU	0x3E		; 6
DST_IP		EQU	0x44		; 4
DST_UDP		EQU	0x48		; 2
;		EQU	0x4A

xPSTART		EQU	0x58		; IPSTARTの可変値
LCD_Y		EQU	0x59

MATH00		EQU	0x5A		; LSB
MATH01		EQU	0x5B		; MSB
MATH10		EQU	0x5C
MATH11		EQU	0x5D
MATH20		EQU	0x5E
MATH21		EQU	0x5F

RMTADRL		EQU	0x60
RMTADRH		EQU	0x61
RMTCNTL		EQU	0x62
RMTCNTH		EQU	0x63
LAST_CURR	EQU	0x64		; BNRY+1
RX_STATUS	EQU	0x65
NEXT_CURR	EQU	0x66
RXBYTES_L	EQU	0x67
RXBYTES_H	EQU	0x68

DHCP_TIMER	EQU	0x6C
FLAG1		EQU	0x6D
DOTCOUNT	EQU	0x6E
COMCOUNT	EQU	0x6F

; 一時利用変数
TMP00		EQU	0x70
TMP01		EQU	0x71
TMP02		EQU	0x72
TMP03		EQU	0x73
TMP10		EQU	0x74
TMP11		EQU	0x75
TMP12		EQU	0x76
TMP13		EQU	0x77
TMP20		EQU	0x78
TMP21		EQU	0x79
TMP22		EQU	0x7A
TMP23		EQU	0x7B

; 割り込みの退避用
W_		EQU	0x7C
STATUS_		EQU	0x7D
PCLATH_		EQU	0x7E
FSR_		EQU	0x7F

; 汎用バッファ
UNIBUF110	EQU	0x110;-0x16F
UNIBUF190	EQU	0x190;-0x1BD
STRBUF		EQU	0x1BE;-0x1EF
;------------------------------------------------------------------------------
; 定数宣言
;------------------------------------------------------------------------------
DEBUG0		EQU	6		; RB6
DEBUG1		EQU	7		; RB7

SCS		EQU	0		; RC0
EXTCOMIN	EQU	1		; RC1
DISP		EQU	2		; RC2
COMWAIT		EQU	5		; 9以下で設定する DHCPのタイミング生成と兼用している

RXF		EQU	0		; RB0
TXE		EQU	1		; RB1
USB_RD		EQU	2		; RB2
USB_WR		EQU	3		; RB3

IOCHRDY		EQU	5		; RB5
RSTDRV		EQU	6		; RC6
IORB		EQU	0		; RE0
IOWB		EQU	1		; RE1

; PS=0 Read
CR		EQU	0		; CRはCLRF PORTAの方が速い
CLDA0		EQU	1
CLDA1		EQU	2
BNRY		EQU	3
TSR		EQU	4
NCR		EQU	5
FIFO		EQU	6
ISR		EQU	7
CRDA0		EQU	8
CRDA1		EQU	9
ID0		EQU	0xA
ID1		EQU	0xB
RSR		EQU	0xC
CNTR0		EQU	0xD
CNTR1		EQU	0xE
CNTR2		EQU	0xF
DATAPORT	EQU	0x20		; NICのA4がPICのA5につながっているので間違わないようにする事
RESETPORT	EQU	0x28		; 上と同じ
; PS=0 Write
PSTART		EQU	1
PSTOP		EQU	2
TPSR		EQU	4
TBCR0		EQU	5
TBCR1		EQU	6
RSAR0		EQU	8
RSAR1		EQU	9
RBCR0		EQU	0xA
RBCR1		EQU	0xB
RCR		EQU	0xC
TCR		EQU	0xD
DCR		EQU	0xE
IMR		EQU	0xF
; PS=1
PAR0		EQU	1
PAR1		EQU	2
PAR2		EQU	3
PAR3		EQU	4
PAR4		EQU	5
PAR5		EQU	6
CURR		EQU	7
MAR0		EQU	8
MAR1		EQU	9
MAR2		EQU	0xA
MAR3		EQU	0xB
MAR4		EQU	0xC
MAR5		EQU	0xD
MAR6		EQU	0xE
MAR7		EQU	0xF
; PS=3
CR9346		EQU	1
BPAGE		EQU	2
CONFIG0		EQU	3
CONFIG1		EQU	4
CONFIG2		EQU	5
CONFIG3		EQU	6
TEST		EQU	7
CSNSAV		EQU	8
HLTCLK		EQU	9
INTR		EQU	0xB
FMWP		EQU	0xC
CONFIG4		EQU	0xD
; BitField
CR_STP		EQU	0x01		; Stop
CR_STA		EQU	0x02		; Start
CR_TXP		EQU	0x04		; Transmit Packet
CR_READ		EQU	0x08		; Remote Read
CR_WRITE	EQU	0x10		; Remote Write
CR_SEND		EQU	0x18		; Send Packet
CR_ABORT	EQU	0x20		; Abort/Complete Remote DMA
CR_PAGE0	EQU	0x00		; Page Select
CR_PAGE1	EQU	0x40
CR_PAGE2	EQU	0x80
CR_PAGE3	EQU	0xC0

DCR_WTS		EQU	0x01		; Word Transfer Select
DCR_BOS		EQU	0x02		; Byte Order Select
DCR_LAS		EQU	0x04		; Long Address Select
DCR_LS		EQU	0x08		; Loopback Select
DCR_ARM		EQU	0x10		; Auto Initialize Remote
DCR_FIFO2	EQU	0x00		; FIFO Threshold Select
DCR_FIFO4	EQU	0x20
DCR_FIFO8	EQU	0x40
DCR_FIFO12	EQU	0x60

IMR_PRXE	EQU	0x01		; Packet Received Interrupt
IMR_PTXE	EQU	0x02		; Packet Transmitted Interrupt
IMR_RXEE	EQU	0x04		; Receive Error Interrupt
IMR_TXEE	EQU	0x08		; Transmit Error Interrupt
IMR_OVWE	EQU	0x10		; Overwrite Warning Interrupt
IMR_CNTE	EQU	0x20		; Counter Overflow Interrupt
IMR_RDCE	EQU	0x40		; DMA Complete Interrupt

RCR_SEP		EQU	0x01		; Save Errored Packets
RCR_AR		EQU	0x02		; Accept Runt Packets
RCR_AB		EQU	0x04		; Accept Broadcast
RCR_AM		EQU	0x08		; Accept Multicast
RCR_PRO		EQU	0x10		; Promiscuous Physical
RCR_MON		EQU	0x20		; Monitor Mode

TCR_CRC		EQU	0x01		; Inhibit CRC
TCR_OPR_NORMAL	EQU	0x00		; Normal Operation
TCR_OPR_INTLB	EQU	0x02		; Internal Loopback
TCR_OPR_EXTLB1	EQU	0x04		; External Loopback 1
TCR_OPR_EXTLB2	EQU	0x06		; External Loopback 2
TCR_ATD		EQU	0x08		; Auto Transmit Disable
TCR_OFST	EQU	0x10		; Collision Offset Enable

ISR_PRX		EQU	0		; Packet Received
ISR_PTX		EQU	1		; Packet Transmitted
ISR_RXE		EQU	2		; Receive Error
ISR_TXE		EQU	3		; Transmit Error
ISR_OVW		EQU	4		; Overwrite Warning
ISR_CNT		EQU	5		; Counter Overflow
ISR_RDC		EQU	6		; Remote DMA Complete
ISR_RST		EQU	7		; Reset Status

TSR_PTX		EQU	0		; Packet Transmitted
TSR_COL		EQU	2		; Transmit Collided
TSR_ABT		EQU	3		; Transmit Aborted
TSR_CRS		EQU	4		; Carrier Sense Lost
TSR_CDH		EQU	6		; CD Heartbeat
TSR_OWC		EQU	7		; Out of Window Collision

RSR_PRX		EQU	0		; Packet Received Intact
RSR_CRC		EQU	1		; CRC Error
RSR_FAE		EQU	2		; Frame Alignment Error
RSR_MPA		EQU	4		; Missed Packet
RSR_PHY		EQU	5		; Physical/Multicast Address
RSR_DIS		EQU	6		; Receiver Disabled
RSR_DFR		EQU	7		; Defering

CONFIG0_BNC	EQU	0x04		; TPのリンク状態が分かる

LISTEN_UDP	EQU	50240
ETHER_MODE	EQU	0		; FLAG1-0
USB_TIMEOUT	EQU	1		; FLAG1-1
NIC_AVAILABLE	EQU	2		; FLAG1-2
NIC_LINKTEST	EQU	3		; FLAG1-3 リンクテスト実施を示す、テストを実行したら手動でビットを落とす
SURPRESS0	EQU	4		; FLAG1-4 10進化で頭のゼロを消す

; データシートに記載はないが、TPSRも0x60以上に配置すると0x40にデータが混入する。
; http://www.nahitech.com/nahitafu/bbs56.html
; #10, #12, #23, #24, #25, #26			; xPSTARTはDHCP完了前はIPSTART、DHCP完了後に-1してバッファを増やす。
ITPSR		EQU	0x40			;  2ページ   512バイト →  1ページ   256バイト
IPSTART 	EQU	0x42			; 30ページ 7,680バイト → 31ページ 7,936バイト
IPSTOP		EQU	0x60			; BNRYとCURRはIPSTART(xPSTART)を基準に計算する。

;------------------------------------------------------------------------------
; 電源ON
;------------------------------------------------------------------------------
;DEBUG		EQU	0		; MPLAB SIMではSSPのデバッグができないので監視ループを外す
	__IDLOCS 0x170
	ORG	0
	LGOTO	POWER_ON
;------------------------------------------------------------------------------
; 割り込み
;------------------------------------------------------------------------------
	ORG	4
	MOVWF	W_			; 状態保存
	SWAPF	STATUS,W
	MOVWF	STATUS_
	MOVF	PCLATH,W
	MOVWF	PCLATH_
	MOVF	FSR,W
	MOVWF	FSR_

	CLRF	STATUS			; ◆ RP=0 ● IRP=0
	BTFSC	PIR1,TMR1IF		; 割り込み要因チェック
	 GOTO	INT_TMR1IF
	BTFSC	PIR1,TMR2IF
	 GOTO	INT_TMR2IF
;	BTFSC	INTCON,INTF
;	 GOTO	INT_INTF
;	BTFSC	INTCON,T0IF
;	 GOTO	INT_T0IF
INT_RETURN
	MOVF	FSR_,W			; 状態復元
	MOVWF	FSR
	MOVF	PCLATH_,W
	MOVWF	PCLATH
	SWAPF	STATUS_,W
	MOVWF	STATUS
	SWAPF	W_,F
	SWAPF	W_,W
	RETFIE
;---------------------------------------
INT_TMR1IF
	BCF	PIR1,TMR1IF		; COM反転タイマー 105msごとに発生
	DECFSZ	COMCOUNT,F		; COMCOUNT回数えてパルスを生成する
	 GOTO	INT_RETURN
	BSF	PORTC,EXTCOMIN
	MOVLW	COMWAIT			; twEXTCOMIN >= 1us(1.2us)
	MOVWF	COMCOUNT		; ｜
	MOVF	DHCP_STATE,W		; ｜
	BTFSS	STATUS,Z		; ｜
	 INCF	DHCP_TIMER,F		; ｜
	BCF	PORTC,EXTCOMIN		; ↓
	GOTO	INT_RETURN

INT_TMR2IF
	BCF	PIR1,TMR2IF		; USB受信バイト間タイムアウトは、
	BCF	T2CON,TMR2ON		; タイマーを止めてフラグを書き込む。
	BSF	FLAG1,USB_TIMEOUT
	GOTO	INT_RETURN

;INT_INTF
;	BCF	INTCON,INTF		; USBパラレルはポーリングで受信させるので使わない
;	GOTO	INT_RETURN		; USBパラレル割り込み 1バイト受信ごとに発生
;
;INT_T0IF
;	BCF	INTCON,T0IF		; ネットワーク割り込みは使わない
;	MOVLW	0xFF			; ネットワーク割り込み 1フレーム受信ごとに発生
;	MOVWF	TMR0			; あと1カウントでカウンタ割り込みを発生させる
;	GOTO	INT_RETURN
;------------------------------------------------------------------------------
; USBからデータを入力しLCDに出力するモード。
; 先頭バイト=0なら画面クリア、1〜240ならその後の50バイトを受信して1ライン描画、241以上は無視
;
; データが連続して流れてこない場合はリフレッシュが滞るので、
;  TMR2をバイト間タイマーとして使用し、タイムアウトしたらデータ待ち状態に戻す。
;
; 使用変数
;		TMP00
; 注意事項
;		このルーチンは無限ループになっている。
;------------------------------------------------------------------------------
usb_mode
	MOVLW	LOW txt_usbmode
	MOVWF	TMP20
	MOVLW	HIGH txt_usbmode
	MOVWF	TMP21
	CALL	getstr
	CALL	puts

	MOVLW	HIGH SWAPTABLE		; ■ PCLATH
	MOVWF	PCLATH
USB_MODE_LOOP
	CALL	usb_read		; 先頭バイト(ラインアドレス)を入力するまで戻らない。
	MOVWF	TMP00

	BTFSC	STATUS,Z		; 0はCLS
	 GOTO	USB_cls
	SUBLW	240
	BTFSS	STATUS,C
	 GOTO	USB_MODE_LOOP		; 241以上は無視する

	BSF	PORTC,SCS		; tsSCS>=3us(0.4us)
	MOVLW	0x80			; ビットスワップ後の更新モードを送信
	MOVWF	SSPBUF
	 MOVLW	50			; 時間調整のためUSB_RXLOOPの初期化をここに持ってくる
	 MOVWF	DOTCOUNT		; 残りの50バイトを受信する。
	 NOP
	MOVF	TMP00,W			; ラインアドレスをビットスワップして送信
	CALL	bitswap
	MOVWF	SSPBUF			; 11T
	
	CLRF	TMR2			; タイマーリセット
	BCF	FLAG1,USB_TIMEOUT
	BSF	T2CON,TMR2ON		; タイマースタート
USB_RXLOOP
	BTFSC	PORTB,RXF		; データが来ているかポーリング
	 GOTO	USB_CHECK_TIMEOUT	;  来ない場合はタイムアウトをチェック
	CLRF	TMR2			; タイマーリセット
	BCF	PORTB,USB_RD		; USBから読み込む
	MOVF	PORTD,W			;  CALL,RETURNのタイムラグを無くすため、
	BSF	PORTB,USB_RD		;  ループ中ではusb_readは使わない
	NOP
	MOVWF	SSPBUF			; 11T
	DECFSZ	DOTCOUNT,F
	 GOTO	USB_RXLOOP

	BCF	T2CON,TMR2ON		; タイマーストップ
	CLRW				; ダミーバイト送信
	CALL	bitswap			; 
	MOVWF	SSPBUF			; 11T
	GOTO	$+1
	NOP
	CLRW
	CALL	bitswap			; ビットスワップして送信
	MOVWF	SSPBUF			; 11T
	CALL	lcd_complete
	GOTO	USB_MODE_LOOP

USB_CHECK_TIMEOUT
	BTFSS	FLAG1,USB_TIMEOUT	; タイムアウトしているか?
	 GOTO	USB_RXLOOP
	BCF	T2CON,TMR2ON		; タイムアウトしたらタイマーを止めて初めに戻る。
	BCF	PORTC,SCS		; thSCS 送信中断
	GOTO	USB_MODE_LOOP

USB_cls					; CLSコマンド
	CALL	lcd_cls
	GOTO	USB_MODE_LOOP
;------------------------------------------------------------------------------
; USBのFIFOから読み出す
;
; 引数		なし
; 戻り値	W
; 使用変数	なし
; 注意事項	割り込みを使っていないので、データが来るまで戻らない。
;------------------------------------------------------------------------------
usb_read
	BTFSC	PORTB,RXF
#IFNDEF DEBUG
	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
	 NOP
#ENDIF
	BCF	PORTB,USB_RD
	MOVF	PORTD,W
	BSF	PORTB,USB_RD
	RETURN
;------------------------------------------------------------------------------
; USBのFIFOに書き込む
;
; 引数		W
; 戻り値	なし
; 使用変数	なし
; 注意事項	PC側が受信可能状態でないと、書き込みができるまで戻らない。
;------------------------------------------------------------------------------
usb_write
	MOVWF	PORTD
	BTFSC	PORTB,TXE
#IFNDEF DEBUG
	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
	 NOP
#ENDIF
	BSF	PORTB,USB_WR
	BSF	STATUS,RP0		; ◆ RP=1
	CLRF	TRISD			; 出力モード
	BCF	STATUS,RP0		; ◆ RP=0
	BCF	PORTB,USB_WR
	BSF	STATUS,RP0		; ◆ RP=1
	COMF	TRISD,F			; 入力モード
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN
;------------------------------------------------------------------------------
; LCD更新の前準備
;
; 引数
;		LCD_Y	ラインアドレス
; 戻り値
;		なし
; 使用変数
;		TMP23(lcd_write)
;------------------------------------------------------------------------------
lcd_prepare
	MOVLW	HIGH SWAPTABLE
	MOVWF	PCLATH			; ■ PCLATH
	BSF	PORTC,SCS		; tsSCS>=3us
	MOVLW	1			; M0=1 データ更新モード
	CALL	lcd_write
	MOVF	LCD_Y,W			; ラインアドレス送信
	CALL	lcd_write
	RETURN
;------------------------------------------------------------------------------
; LCDクリア
;
; 引数
;		なし
; 戻り値
;		なし
; 使用変数
;		TMP23(lcd_write)
;------------------------------------------------------------------------------
lcd_cls
	MOVLW	HIGH SWAPTABLE
	MOVWF	PCLATH			; ■ PCLATH
	BSF	PORTC,SCS		; tsSCS>=3us
	MOVLW	4			; M2=1 全クリア
	CALL	lcd_write
	CALL	lcd_write		; ダミー書き込み
	CALL	lcd_complete
	RETURN
;------------------------------------------------------------------------------
; LCDに書き込む
;
; 引数
;		W	書き込むデータ
; 戻り値
;		なし
; 使用変数
;		TMP23
; 注意事項
;		事前にPCLATHの設定とSCSをHにしておくこと。
;------------------------------------------------------------------------------
lcd_write
	MOVWF	TMP23
	BSF	STATUS,RP0		; ◆ RP=1
	BTFSS	SSPSTAT,BF		; 前回の送信が終わっているか確認
#IFNDEF DEBUG
	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
	 NOP
#ENDIF
	BCF	STATUS,RP0		; ◆ RP=0
	MOVF	SSPBUF,W		; BFをクリアするためにダミーで読み出し
	MOVF	TMP23,W
	CALL	bitswap			; ビットスワップして送信
	MOVWF	SSPBUF
	RETURN
;------------------------------------------------------------------------------
; LCD駆動の後処理
;
; 引数
;		なし
; 戻り値
;		なし
; 使用変数
;		なし
;------------------------------------------------------------------------------
lcd_complete				; データ送信後からthSCS>=1us待ち、SCSをLにする。
	BSF	STATUS,RP0		; ◆ RP=1
	BTFSS	SSPSTAT,BF		; 前回の送信が終わっているか確認
#IFNDEF DEBUG
	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
	 NOP
#ENDIF
	BCF	STATUS,RP0		; ◆ RP=0
	GOTO	$+1
	GOTO	$+1
	BCF	PORTC,SCS
	RETURN
;------------------------------------------------------------------------------
; ウエイト 10ms*Wのウエイト
;
; 引数
;		W
; 戻り値
;		なし
; 使用変数
;		TMP21,TMP22,TMP23
;------------------------------------------------------------------------------
wait_10ms				; ここを呼ぶと単純に10msのタイマーになる
	MOVLW	1
wait_10msX
	MOVWF	TMP21
WAIT0
	MOVLW	65
	MOVWF	TMP22
WAIT1
	CLRF	TMP23
WAIT2
	DECFSZ	TMP23,F
	 GOTO	WAIT2
	DECFSZ	TMP22,F
	 GOTO	WAIT1
	DECFSZ	TMP21,F
	 GOTO	WAIT0
	RETURN
;------------------------------------------------------------------------------
; プログラムEEPROMからNULLでターミネートされた文字列を読み込む。
;
; 引数
;		TMP20		文字列アドレスLSB(破壊)
;		TMP21		文字列アドレスMSB(破壊)
; 戻り値
;		STRBUF		表示文字列(NULLで終端)
; 使用変数
;		なし
; 注意事項
;		NULLが出現するまで無限ループする
;------------------------------------------------------------------------------
getstr
	BSF	STATUS,IRP		; ● IRP=1
	MOVLW	LOW STRBUF
	MOVWF	FSR

	BSF	STATUS,RP1		; ◆ RP=2
GETSTR_LOOP
	MOVF	TMP21,W
	MOVWF	EEADRH
	MOVF	TMP20,W
	MOVWF	EEADR
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD		; READ
	BSF	EECON1,RD
	NOP
	NOP

	BCF	STATUS,RP0		; ◆ RP=2
	RLF	EEDATA,W		; 上位
	RLF	EEDATH,W
	ANDLW	0x7F
	MOVWF	INDF
	BTFSC	STATUS,Z		; NULLチェック
	 GOTO	GETSTR_RETURN
	INCF	FSR,F

	MOVF	EEDATA,W		; 下位
	ANDLW	0x7F
	MOVWF	INDF
	BTFSC	STATUS,Z
	 GOTO	GETSTR_RETURN
	INCF	FSR,F

	INCF	TMP20,F
	BTFSC	STATUS,Z
	 INCF	TMP21,F	
	GOTO	GETSTR_LOOP
GETSTR_RETURN
	BCF	STATUS,RP1		; ◆ RP=0
	RETURN
;------------------------------------------------------------------------------
; STRBUFに入った文字列をフォント番号に置き換える
; 使える文字は、スペース - . 0〜9 : A〜Z a〜z
;
; 引数		STRBUF
; 戻り値	STRBUF
; 使用変数	なし
; 注意事項	NULLが出現するまで無限ループするので注意
;------------------------------------------------------------------------------
replace_char
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	LOW STRBUF
	MOVWF	FSR
REPLACE_LOOP
	MOVF	INDF,W
	BTFSC	STATUS,Z		; NULLチェック
	 RETURN
	MOVLW	'a'			; 'a'以上
	SUBWF	INDF,W
	MOVLW	6
	BTFSC	STATUS,C
	 SUBWF	INDF,F
	MOVLW	'A'			; 'A'以上
	SUBWF	INDF,W
	MOVLW	6
	BTFSC	STATUS,C
	 SUBWF	INDF,F
	MOVLW	'0'			; '0'以上
	SUBWF	INDF,W
	BTFSC	STATUS,C
	 DECF	INDF,F
	MOVLW	'-'			; '-'以上
	SUBWF	INDF,W
	MOVLW	12
	BTFSC	STATUS,C
	 SUBWF	INDF,F
	MOVLW	0x1F			
	SUBWF	INDF,F
	INCF	FSR,F
	GOTO	REPLACE_LOOP
;------------------------------------------------------------------------------
; Wx7
;
; 引数
;		W	掛けられる数
; 戻り値
;		MATH10	LSB
;		MATH11	MSB
; 使用変数
;		TMP23
; 注意事項
;		上位への桁上がりは1度しか処理しないため、引数のWは85以下を厳守すること。
;------------------------------------------------------------------------------
Wx7
	CLRF	MATH11
	MOVWF	TMP23
	MOVWF	MATH10		; *1
	
	RLF	TMP23,W		; *2
	ANDLW	0xFE
	MOVWF	TMP23
	ADDWF	MATH10,F
	
	RLF	TMP23,W		; *4
	RLF	MATH11,F		; シフトであふれたビットを上位へ移す
	ANDLW	0xFE
	ADDWF	MATH10,F
	BTFSC	STATUS,C
	 INCF	MATH11,F
	RETURN
;------------------------------------------------------------------------------
; 20x8ドット文字列表示
;
; 引数		LCD_Y		表示開始ライン
;		STRBUF		文字列(NULLで終端)
; 戻り値
;		なし
; 使用変数
;		TMP20,TMP21,TMP22,TMP23(lcd_write)
;------------------------------------------------------------------------------
puts
	CALL	replace_char		; 文字コードを書き換え
	CALL	blank_line		; 先頭ライン
	CALL	blank_line
	CALL	blank_line
	MOVLW	14
	MOVWF	TMP20
	CLRF	TMP21			; フォントアドレス計算用カウンタ
	BSF	STATUS,IRP		; ● IRP=1
PUTS_LINE				; 行ループ
	MOVLW	LOW STRBUF		; 先頭文字へ移動
	MOVWF	FSR
	CALL	lcd_prepare
	MOVLW	50			; 50文字
	MOVWF	TMP22
PUTS_CHAR
	MOVF	INDF,W			; NULLの場合は空白とダミーバイトを出力
	BTFSC	STATUS,Z
	 GOTO	PUTS_DUMMYCHAR

	CALL	Wx7			; フォントアドレス計算
	MOVF	TMP21,W
	MOVWF	MATH20
	CLRF	MATH21
	CALL	add16
	
	MOVLW	LOW FONTDATA
	MOVWF	MATH20
	MOVLW	HIGH FONTDATA
	MOVWF	MATH21
	CALL	add16

	MOVF	MATH10,W
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	BCF	STATUS,RP1		; ◆ RP=0
	MOVF	MATH11,W
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADRH
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP

	BCF	STATUS,RP0		; ◆ RP=2
	BTFSC	TMP20,0
	 GOTO	PUTS_ODDLINE
PUTS_EVENLINE
	MOVF	EEDATA,W
	GOTO	PUTS_SEND
PUTS_ODDLINE
	RLF	EEDATA,W
	RLF	EEDATH,W
PUTS_SEND
	IORLW	0x80
	BCF	STATUS,RP1		; ◆ RP=0
	MOVWF	SSPBUF
PUTS_NEXTCHAR
	INCF	FSR,F
	DECFSZ	TMP22,F
	 GOTO	PUTS_CHAR
PUTS_DUMMYCHAR
	MOVF	TMP22,W			; 残りの空白+ダミーバイトを送信
	CALL	blank_another
	BTFSC	TMP20,0
	 INCF	TMP21,F
	DECFSZ	TMP20,F
	 GOTO	PUTS_LINE
	CALL	blank_line
	CALL	blank_line
	CALL	blank_line		; 最終ライン
	RETURN
;------------------------------------------------------------------------------
; 空白出力  空白を出力して更新モードを終了後、ラインアドレスをインクリメントする。
;
; blank_line	更新モード、アドレス出力、1ライン丸ごと空白
; blank_another	残りの文字分空白
;
; 引数		LCD_Y	ラインアドレス
;		W	残りの文字数(blank_anotherのみ)
; 戻り値	LCD_Y	次に表示するラインアドレス
; 使用変数	TMP22,TMP23(lcd_write)
;------------------------------------------------------------------------------
blank_line
	CALL	lcd_prepare
	MOVLW	50			; 3
	GOTO	$+1			; 5
	GOTO	$+1			; 7
blank_another
	ADDLW	2			; 8 ダミーバイトを含める
	MOVWF	TMP22			; 9
BLANKLOOP
	MOVLW	0xFF			; 10
	MOVWF	SSPBUF			; 11
	GOTO	$+1			; 2
	GOTO	$+1			; 4
	GOTO	$+1			; 6
	DECFSZ	TMP22,F			; 7
	 GOTO	BLANKLOOP		; 9
	CALL	lcd_complete
	INCF	LCD_Y,F			; 次のラインへ
	RETURN	

;------------------------------------------------------------------------------
; 16bit 足し算 MATH1 = MATH1 + MATH2
;
; 引数
;	MATH10	LSB 足される数
;	MATH11	MSB
;	MATH20	LSB 足す数(非破壊)
;	MATH21	MSB
;
; 戻り値
;	MATH10	LSB 和
;	MATH11	MSB
;
; 使用変数
;	なし
;------------------------------------------------------------------------------
add16
	MOVF	MATH20,W
	ADDWF	MATH10,F
	MOVF	MATH21,W
	BTFSC	STATUS,C
	 INCF	MATH21,W		; 桁上がりした+1を含めて加算するとCフラグも使えるようになる
	ADDWF	MATH11,F
	RETURN
;------------------------------------------------------------------------------
; 16bit 割り算 http://elm-chan.org/docs/avrlib/div16.txt
;
; 引数
;	MATH00	LSB 割られる数(0x0000..0xffff)
;	MATH01	MSB
;	MATH10	LSB 割る数(0x0001..0x7fff)(非破壊)
;	MATH11	MSB
;
; 戻り値
;	MATH00	LSB 商
;	MATH01	MSB
;	MATH20	LSB 余り
;	MATH21	MSB
;
; 使用変数
;	TMP20
;------------------------------------------------------------------------------
div16
	CLRF	MATH20		; clr	mod0		initialize variables
	CLRF	MATH21		; clr	mod1		mod = 0;
	MOVLW	16		; ldi	lc,16		lc = 16;
	MOVWF	TMP20
DIV16_1					;---- calcurating loop
	BCF	STATUS,C	; lsl	var10		var1 = var1 << 1;
	RLF	MATH00,F
	RLF	MATH01,F	; rol	var11
	RLF	MATH20,F	; rol	mod0		mod = mod << 1 + carry;
	RLF	MATH21,F	; rol	mod1
	MOVF	MATH10,W	; cp	mod0,var20	if (mod < var2) {
	SUBWF	MATH20,W
	MOVF	MATH11,W
	BTFSS	STATUS,C	; cpc	mod1,var21
	INCF	MATH11,W	;  Cフラグを足す
	SUBWF	MATH21,W
	BTFSS	STATUS,C
	GOTO	DIV16_2		; brcs	PC+4		} else {
	INCF	MATH00,F	; inc	var10		  var1++;
	MOVF	MATH10,W	; sub	mod0,var20	  mod -= var2;
	SUBWF	MATH20,F
	MOVF	MATH11,W	; sbc	mod1,var21
	BTFSS	STATUS,C	;  Cフラグを足す
	INCF	MATH11,W
	SUBWF	MATH21,F
DIV16_2					;			}
	DECFSZ	TMP20,F		; dec	lc		if (--lc > 0)
	GOTO	DIV16_1		; brne	PC-11		  continue loop;
	RETURN
;------------------------------------------------------------------------------
; 16進文字列変換
;
; 引数		W	値
;		FSR	文字列格納場所
; 戻り値	FSR
; 使用変数	TMP23
;------------------------------------------------------------------------------
bin2hex
	MOVWF	TMP23
	BSF	STATUS,IRP		; ◆ IRP=1
	MOVLW	HIGH HEXTABLE
	MOVWF	PCLATH			; ■ PCLATH
	SWAPF	TMP23,W
	ANDLW	0x0F
	CALL	BIN2CHAR
	MOVWF	INDF
	INCF	FSR,F

	MOVF	TMP23,W
	ANDLW	0x0F
	CALL	BIN2CHAR
	MOVWF	INDF
	RETURN	
BIN2CHAR
	ADDWF	PCL,F
HEXTABLE
	RETLW	'0'
	RETLW	'1'
	RETLW	'2'
	RETLW	'3'
	RETLW	'4'
	RETLW	'5'
	RETLW	'6'
	RETLW	'7'
	RETLW	'8'
	RETLW	'9'
	RETLW	'A'
	RETLW	'B'
	RETLW	'C'
	RETLW	'D'
	RETLW	'E'
	RETLW	'F'
;------------------------------------------------------------------------------
; NICリセット
;
; 引数		なし
; 戻り値	FLAG1-NIC_AVAILABLE
; 使用変数	TMP23
;------------------------------------------------------------------------------
nic_reset
	BCF	FLAG1,NIC_AVAILABLE
	BSF	PORTC,RSTDRV		; NIC初期化
	CALL	wait_10ms
	BCF	PORTC,RSTDRV		; リセット解除
	CALL	wait_10ms		; リセットが終わっても9346の自動ロードを待つ

	MOVLW	ID0			; ID0を読み出してNICが実装されているか確認
	MOVWF	PORTA
	CALL	nic_read
	SUBLW	'P'
	BTFSS	STATUS,Z
	 RETURN

	INCF	PORTA,F			; ID1
	CALL	nic_read
	SUBLW	'p'
	BTFSS	STATUS,Z
	 RETURN

	CLRF	PORTA			; NICレジスタ初期化
	MOVLW	CR_PAGE3|CR_ABORT|CR_STP
	CALL	nic_write

	MOVLW	CONFIG1
	MOVWF	PORTA
	CLRW
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0|CR_ABORT|CR_STP
	CALL	nic_write

	MOVLW	PSTART			; PSTART
	MOVWF	PORTA
	MOVLW	IPSTART			; DHCP処理前のバッファ割り当てを入れる
	MOVWF	xPSTART
	CALL	nic_write

	INCF	PORTA,F			; PSTOP
	MOVLW	IPSTOP
	CALL	nic_write

	INCF	PORTA,F			; BNRY
	MOVF	xPSTART,W
	CALL	nic_write

	INCF	PORTA,F			; TPSR
	MOVLW	ITPSR
	CALL	nic_write

	MOVLW	ISR			; ISR=RESET
	MOVWF	PORTA
	MOVLW	0xFF
	CALL	nic_write
	
	MOVLW	RBCR0			; RBCR0=0
	MOVWF	PORTA
	CLRW
	CALL	nic_write

	INCF	PORTA,F			; RBCR1=0
	CALL	nic_write

	INCF	PORTA,F			; RCR=MON
	MOVLW	RCR_MON
	CALL	nic_write

	INCF	PORTA,F			; TCR=INTLB
	MOVLW	TCR_OPR_INTLB
	CALL	nic_write

	INCF	PORTA,F			; DCR=FIFO12, OPR_LOOPBACK
	MOVLW	DCR_FIFO12
	CALL	nic_write

	INCF	PORTA,F			; IMR=0
	CLRW
	CALL	nic_write

	CLRF	RMTADRL
	CLRF	RMTADRH
	MOVLW	12
	MOVWF	RMTCNTL
	CLRF	RMTCNTH
	CALL	prepare_remote_read

	BCF	STATUS,IRP		; ◆ IRP=0
	MOVLW	MY_MAC
	MOVWF	FSR
	MOVLW	6			; MACアドレスを取得
	MOVWF	TMP23
GET_MACADDRESS
	CALL	nic_read		; ダミーリード
	CALL	nic_read
	MOVWF	INDF
	INCF	FSR,F
	DECFSZ	TMP23,F
	 GOTO	GET_MACADDRESS

	CLRF	PORTA
	MOVLW	CR_PAGE1| CR_ABORT| CR_STP
	CALL	nic_write

	MOVLW	MY_MAC
	MOVWF	FSR
	MOVLW	PAR0
	MOVWF	PORTA
	MOVLW	6			; MACアドレスをセット
	MOVWF	TMP23
SET_MACADDRESS
	MOVF	INDF,W
	CALL	nic_write
	INCF	FSR,F
	INCF	PORTA,F
	DECFSZ	TMP23,F
	 GOTO	SET_MACADDRESS

	INCF	xPSTART,W		; CURR
	MOVWF	LAST_CURR
	CALL	nic_write

	MOVLW	8			; マルチキャストフィルタを初期化
	MOVWF	TMP23
	CLRW
CLR_MULTICAST
	INCF	PORTA,F
	CALL	nic_write
	DECFSZ	TMP23,F
	 GOTO	CLR_MULTICAST
	
	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_STP
	CALL	nic_write

	MOVLW	RCR			; RCR=AB
	MOVWF	PORTA
	MOVLW	RCR_AB
	CALL	nic_write

	INCF	PORTA,F			; TCR=NORMAL
	MOVLW	TCR_OPR_NORMAL
	CALL	nic_write

	INCF	PORTA,F			; DCR=FIFO12, OPR_NORMAL
	MOVLW	DCR_FIFO12| DCR_LS
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_STA
	CALL	nic_write

	BSF	FLAG1,NIC_AVAILABLE
	RETURN
;------------------------------------------------------------------------------
; リンク状態検出
;
; 引数		なし
; 戻り値	Zフラグ SET:リンク中 CLR:リンク断
; 使用変数	なし
;------------------------------------------------------------------------------
nic_linktest
	CLRF	PORTA			; ページビットだけ変更する
	CALL	nic_read
	IORLW	0xC0
	CALL	nic_write
	MOVLW	CONFIG0
	MOVWF	PORTA
	CALL	nic_read
	ANDLW	CONFIG0_BNC
	RETURN
;------------------------------------------------------------------------------
; 指定バイト数スキップしてからNICのレジスタを読みだす
;
; 引数		PORTA=アドレス,W=スキップバイト
; 戻り値	W=データ
; 使用変数	なし
; 注意事項	IOCHRDYのLOWが続くと戻らない
;------------------------------------------------------------------------------
nic_skip_read
	XORLW	0xFF			; ファイルレジスタを使わずにループさせる
	ADDLW	1
NIC_SKIP_LOOP
	BCF	PORTE,IORB
;	BTFSS	PORTB,IOCHRDY
#IFNDEF DEBUG
;	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
;	 NOP
#ENDIF
	BSF	PORTE,IORB
	ADDLW	1
	BTFSS	STATUS,Z
	 GOTO	NIC_SKIP_LOOP
;------------------------------------------------------------------------------
; NICのレジスタから読みだす
;
; 引数		PORTA=アドレス
; 戻り値	W=データ
; 使用変数	なし
; 注意事項	IOCHRDYのLOWが続くと戻らない
;------------------------------------------------------------------------------
nic_read
	BCF	PORTE,IORB
;	BTFSS	PORTB,IOCHRDY
#IFNDEF DEBUG
;	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
;	 NOP
#ENDIF
	MOVF	PORTD,W
	BSF	PORTE,IORB
	RETURN

;------------------------------------------------------------------------------
; NICのレジスタに書き込む
;
; 引数		PORTA=アドレス, W=データ(非破壊)
; 戻り値	なし
; 使用変数	なし
; 注意事項	IOCHRDYのLOWが続くと戻らない
;------------------------------------------------------------------------------
nic_write_sum
	CALL	add_checksum
nic_write
	MOVWF	PORTD
	BSF	STATUS,RP0		; ◆ RP=1
	CLRF	TRISD			; 出力モード
	BCF	STATUS,RP0		; ◆ RP=0
	BCF	PORTE,IOWB
;	BTFSS	PORTB,IOCHRDY
#IFNDEF DEBUG
;	 GOTO	$-1
#ENDIF
#IFDEF DEBUG
;	 NOP
#ENDIF
	BSF	PORTE,IOWB
	BSF	STATUS,RP0		; ◆ RP=1
	COMF	TRISD,F			; 入力モード
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN

;------------------------------------------------------------------------------
; リモートリードの準備
;
; 引数		RMTADRL, RMTADRH, RMTCNTL, RMTCNTH
; 戻り値	なし
; 使用変数	なし
;------------------------------------------------------------------------------
prepare_remote_read
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVF	RMTADRL,W
	CALL	nic_write

	INCF	PORTA,F			; RSAR1
	MOVF	RMTADRH,W
	CALL	nic_write

	INCF	PORTA,F			; RBCR0
	MOVF	RMTCNTL,W
	CALL	nic_write

	INCF	PORTA,F			; RBCR1
	MOVF	RMTCNTH,W
	CALL	nic_write

	CLRF	PORTA			; READ| START
	MOVLW	CR_PAGE0| CR_READ| CR_STA
	CALL	nic_write
	MOVLW	DATAPORT
	MOVWF	PORTA
	RETURN
;------------------------------------------------------------------------------
; チェックサム計算クリア
; 引数		なし
; 戻り値	なし
; 使用変数	なし
;------------------------------------------------------------------------------
clear_checksum
	CLRF	CKSUM_H
	CLRF	CKSUM_L
	CLRF	CKSUM_COUNT
	RETURN
;------------------------------------------------------------------------------
; チェックサム計算
; 引数		W(非破壊)
; 戻り値	CKSUM_H,CKSUM_L
; 使用変数	TMP23
;------------------------------------------------------------------------------
add_checksum
	MOVWF	TMP23
	INCF	CKSUM_COUNT,F
	BTFSS	CKSUM_COUNT,0
	 GOTO	CKSUM_LOW
CKSUM_HIGH
	ADDWF	CKSUM_H,F
	MOVLW	1
	BTFSC	STATUS,C
	 ADDWF	CKSUM_L,F
	BTFSC	STATUS,C
	 INCF	CKSUM_H,F
	MOVF	TMP23,W
	RETURN
CKSUM_LOW
	ADDWF	CKSUM_L,F
	MOVLW	1
	BTFSC	STATUS,C
	 GOTO	CKSUM_HIGH
	MOVF	TMP23,W
	RETURN
;------------------------------------------------------------------------------
; チェックサム送信
; 引数		なし
; 戻り値	なし
; 使用変数	なし
;------------------------------------------------------------------------------
send_checksum
	MOVLW	DATAPORT
	MOVWF	PORTA
	COMF	CKSUM_H,W
	CALL	nic_write
	COMF	CKSUM_L,W
	CALL	nic_write
	RETURN
;------------------------------------------------------------------------------
; ブロードキャスト用のFFフィルを送る
; 引数		W	送信オクテット数
; 戻り値	なし
; 使用変数	TMP22
; 注意事項	チェックサムの計算も行う、2の倍数で送ったほうが良い。
;------------------------------------------------------------------------------
fill_ff
	MOVWF	TMP22
	MOVLW	DATAPORT
	MOVWF	PORTA
FILLFF_LOOP
	MOVLW	0xFF
	CALL	nic_write_sum
	DECFSZ	TMP22,F
	 GOTO	FILLFF_LOOP
	RETURN
;------------------------------------------------------------------------------
; パディング用の00フィルを送る
; 引数		W	送信オクテット数
; 戻り値	なし
; 使用変数	TMP23
; 注意事項	チェックサムの計算は省略する、2の倍数で送ったほうが良い。
;------------------------------------------------------------------------------
fill_zero
	MOVWF	TMP23
	MOVLW	DATAPORT
	MOVWF	PORTA
FILLZERO_LOOP
	CLRW
	CALL	nic_write
	DECFSZ	TMP23,F
	 GOTO	FILLZERO_LOOP
	RETURN
;------------------------------------------------------------------------------
; MACアドレスを送る
; 引数		W=MY_MAC または DST_MAC
; 戻り値	なし
; 使用変数	TMP22
; 注意事項	チェックサムの計算も行う
;------------------------------------------------------------------------------
send_mac
	MOVWF	FSR
	BCF	STATUS,IRP
	MOVLW	6
send_xxx
	MOVWF	TMP22
	MOVLW	DATAPORT
	MOVWF	PORTA
SENDXXX_LOOP
	MOVF	INDF,W
	CALL	nic_write_sum
	INCF	FSR,F
	DECFSZ	TMP22,F
	 GOTO	SENDXXX_LOOP
	RETURN
;------------------------------------------------------------------------------
; 4オクテットの数値を送る
; 引数		W=4オクテットの数値の先頭バイト
; 戻り値	なし
; 使用変数	TMP23
; 注意事項	チェックサムの計算も行う
;------------------------------------------------------------------------------
send_4oct
	MOVWF	FSR
	MOVLW	4
	GOTO	send_xxx
;------------------------------------------------------------------------------
; 2オクテットの数値を送る
; 引数		W=2オクテットの数値の先頭バイト
; 戻り値	なし
; 使用変数	TMP23
; 注意事項	チェックサムの計算も行う
;------------------------------------------------------------------------------
send_2oct
	MOVWF	FSR
	MOVLW	2
	GOTO	send_xxx
;------------------------------------------------------------------------------
ether_mode
	MOVLW	LOW txt_ethmode
	MOVWF	TMP20
	MOVLW	HIGH txt_ethmode
	MOVWF	TMP21
	CALL	getstr
	CALL	puts

	MOVLW	LOW txt_macaddr
	MOVWF	TMP20
	MOVLW	HIGH txt_macaddr
	MOVWF	TMP21
	CALL	getstr
	MOVLW	LOW STRBUF+13
	MOVWF	FSR
	MOVF	MY_MAC,W
	CALL	bin2hex
	INCF	FSR,F
	INCF	FSR,F
	MOVF	MY_MAC+1,W
	CALL	bin2hex
	INCF	FSR,F
	INCF	FSR,F
	MOVF	MY_MAC+2,W
	CALL	bin2hex
	INCF	FSR,F
	INCF	FSR,F
	MOVF	MY_MAC+3,W
	CALL	bin2hex
	INCF	FSR,F
	INCF	FSR,F
	MOVF	MY_MAC+4,W
	CALL	bin2hex
	INCF	FSR,F
	INCF	FSR,F
	MOVF	MY_MAC+5,W
	CALL	bin2hex
	CALL	puts

	MOVLW	100
	CALL	wait_10msX

	MOVLW	LOW txt_discover
	MOVWF	TMP20
	MOVLW	HIGH txt_discover
	MOVWF	TMP21
	CALL	getstr
	CALL	puts
	
	MOVLW	1
	MOVWF	DHCP_STATE
	movlw	2
	MOVWF	DHCP_TIMER
ETHER_MODE_LOOP
	CLRF	PORTA
	MOVLW	CR_PAGE1| CR_ABORT| CR_STA
	CALL	nic_write

	MOVLW	CURR			; 最後に読み出した時に計算したCURRと比較する
	MOVWF	PORTA
ETHER_POLLING
	BTFSC	PORTB,RXF		; USBにデータが流れてきたら空読みする
	 GOTO	ETHER_POLLING1
	BCF	PORTB,USB_RD
	BSF	PORTB,USB_RD
	 GOTO	ETHER_POLLING
ETHER_POLLING1
	BTFSC	DHCP_TIMER,2		; 4 x 0.5sでDHCPを送出
	 GOTO	dhcp_xmit

	CALL	nic_read
	SUBWF	LAST_CURR,W
	BTFSC	STATUS,Z
	 GOTO	ETHER_POLLING

	CLRF	PORTA			; 受信処理開始
	MOVLW	CR_PAGE0| CR_ABORT| CR_STA
	CALL	nic_write

	MOVLW	ISR			; エラー状態はリセット
	MOVWF	PORTA
	CALL	nic_read
	ANDLW	B'10010100'
	BTFSS	STATUS,Z
	 GOTO	ERROR_RECOVERY

	MOVF	LAST_CURR,W		; ヘッダを含めてデータを読み出す(FCSは含まない)
	MOVWF	RMTADRH
	CLRF	RMTADRL
	MOVLW	HIGH 1518		; ヘッダ4+予想される最大フレーム1514
	MOVWF	RMTCNTH
	MOVLW	LOW  1518
	MOVWF	RMTCNTL
	CALL	prepare_remote_read

	CALL	nic_read		; ヘッダ
	MOVWF	RX_STATUS
	ANDLW	B'11011110'		; 受信ステータスのエラーチェック
	BTFSS	STATUS,Z
	 GOTO	ERROR_RECOVERY
	BTFSS	RX_STATUS,0
	 GOTO	ERROR_RECOVERY

	CALL	nic_read
	MOVWF	NEXT_CURR
	CALL	nic_read
	MOVWF	RXBYTES_L
	CALL	nic_read
	MOVWF	RXBYTES_H

	MOVLW	4			; FCSを引いた実際のデータサイズ
	SUBWF	RXBYTES_L,F
	BTFSS	STATUS,C
	 DECF	RXBYTES_H,F

TYPE_ANALYZE
	MOVLW	6			; 自分のアドレスをスキップ
	CALL	nic_skip_read
	MOVWF	DST_MAC			; 応答用アドレスを保存
	CALL	nic_read
	MOVWF	DST_MAC+1
	CALL	nic_read
	MOVWF	DST_MAC+2
	CALL	nic_read
	MOVWF	DST_MAC+3
	CALL	nic_read
	MOVWF	DST_MAC+4
	CALL	nic_read
	MOVWF	DST_MAC+5

	CALL	nic_read		; タイプチェック=0x08xx
	SUBLW	0x08
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	CALL	nic_read
	BTFSC	STATUS,Z
	 GOTO	TYPE_IP			; IP
	SUBLW	0x06			; ARP
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
TYPE_ARP
	MOVLW	7			; ARP OPRまでスキップ
	CALL	nic_skip_read
	SUBLW	1			; リクエストだけ処理する
	BTFSS	STATUS,Z	
	 GOTO	CMPL_ANALYZE

	BSF	STATUS,IRP		; ■ IRP=1
	MOVLW	LOW UNIBUF110
	MOVWF	FSR
	MOVLW	10
	MOVWF	TMP00
ARP_SAVE
	CALL	nic_read
	MOVWF	INDF
	INCF	FSR,F
	DECFSZ	TMP00,F
	 GOTO	ARP_SAVE

	MOVLW	6			; MACアドレスをスキップ
	CALL	nic_skip_read
	SUBWF	MY_IP,W
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	CALL	nic_read
	SUBWF	MY_IP+1,W
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	CALL	nic_read
	SUBWF	MY_IP+2,W
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	CALL	nic_read
	SUBWF	MY_IP+3,W
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE

	CALL	update_bnry		; リモートリード中止、受信バッファを開放する

	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	CLRW
	CALL	nic_write

	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write

	INCF	PORTA,F			; RBCR0
	MOVLW	60
	CALL	nic_write

	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write

	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write

	MOVLW	DATAPORT
	MOVWF	PORTA
	BCF	STATUS,IRP		; ■ IRP=0
	MOVLW	DST_MAC
	CALL	send_mac
	MOVLW	MY_MAC
	CALL	send_mac
	MOVLW	0x08
	CALL	nic_write
	MOVLW	0x06
	CALL	nic_write
	MOVLW	0x00
	CALL	nic_write
	MOVLW	0x01
	CALL	nic_write
	MOVLW	0x08
	CALL	nic_write
	MOVLW	0x00
	CALL	nic_write
	MOVLW	0x06
	CALL	nic_write
	MOVLW	0x04
	CALL	nic_write
	MOVLW	0x00
	CALL	nic_write
	MOVLW	0x02
	CALL	nic_write
	MOVLW	MY_MAC
	CALL	send_mac
	MOVLW	MY_IP
	CALL	send_4oct
	BSF	STATUS,IRP		; ■ IRP=1
	MOVLW	LOW UNIBUF110
	MOVWF	FSR
	MOVLW	10
	CALL	send_xxx
	MOVLW	18
	CALL	fill_zero
	
	MOVLW	TBCR0			; TBCR0
	MOVWF	PORTA
	MOVLW	60
	CALL	nic_write

	MOVLW	TBCR1			; TBCR1
	MOVWF	PORTA
	CLRW
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_TXP| CR_STA
	CALL	nic_write
	GOTO	ETHER_MODE_LOOP		; BNRYアップデート済みなので直接戻る
	
TYPE_IP
	CALL	nic_read		; IPバージョンチェック
	MOVWF	TMP00
	ANDLW	0xF0
	SUBLW	0x40
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	
	RLF	TMP00,F			; 残りのIPヘッダサイズ計算
	RLF	TMP00,W
	ANDLW	0x3C
	MOVWF	TMP00
	CALL	nic_read		; TOSは無視
	CALL	nic_read		; PING用にLENGTHを保存
	MOVWF	TMP02
	CALL	nic_read
	MOVWF	TMP03
	
	MOVLW	5			; プロトコル番号まで5バイトスキップ
	CALL	nic_skip_read
	MOVWF	TMP01
	SUBLW	0x11			; =UDP
	BTFSC	STATUS,Z
	 GOTO	IS_UDP
	DECF	TMP01,W			; =ICMP
	BTFSC	STATUS,Z
	 GOTO	IS_ICMP
	GOTO	CMPL_ANALYZE

IS_UDP
	MOVLW	8			; 残りのヘッダと相手のUDPポートをスキップ
	SUBWF	TMP00,W
	CALL	nic_skip_read		; UDPヘッダまで進める
	MOVWF	TMP10
	CALL	nic_read
	MOVWF	TMP11

	MOVF	TMP10,W
	SUBWF	MY_UDP,W		; 宛先UDPポートチェック
	BTFSS	STATUS,Z
	 GOTO	IS_DHCP
	MOVF	TMP11,W
	SUBWF	MY_UDP+1,W
	BTFSC	STATUS,Z
	 GOTO	PROTO_PICT		; 画像データだった
IS_DHCP
	MOVF	TMP10,W			; (68)DHCP CLIENT?
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
	MOVF	TMP11,W
	SUBLW	68
	BTFSC	STATUS,Z
	 CALL	dhcp_analyze
	MOVLW	3
	SUBWF	DHCP_STATE,W
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE		; DHCP処理中なら通常ループへ戻る
	CLRF	DHCP_STATE
	DECF	xPSTART,F		; DHCP完了(3)が来たら送信バッファを減らし受信バッファを増やす
	GOTO	BUFFER_RESET		; バッファをリセットしてサイズ変更を反映させる

PROTO_PICT
	CALL	nic_read		; データサイズ
	MOVWF	TMP01
	CALL	nic_read
	MOVWF	TMP00
	MOVLW	8			; ヘッダサイズを引く
	SUBWF	TMP00,F
	CLRW
	BTFSS	STATUS,C
	 ADDLW	1
	SUBWF	TMP01,F

	MOVF	TMP00,W			; データサイズが0ならリターン
	IORWF	TMP01,W
	BTFSC	STATUS,Z
	 GOTO	CMPL_ANALYZE

	CALL	nic_read		; チェックサムは無視
	CALL	nic_read
	CALL	nic_read
	MOVWF	TMP02
	BTFSC	STATUS,Z		; 0はCLS
	 GOTO	ETHER_cls

	MOVLW	51			; --51(データサイズ)
	SUBWF	TMP00,F
	MOVLW	1
	BTFSS	STATUS,C
	 SUBWF	TMP01,F
	BTFSS	STATUS,C
	 GOTO	CMPL_ANALYZE		; データが欠落しているなら即戻る

	MOVLW	HIGH SWAPTABLE		; ■ PCLATH
	MOVWF	PCLATH
	BSF	PORTC,SCS		; tsSCS>=3us
	MOVLW	0x80			; ビットスワップ後の更新モードを送信
	MOVWF	SSPBUF
PROTO_PICT_LOOP
	DECF	TMP02,W			; アドレスは1〜240か?
	SUBLW	239
	BTFSS	STATUS,C
	 GOTO	PROTO_PICT_LOOPEND	; エラーデータの場合はそれ以降を処理しない
	
	MOVF	TMP02,W			; ラインアドレスをビットスワップして送信
	CALL	bitswap
	MOVWF	SSPBUF			; 12T
	MOVLW	50			; 残りの50バイトを受信する。
	MOVWF	DOTCOUNT
	GOTO	$+1			; ノイズ対策用ダミーウエイト10T
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
ETHER_DRAWLOOP
	CALL	nic_read
	MOVWF	SSPBUF			; 11T
	DECFSZ	DOTCOUNT,F
	 GOTO	ETHER_DRAWLOOP

	NOP
	CLRW				; ダミーバイト送信
	CALL	bitswap			; 
	MOVWF	SSPBUF			; 11T

	MOVLW	51			; --51(データサイズ)
	SUBWF	TMP00,F
	MOVLW	1
	BTFSS	STATUS,C
	 SUBWF	TMP01,F
	BTFSS	STATUS,C
	 GOTO	PROTO_PICT_LOOPEND

	CALL	nic_read
	MOVWF	TMP02
	GOTO	PROTO_PICT_LOOP

ETHER_cls				; CLSコマンド
	CALL	lcd_cls
	GOTO	CMPL_ANALYZE

PROTO_PICT_LOOPEND
	NOP
	CLRW				; ダミーバイト送信
	MOVWF	SSPBUF			; 11T
	CALL	lcd_complete
	;GOTO	CMPL_ANALYZE

CMPL_ANALYZE
	CALL	update_bnry
	GOTO	ETHER_MODE_LOOP

update_bnry
	CLRF	PORTA			; リモートリード終了
	MOVLW	CR_PAGE0| CR_ABORT| CR_STA
	CALL	nic_write

	MOVLW	BNRY			; BNRY更新
	MOVWF	PORTA

	MOVF	NEXT_CURR,W		; セットするBNRYの計算
	MOVWF	LAST_CURR		;  LAST_CURRも同時更新
	SUBWF	xPSTART,W
	BTFSC	STATUS,Z
	 MOVLW	IPSTOP-1		; バッファトップの時はIPSTOP - 1
	BTFSS	STATUS,Z
	 DECF	NEXT_CURR,W		; それ以外はNEXT_CURR - 1
	CALL	nic_write
	RETURN

IS_ICMP
	MOVLW	2			; IPチェックサム無視
	CALL	nic_skip_read		; 相手のアドレスを保存
	MOVWF	DST_IP
	CALL	nic_read
	MOVWF	DST_IP+1
	CALL	nic_read
	MOVWF	DST_IP+2
	CALL	nic_read
	MOVWF	DST_IP+3
	MOVLW	4			; 自分のIPアドレスを無視
	CALL	nic_skip_read		; ICMPタイプは?
	SUBLW	8
	BTFSS	STATUS,Z
	 GOTO	CMPL_ANALYZE
IS_ECHO_REQUEST
	MOVLW	2
	CALL	nic_skip_read		; コード、チェックサム無視
	
	MOVF	TMP00,W			; PINGの返信用にコピーするサイズを計算
	ADDLW	4			; IPサイズ(TMP02,03)-IPヘッダ(TMP00)-ICMPヘッダ(4)
	SUBWF	TMP03,F
	BTFSS	STATUS,C
	 DECF	TMP02,F
	MOVLW	96			; 96バイト以上はバッファ上限の96にセット
	SUBWF	TMP03,W
	MOVLW	1
	BTFSS	STATUS,C
	 SUBWF	TMP02,W
	MOVF	TMP03,W
	BTFSC	STATUS,C
	 MOVLW	96
	MOVWF	TMP01			; = コピーするサイズ
	MOVWF	TMP03
	
	ADDWF	TMP00,W			; フレーム長が60バイト以下にならないようにするパッドのバイト数
	ADDLW	18			; Ethernetヘッダ+ICMPヘッダ
	SUBLW	60
	MOVWF	TMP02
	BTFSS	STATUS,C
	 CLRF	TMP02
	 
	BSF	STATUS,IRP		; ● IRP=1
	MOVLW	LOW UNIBUF110
	MOVWF	FSR
ICMP_ECHO_DATACOPY
	CALL	nic_read
	MOVWF	INDF
	INCF	FSR,F
	DECFSZ	TMP03,F
	 GOTO	ICMP_ECHO_DATACOPY
	
	CALL	update_bnry		; リモートリード中止、受信バッファを開放する

	MOVLW	RSAR0			; ICMPパケット生成 RSAR0
	MOVWF	PORTA
	CLRW
	CALL	nic_write

	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write

	INCF	PORTA,F			; RBCR0
	MOVLW	34			; Ethernet+IP
	CALL	nic_write

	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write

	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write

	MOVLW	DATAPORT
	MOVWF	PORTA
	BCF	STATUS,IRP		; ■ IRP=0
	MOVLW	DST_MAC			; Ethernet
	CALL	send_mac
	MOVLW	MY_MAC
	CALL	send_mac
	MOVLW	0x08
	CALL	nic_write
	MOVLW	0x00
	CALL	nic_write

	CALL	clear_checksum		; IP
	MOVLW	0x45
	CALL	nic_write_sum
	MOVLW	0x00
	CALL	nic_write_sum
	CALL	nic_write_sum		; LENGTH=20+4+TMP01
	MOVLW	24
	ADDWF	TMP01,W
	CALL	nic_write_sum
	MOVF	IP_XID,W
	CALL	nic_write_sum
	MOVF	IP_XID+1,W
	CALL	nic_write_sum
	MOVLW	0x00
	CALL	nic_write		; FLAG+OFFSET
	CALL	nic_write
	MOVLW	0x7F			; TTL
	CALL	nic_write_sum
	MOVLW	0x01			; PROTO=ICMP
	CALL	nic_write_sum
	MOVLW	0x00
	CALL	nic_write		; DUMMY SUM
	CALL	nic_write
	MOVLW	MY_IP
	CALL	send_4oct
	MOVLW	DST_IP
	CALL	send_4oct
	
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	24			; IPチェックサムの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	2
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write
	CALL	send_checksum
	
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	34			; IPペイロードの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVF	TMP02,W			; ICMPヘッダ+データ+パッド
	ADDWF	TMP01,W
	ADDLW	4
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write

	MOVLW	DATAPORT
	MOVWF	PORTA
	CALL	clear_checksum	
	MOVLW	0x00
	CALL	nic_write		; TYPE=(0)ECHO REPLY
	CALL	nic_write		; CODE=0
	CALL	nic_write		; DUMMY SUM
	CALL	nic_write

	BSF	STATUS,IRP		; ● IRP=1
	MOVLW	LOW UNIBUF110		; コピーしたデータを書く
	MOVWF	FSR
	MOVF	TMP01,W
	MOVWF	TMP03
ICMP_ECHO_DATASET
	MOVF	INDF,W
	CALL	nic_write_sum
	INCF	FSR,F
	DECFSZ	TMP03,F
	 GOTO	ICMP_ECHO_DATASET

	MOVF	TMP02,W
	BTFSC	STATUS,Z
	 GOTO	ICMP_REPLY
	MOVWF	TMP03
ICMP_ECHO_PADSET
	CLRW
	CALL	nic_write
	DECFSZ	TMP03,F
	 GOTO	ICMP_ECHO_PADSET
ICMP_REPLY
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	36			; ICMPチェックサムの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	2
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write
	CALL	send_checksum

	MOVLW	TBCR0			; TBCR0
	MOVWF	PORTA
	MOVLW	38			; Ethernet+IPヘッダ+ICMPヘッダ
	ADDWF	TMP01,W			; +データ
	ADDWF	TMP02,W			; +パッド
	CALL	nic_write

	MOVLW	TBCR1			; TBCR1
	MOVWF	PORTA
	MOVLW	0
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_TXP| CR_STA
	CALL	nic_write

	INCF	IP_XID+1,F		; IP_XID更新
	BTFSC	STATUS,Z
	 INCF	IP_XID,F
	GOTO	ETHER_MODE_LOOP		; BNRYアップデート済みなので直接戻る
;------------------------------------------------------------------------------
dhcp_xmit
	CLRF	DHCP_TIMER
	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_STA
	CALL	nic_write

	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	CLRW
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	34			; Ether14+IPヘッダ20
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write

	MOVLW	DATAPORT
	MOVWF	PORTA
	MOVLW	6			; BROADCAST
	CALL	fill_ff
	MOVLW	MY_MAC			; MY MAC
	CALL	send_mac
	MOVLW	0x08			; TYPE=IP
	CALL	nic_write
	MOVLW	0x00
	CALL	nic_write
	
	CALL	clear_checksum
	MOVLW	0x45			; IPv4
	CALL	nic_write_sum
	MOVLW	0x00			; TOS
	CALL	nic_write_sum
	MOVLW	HIGH 287		; SIZE
	CALL	nic_write_sum
	MOVLW	LOW 287
	CALL	nic_write_sum
	MOVLW	IP_XID			; ID
	CALL	send_2oct
	MOVLW	0x00			; FLAG
	CALL	nic_write
	CALL	nic_write
	MOVLW	0x7F			; TTL
	CALL	nic_write_sum
	MOVLW	0x11			; PROTO=UDP
	CALL	nic_write_sum
	MOVLW	0x00			; DUMMY SUM
	CALL	nic_write
	CALL	nic_write
	MOVLW	MY_IP			; MY IP
	CALL	send_4oct
	MOVLW	4			; BROADCAST
	CALL	fill_ff
	
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	24			; IPチェックサムの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	2
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write
	CALL	send_checksum

	CALL	clear_checksum
	MOVF	MY_IP,W			; UDPの仮想ヘッダのチェックサムを加算しておく
	CALL	add_checksum
	MOVF	MY_IP+1,W
	CALL	add_checksum
	MOVF	MY_IP+2,W
	CALL	add_checksum
	MOVF	MY_IP+3,W
	CALL	add_checksum
	MOVLW	0xFF
	CALL	add_checksum
	CALL	add_checksum
	CALL	add_checksum
	CALL	add_checksum
	MOVLW	0x00			; UDP=17
	CALL	add_checksum
	MOVLW	0x11
	CALL	add_checksum
	MOVLW	HIGH 267		; UDP LENGTH
	CALL	add_checksum
	MOVLW	LOW 267
	CALL	add_checksum
	
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	34			; IPペイロードの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	LOW 267
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	MOVWF	HIGH 267
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write

	MOVLW	DATAPORT
	MOVWF	PORTA
	MOVLW	0x00			; MY PORT=68(DHCP CLIENT)
	CALL	nic_write_sum
	MOVLW	68
	CALL	nic_write_sum
	MOVLW	0x00			; DST PORT=67(DHCP SRV)
	CALL	nic_write_sum
	MOVLW	67
	CALL	nic_write_sum
	MOVLW	HIGH 267		; UDP LENGTH
	CALL	nic_write_sum
	MOVLW	LOW 267
	CALL	nic_write_sum
	MOVLW	0x00			; DUMMY SUM
	CALL	nic_write
	CALL	nic_write

	MOVLW	0x01			; BOOTP OP
	CALL	nic_write_sum
	CALL	nic_write_sum		; HTYPE
	MOVLW	0x06			; HLEN
	CALL	nic_write_sum
	MOVLW	0x00			; HOPS
	CALL	nic_write_sum
	MOVLW	DHCP_XID		; XID
	CALL	send_4oct
	MOVLW	8			; SECS,FLAGS,CIADDR
	CALL	fill_zero
	MOVLW	MY_IP			; YIADDR
	CALL	send_4oct
	MOVLW	8			; SIADDR,GIADDR
	CALL	fill_zero
	MOVLW	MY_MAC			; CHADDR
	CALL	send_mac
	MOVLW	202			; CHADDR,SNAME,FILE
	CALL	fill_zero
	
	MOVLW	0x63			; MAGIC COOKIE
	CALL	nic_write_sum
	MOVLW	0x82
	CALL	nic_write_sum
	MOVLW	0x53
	CALL	nic_write_sum
	MOVLW	0x63
	CALL	nic_write_sum
	
	MOVLW	0x3D			; 61 CLIENT IDENT
	CALL	nic_write_sum
	MOVLW	0x07
	CALL	nic_write_sum
	MOVLW	0x01
	CALL	nic_write_sum
	MOVLW	MY_MAC			; IDENT
	CALL	send_mac
	MOVLW	0x35			; 53 MESSAGE TYPE
	CALL	nic_write_sum
	MOVLW	0x01
	CALL	nic_write_sum

	DECF	DHCP_STATE,W		; 状態が1の時、OFFER
	BTFSS	STATUS,Z		; それ以外はREQUEST
	 GOTO	DHCP_REQUEST		; (プログラムのロジック上、1と2以外が来ることは無い)
DHCP_DISCOVER
	MOVLW	0x01			; DISCOVER
	CALL	nic_write_sum
	MOVLW	0xFF			; END
	CALL	nic_write_sum
	MOVLW	6
	CALL	fill_zero
	GOTO	DHCP_TRANSMIT
DHCP_REQUEST
	MOVLW	0x03			; REQUEST
	CALL	nic_write_sum
	MOVLW	0x32			; 50 REQUESTED IP ADDRESS
	CALL	nic_write_sum
	MOVLW	0x04
	CALL	nic_write_sum
	MOVLW	MY_IP
	CALL	send_4oct
	MOVLW	0xFF			; END
	CALL	nic_write_sum
DHCP_TRANSMIT
	MOVLW	RSAR0			; RSAR0
	MOVWF	PORTA
	MOVLW	40			; UDPチェックサムの位置
	CALL	nic_write
	INCF	PORTA,F			; RSAR1
	MOVLW	ITPSR
	CALL	nic_write
	INCF	PORTA,F			; RBCR0
	MOVLW	2
	CALL	nic_write
	INCF	PORTA,F			; RBCR1
	CLRW
	CALL	nic_write
	CLRF	PORTA			; WRITE| START
	MOVLW	CR_PAGE0| CR_WRITE| CR_STA
	CALL	nic_write
	CALL	send_checksum

	MOVLW	TBCR0			; TBCR0
	MOVWF	PORTA
	MOVLW	LOW 301
	CALL	nic_write

	MOVLW	TBCR1			; TBCR1
	MOVWF	PORTA
	MOVLW	HIGH 301
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_TXP| CR_STA
	CALL	nic_write
	INCF	IP_XID+1,F		; IP_XID更新
	BTFSC	STATUS,Z
	 INCF	IP_XID,F
	GOTO	ETHER_MODE_LOOP
;------------------------------------------------------------------------------
dhcp_analyze
	MOVF	DHCP_STATE,W		; DHCPを実行していない場合はそのままリターン
	BTFSC	STATUS,Z
	 RETURN

	MOVLW	4
	CALL	nic_skip_read		; UDPサイズとチェックサムはスキップ
	SUBLW	2			; OP=REPLY以外は無視
	BTFSS	STATUS,Z
	 RETURN
	
	MOVLW	3
	CALL	nic_skip_read		; XIDチェック
	SUBWF	DHCP_XID,W
	BTFSS	STATUS,Z
	 RETURN
	CALL	nic_read
	SUBWF	DHCP_XID+1,W
	BTFSS	STATUS,Z
	 RETURN
	CALL	nic_read
	SUBWF	DHCP_XID+2,W
	BTFSS	STATUS,Z
	 RETURN
	CALL	nic_read
	SUBWF	DHCP_XID+3,W
	BTFSS	STATUS,Z
	 RETURN

	MOVLW	8			; SECS,FLAGS,CIADDR
	CALL	nic_skip_read		; YIADDR保存
	MOVWF	MY_IP
	CALL	nic_read
	MOVWF	MY_IP+1
	CALL	nic_read
	MOVWF	MY_IP+2
	CALL	nic_read
	MOVWF	MY_IP+3

	MOVLW	219			; SIADDR,GIADDR,CHADDR,SNAME,FILE,COOKIEをスキップ
	CALL	nic_skip_read		; 捨てる
DHCP_OPTIONLOOP
	CALL	nic_read
	MOVWF	TMP10
	BTFSC	STATUS,Z		; (0) PAD?
	 GOTO	DHCP_OPTIONLOOP
	SUBLW	1			; (1)NETMASK
	BTFSC	STATUS,Z
	 GOTO	DHCP_NETMASK
	MOVF	TMP10,W
	SUBLW	3			; (3)GATEWAY
	BTFSC	STATUS,Z
	 GOTO	DHCP_GATEWAY
	MOVF	TMP10,W
	SUBLW	53			; (53)MESSAGE TYPE
	BTFSC	STATUS,Z
	 GOTO	DHCP_MSGTYPE
	COMF	TMP10,W			; (255)END
	BTFSC	STATUS,Z
	 RETURN
DHCP_OTHER
	CALL	nic_read		; LENGTHを読んで-1して空読みする
	ADDLW	0xFF
	CALL	nic_skip_read
	GOTO	DHCP_OPTIONLOOP	

DHCP_NETMASK
	MOVLW	NETMASK
DHCP_READ4OCT
	MOVWF	FSR
	BCF	STATUS,IRP		; ■ IRP=0
	CALL	nic_read
	MOVWF	TMP02			; LENGTH
	MOVLW	4			; とりあえず4バイト読む
	MOVWF	TMP03
DHCP_READ4OCT_LOOP
	CALL	nic_read
	MOVWF	INDF
	INCF	FSR,F
	DECF	TMP02,F
	DECFSZ	TMP03,F
	 GOTO	DHCP_READ4OCT_LOOP
	BTFSC	STATUS,Z		; LENGTH=0?
	 GOTO	DHCP_OPTIONLOOP
	DECF	TMP02,W			; 残りのLENGTHを空読みして戻る
	CALL	nic_skip_read
	GOTO	DHCP_OPTIONLOOP	
	
DHCP_GATEWAY
	MOVLW	GW_IP
	GOTO	DHCP_READ4OCT

DHCP_MSGTYPE
	CALL	nic_read		; LENGTH省略
	CALL	nic_read		; TYPEは?
	MOVWF	TMP10
	SUBLW	2			; (2)OFFER
	BTFSC	STATUS,Z
	 GOTO	DHCP_OFFER
	MOVF	TMP10,W
	SUBLW	5			; (5)ACK
	BTFSC	STATUS,Z
	 GOTO	DHCP_ACK
	MOVF	TMP10,W
	SUBLW	6			; (6)NAK
	BTFSC	STATUS,Z
	 GOTO	DHCP_NAK
	GOTO	DHCP_OPTIONLOOP		; それ以外は処理をしないが、オプションはすべて読み込ませる(RETURNで破棄しない)

DHCP_OFFER
	INCF	DHCP_STATE,F		; REQUESTへ移行
	MOVLW	71
	MOVWF	LCD_Y
	MOVLW	LOW txt_request
	MOVWF	TMP20
	MOVLW	HIGH txt_request
	MOVWF	TMP21
	CALL	getstr
	CALL	puts
	MOVLW	3
	MOVWF	DHCP_TIMER
	GOTO	DHCP_OPTIONLOOP

DHCP_ACK
	CALL	disp_address		; 受け入れられたのでアドレス表示
	INCF	DHCP_XID+3,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID+2,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID+1,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID,F
	INCF	DHCP_STATE,F		; バッファ変更の遷移へ進む
	GOTO	DHCP_OPTIONLOOP

DHCP_NAK
	MOVLW	1			; DISCOVERに戻ってやり直す
	MOVWF	DHCP_STATE		; このトランザクションは破棄
	MOVLW	3
	MOVWF	DHCP_TIMER
	INCF	DHCP_XID+3,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID+2,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID+1,F
	BTFSC	STATUS,Z
	 INCF	DHCP_XID,F

	MOVLW	12			; 取得したデータはいったん削除
	MOVWF	TMP10
	MOVLW	MY_IP
	MOVWF	FSR
DHCP_NAK_CLEAR
	CLRF	INDF
	DECFSZ	TMP10,F
	 GOTO	DHCP_NAK_CLEAR
	GOTO	DHCP_OPTIONLOOP

;------------------------------------------------------------------------------
ERROR_RECOVERY
	MOVLW	B'01000000'
	XORWF	PORTB,F
BUFFER_RESET
	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_STP
	CALL	nic_write

	MOVLW	11
	MOVWF	TMP01
WAIT1600ns1
	CLRF	TMP00
WAIT1600ns0
	DECFSZ	TMP00,F
	 GOTO	WAIT1600ns0
	DECFSZ	TMP01,F
	 GOTO	WAIT1600ns1

	MOVLW	RBCR0			; RBCRクリア
	MOVWF	PORTA
	CLRW
	CALL	nic_write
	INCF	PORTA,F
	CALL	nic_write
	
	MOVLW	TCR
	MOVWF	PORTA			; TCR=INTLB
	MOVLW	TCR_OPR_INTLB
	CALL	nic_write

	INCF	PORTA,F			; DCR=FIFO12,OPR_LOOPBACK
	MOVLW	DCR_FIFO12
	CALL	nic_write
	
	MOVLW	PSTART			; PSTARTリセット
	MOVWF	PORTA
	MOVF	xPSTART,W
	CALL	nic_write

	INCF	PORTA,F			; PSTOPリセット
	MOVLW	IPSTOP
	CALL	nic_write

	INCF	PORTA,F			; BNRYリセット
	MOVF	xPSTART,W
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE1| CR_ABORT| CR_STP
	CALL	nic_write
	
	MOVLW	CURR			; CURRリセット
	MOVWF	PORTA
	INCF	xPSTART,W
	MOVWF	LAST_CURR
	CALL	nic_write

	CLRF	PORTA
	MOVLW	CR_PAGE0| CR_ABORT| CR_STA
	CALL	nic_write

	MOVLW	ISR			; ISRクリア
	MOVWF	PORTA
	MOVLW	0xFF
	CALL	nic_write
	
	MOVLW	TCR
	MOVWF	PORTA			; TCR=OPR_NORMAL
	MOVLW	TCR_OPR_NORMAL
	CALL	nic_write

	INCF	PORTA,F			; DCR=FIFO12,OPR_NORMAL
	MOVLW	DCR_FIFO12| DCR_LS
	CALL	nic_write
	GOTO	ETHER_MODE_LOOP
;------------------------------------------------------------------------------
; 10進文字列変換 各桁の数字をバッファに送る
;
; 引数
;	MATH01		MSB	表示する桁の数値
;	MATH00		LSB
;
; 戻り値
;	MATH01		MSB	次の桁への余り
;	MATH00		LSB
;
; 使用変数
;	TMP20(数値演算ルーチン内)
;------------------------------------------------------------------------------
dec_10000
	MOVLW	0x27			; 0x2710 = 10,000
	MOVWF	MATH11
	MOVLW	0x10
dec_div16
	MOVWF	MATH10
	CALL	div16
	GOTO	dec_1
;------------------------------------------------------------------------------
dec_1000
	MOVLW	0x03			; 0x03E8 = 1,000
	MOVWF	MATH11
	MOVLW	0xE8
	GOTO	dec_div16
;------------------------------------------------------------------------------
dec_100
	CLRF	MATH11			; 100
	MOVLW	100
	GOTO	dec_div16
;------------------------------------------------------------------------------
dec_10
	CLRF	MATH11			; 10
	MOVLW	10
	GOTO	dec_div16
;------------------------------------------------------------------------------
dec_1
	MOVF	MATH00,W		; 文字化
	BTFSS	STATUS,Z
	 GOTO	DEC_1_0
	BTFSC	FLAG1,SURPRESS0
	 GOTO	DEC_1_1
DEC_1_0
	BCF	FLAG1,SURPRESS0
	ADDLW	'0'
	MOVWF	INDF
	INCF	FSR,F
DEC_1_1
	MOVF	MATH21,W		; 余り
	MOVWF	MATH01
	MOVF	MATH20,W
	MOVWF	MATH00
	RETURN
;------------------------------------------------------------------------------
format_xxxxx
	BSF	FLAG1,SURPRESS0
	CALL	dec_10000
	CALL	dec_1000
	GOTO	format_xxx1
format_xxx
	BSF	FLAG1,SURPRESS0
	MOVWF	MATH00
	CLRF	MATH01
format_xxx1
	CALL	dec_100
	CALL	dec_10
	BCF	FLAG1,SURPRESS0
	CALL	dec_1
	RETURN
;------------------------------------------------------------------------------
dec_dot					; ドット挿入
	MOVLW	'.'
	MOVWF	INDF
	INCF	FSR,F
	RETURN
;------------------------------------------------------------------------------
disp_address
	MOVLW	71
	MOVWF	LCD_Y
	MOVLW	LOW txt_ipaddr
	MOVWF	TMP20
	MOVLW	HIGH txt_ipaddr
	MOVWF	TMP21
	CALL	getstr
	MOVLW	LOW STRBUF+13
	MOVWF	FSR
	MOVF	MY_IP,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	MY_IP+1,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	MY_IP+2,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	MY_IP+3,W
	CALL	format_xxx
	CALL	puts

	MOVLW	LOW txt_netmask
	MOVWF	TMP20
	MOVLW	HIGH txt_netmask
	MOVWF	TMP21
	CALL	getstr
	MOVLW	LOW STRBUF+13
	MOVWF	FSR
	MOVF	NETMASK,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	NETMASK+1,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	NETMASK+2,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	NETMASK+3,W
	CALL	format_xxx
	CALL	puts

	MOVLW	LOW txt_gateway
	MOVWF	TMP20
	MOVLW	HIGH txt_gateway
	MOVWF	TMP21
	CALL	getstr
	MOVLW	LOW STRBUF+13
	MOVWF	FSR
	MOVF	GW_IP,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	GW_IP+1,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	GW_IP+2,W
	CALL	format_xxx
	CALL	dec_dot
	MOVF	GW_IP+3,W
	CALL	format_xxx
	CALL	puts

	MOVLW	LOW txt_udpport
	MOVWF	TMP20
	MOVLW	HIGH txt_udpport
	MOVWF	TMP21
	CALL	getstr
	MOVLW	LOW STRBUF+13
	MOVWF	FSR
	MOVF	MY_UDP,W
	MOVWF	MATH01
	MOVF	MY_UDP+1,W
	MOVWF	MATH00
	CALL	format_xxxxx
	CALL	puts
	RETURN
;------------------------------------------------------------------------------
; 頭からN文字の0を除去する
;
; 引数
;	W		N文字数
;
; 戻り値
;	STRING		表示文字列(NULLで終端)
;
; 使用変数
;	TMP20
;------------------------------------------------------------------------------
zero_replace
	MOVWF	TMP20
ZERO_REPL_LOOP
	MOVLW	'0'			; 文字が0でなければそこで終了
	SUBWF	INDF,W
	BTFSS	STATUS,Z
	RETURN
	MOVLW	' '			; 0ならばスペースに置換
	MOVWF	INDF
	INCF	FSR,F
	DECFSZ	TMP20,F
	GOTO	ZERO_REPL_LOOP
	RETURN
;------------------------------------------------------------------------------
; ビットスワップテーブル
;
; 引数		W
; 戻り値	W
; 使用変数	なし
; 注意事項	lcd_writeと同じプログラムページに置き、コール前にSWAPTABLEのPCLATHをセットしておく。
;------------------------------------------------------------------------------
	ORG	0x6FF
bitswap
	ADDWF	PCL,F
SWAPTABLE
	RETLW	0x00
	RETLW	0x80
	RETLW	0x40
	RETLW	0xC0
	RETLW	0x20
	RETLW	0xA0
	RETLW	0x60
	RETLW	0xE0
	RETLW	0x10
	RETLW	0x90
	RETLW	0x50
	RETLW	0xD0
	RETLW	0x30
	RETLW	0xB0
	RETLW	0x70
	RETLW	0xF0
	RETLW	0x08
	RETLW	0x88
	RETLW	0x48
	RETLW	0xC8
	RETLW	0x28
	RETLW	0xA8
	RETLW	0x68
	RETLW	0xE8
	RETLW	0x18
	RETLW	0x98
	RETLW	0x58
	RETLW	0xD8
	RETLW	0x38
	RETLW	0xB8
	RETLW	0x78
	RETLW	0xF8
	RETLW	0x04
	RETLW	0x84
	RETLW	0x44
	RETLW	0xC4
	RETLW	0x24
	RETLW	0xA4
	RETLW	0x64
	RETLW	0xE4
	RETLW	0x14
	RETLW	0x94
	RETLW	0x54
	RETLW	0xD4
	RETLW	0x34
	RETLW	0xB4
	RETLW	0x74
	RETLW	0xF4
	RETLW	0x0C
	RETLW	0x8C
	RETLW	0x4C
	RETLW	0xCC
	RETLW	0x2C
	RETLW	0xAC
	RETLW	0x6C
	RETLW	0xEC
	RETLW	0x1C
	RETLW	0x9C
	RETLW	0x5C
	RETLW	0xDC
	RETLW	0x3C
	RETLW	0xBC
	RETLW	0x7C
	RETLW	0xFC
	RETLW	0x02
	RETLW	0x82
	RETLW	0x42
	RETLW	0xC2
	RETLW	0x22
	RETLW	0xA2
	RETLW	0x62
	RETLW	0xE2
	RETLW	0x12
	RETLW	0x92
	RETLW	0x52
	RETLW	0xD2
	RETLW	0x32
	RETLW	0xB2
	RETLW	0x72
	RETLW	0xF2
	RETLW	0x0A
	RETLW	0x8A
	RETLW	0x4A
	RETLW	0xCA
	RETLW	0x2A
	RETLW	0xAA
	RETLW	0x6A
	RETLW	0xEA
	RETLW	0x1A
	RETLW	0x9A
	RETLW	0x5A
	RETLW	0xDA
	RETLW	0x3A
	RETLW	0xBA
	RETLW	0x7A
	RETLW	0xFA
	RETLW	0x06
	RETLW	0x86
	RETLW	0x46
	RETLW	0xC6
	RETLW	0x26
	RETLW	0xA6
	RETLW	0x66
	RETLW	0xE6
	RETLW	0x16
	RETLW	0x96
	RETLW	0x56
	RETLW	0xD6
	RETLW	0x36
	RETLW	0xB6
	RETLW	0x76
	RETLW	0xF6
	RETLW	0x0E
	RETLW	0x8E
	RETLW	0x4E
	RETLW	0xCE
	RETLW	0x2E
	RETLW	0xAE
	RETLW	0x6E
	RETLW	0xEE
	RETLW	0x1E
	RETLW	0x9E
	RETLW	0x5E
	RETLW	0xDE
	RETLW	0x3E
	RETLW	0xBE
	RETLW	0x7E
	RETLW	0xFE
	RETLW	0x01
	RETLW	0x81
	RETLW	0x41
	RETLW	0xC1
	RETLW	0x21
	RETLW	0xA1
	RETLW	0x61
	RETLW	0xE1
	RETLW	0x11
	RETLW	0x91
	RETLW	0x51
	RETLW	0xD1
	RETLW	0x31
	RETLW	0xB1
	RETLW	0x71
	RETLW	0xF1
	RETLW	0x09
	RETLW	0x89
	RETLW	0x49
	RETLW	0xC9
	RETLW	0x29
	RETLW	0xA9
	RETLW	0x69
	RETLW	0xE9
	RETLW	0x19
	RETLW	0x99
	RETLW	0x59
	RETLW	0xD9
	RETLW	0x39
	RETLW	0xB9
	RETLW	0x79
	RETLW	0xF9
	RETLW	0x05
	RETLW	0x85
	RETLW	0x45
	RETLW	0xC5
	RETLW	0x25
	RETLW	0xA5
	RETLW	0x65
	RETLW	0xE5
	RETLW	0x15
	RETLW	0x95
	RETLW	0x55
	RETLW	0xD5
	RETLW	0x35
	RETLW	0xB5
	RETLW	0x75
	RETLW	0xF5
	RETLW	0x0D
	RETLW	0x8D
	RETLW	0x4D
	RETLW	0xCD
	RETLW	0x2D
	RETLW	0xAD
	RETLW	0x6D
	RETLW	0xED
	RETLW	0x1D
	RETLW	0x9D
	RETLW	0x5D
	RETLW	0xDD
	RETLW	0x3D
	RETLW	0xBD
	RETLW	0x7D
	RETLW	0xFD
	RETLW	0x03
	RETLW	0x83
	RETLW	0x43
	RETLW	0xC3
	RETLW	0x23
	RETLW	0xA3
	RETLW	0x63
	RETLW	0xE3
	RETLW	0x13
	RETLW	0x93
	RETLW	0x53
	RETLW	0xD3
	RETLW	0x33
	RETLW	0xB3
	RETLW	0x73
	RETLW	0xF3
	RETLW	0x0B
	RETLW	0x8B
	RETLW	0x4B
	RETLW	0xCB
	RETLW	0x2B
	RETLW	0xAB
	RETLW	0x6B
	RETLW	0xEB
	RETLW	0x1B
	RETLW	0x9B
	RETLW	0x5B
	RETLW	0xDB
	RETLW	0x3B
	RETLW	0xBB
	RETLW	0x7B
	RETLW	0xFB
	RETLW	0x07
	RETLW	0x87
	RETLW	0x47
	RETLW	0xC7
	RETLW	0x27
	RETLW	0xA7
	RETLW	0x67
	RETLW	0xE7
	RETLW	0x17
	RETLW	0x97
	RETLW	0x57
	RETLW	0xD7
	RETLW	0x37
	RETLW	0xB7
	RETLW	0x77
	RETLW	0xF7
	RETLW	0x0F
	RETLW	0x8F
	RETLW	0x4F
	RETLW	0xCF
	RETLW	0x2F
	RETLW	0xAF
	RETLW	0x6F
	RETLW	0xEF
	RETLW	0x1F
	RETLW	0x9F
	RETLW	0x5F
	RETLW	0xDF
	RETLW	0x3F
	RETLW	0xBF
	RETLW	0x7F
	RETLW	0xFF
;------------------------------------------------------------------------------
; 文字列テーブル
;------------------------------------------------------------------------------
	ORG	0x0800
NULL	EQU	0
txt_title	DA	'-'<<7|'-','-'<<7|' ','m'<<7|'A','Q'<<7|'U','O'<<7|'S',' '<<7|'V','e'<<7|'r'
		DA	'.'<<7|'0','.'<<7|'3','6'<<7|' ','-'<<7|'-','-'<<7|NULL
txt_usbmode	DA	'-'<<7|'-','-'<<7|' ','U'<<7|'S','B'<<7|' ','M'<<7|'o','d'<<7|'e',' '<<7|'-','-'<<7|'-',NULL
txt_ethmode	DA	'-'<<7|'-','-'<<7|' ','E'<<7|'t','h'<<7|'e','r'<<7|'n','e'<<7|'t',' '<<7|'M','o'<<7|'d','e'<<7|' ','-'<<7|'-','-'<<7|NULL
txt_macaddr	DA	'M'<<7|'A','C'<<7|' ','A'<<7|'d','d'<<7|'r','e'<<7|'s','s'<<7|':',' '<<7|' ',' '<<7|':',' '<<7|' ',':'<<7|' ',' '<<7|':',' '<<7|' ',':'<<7|' ',' '<<7|':',' '<<7|' ',NULL
txt_discover	DA	'D'<<7|'H','C'<<7|'P',' '<<7|'D','i'<<7|'s','c'<<7|'o','v'<<7|'e','r'<<7|'.','.'<<7|'.',NULL
txt_request	DA	'D'<<7|'H','C'<<7|'P',' '<<7|'R','e'<<7|'q','u'<<7|'e','s'<<7|'t','.'<<7|'.','.'<<7|NULL
txt_ipaddr	DA	'I'<<7|'P',' '<<7|'A','d'<<7|'d','r'<<7|'e','s'<<7|'s',' '<<7|':',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',NULL
txt_netmask	DA	'N'<<7|'e','t'<<7|'m','a'<<7|'s','k'<<7|' ',' '<<7|' ',' '<<7|':',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',NULL
txt_gateway	DA	'G'<<7|'a','t'<<7|'e','w'<<7|'a','y'<<7|' ',' '<<7|' ',' '<<7|':',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',' '<<7|' ',NULL
txt_udpport	DA	'U'<<7|'D','P'<<7|' ','P'<<7|'o','r'<<7|'t',' '<<7|' ',' '<<7|':',' '<<7|' ',' '<<7|' ',' '<<7|' ',NULL
;------------------------------------------------------------------------------
FONTTOP		; 14x7ドットフォント
FONTDATA	EQU	FONTTOP-7
	DA	0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF	; スペース
	DA	0x3FFF, 0x3FFF, 0x3FFF, 0x0081, 0x3FFF, 0x3FFF, 0x3FFF	; -
	DA	0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x21E7, 0x33C3	; .
	DA	0x20E3, 0x24C9, 0x0C1C, 0x0210, 0x0E0C, 0x24C9, 0x31C1	; 0
	DA	0x21F3, 0x39C3, 0x39F3, 0x39F3, 0x39F3, 0x39F3, 0x39F3	; 1
	DA	0x20E3, 0x0E08, 0x061C, 0x3CCC, 0x39F9, 0x23E3, 0x0000	; 2
	DA	0x20E3, 0x0E08, 0x3C7C, 0x30E1, 0x3E78, 0x041C, 0x31C1	; 3
	DA	0x30F1, 0x24E1, 0x24C9, 0x0C99, 0x0C99, 0x0000, 0x3CF9	; 4
	DA	0x0000, 0x0F9F, 0x019F, 0x3C01, 0x3E7C, 0x0C1C, 0x2181	; 5
	DA	0x38F9, 0x23E3, 0x01CF, 0x0401, 0x0E1C, 0x041C, 0x31C1	; 6
	DA	0x0001, 0x3E7C, 0x3C7C, 0x38F9, 0x31F3, 0x23E7, 0x27CF	; 7
	DA	0x20E3, 0x0E08, 0x249C, 0x20C1, 0x0E08, 0x0C1C, 0x2181	; 8
	DA	0x20E3, 0x0E08, 0x0E1C, 0x200C, 0x3CE0, 0x31F1, 0x27C7	; 9
	DA	0x3FFF, 0x21E7, 0x33C3, 0x3FFF, 0x33FF, 0x21C3, 0x3FE7	; :
	DA	0x31E3, 0x24C1, 0x0449, 0x0E1C, 0x0000, 0x0E1C, 0x0E1C	; A
	DA	0x0083, 0x0E18, 0x0C1C, 0x0081, 0x0E18, 0x0C1C, 0x0181	; B
	DA	0x20E3, 0x0648, 0x0E1C, 0x0F9F, 0x0E1F, 0x041C, 0x31C1	; C
	DA	0x0187, 0x0C91, 0x0E1C, 0x0E1C, 0x0E1C, 0x0899, 0x0383	; D
	DA	0x0000, 0x0F9F, 0x0F9F, 0x0081, 0x0F9F, 0x0F9F, 0x2000	; E
	DA	0x0040, 0x0F9F, 0x0F9F, 0x0081, 0x0F9F, 0x0F9F, 0x0F9F	; F
	DA	0x20E3, 0x0648, 0x0F9C, 0x081F, 0x0E10, 0x041C, 0x31C1	; G
	DA	0x0E1C, 0x0E1C, 0x0E1C, 0x0000, 0x0E1C, 0x0E1C, 0x0E1C	; H
	DA	0x30E1, 0x39F3, 0x39F3, 0x39F3, 0x39F3, 0x39F3, 0x30E1	; I
	DA	0x3E7C, 0x3E7C, 0x3E7C, 0x0E7C, 0x0E1C, 0x041C, 0x31C1	; J
	DA	0x0C1C, 0x0191, 0x0F87, 0x039F, 0x0987, 0x0C91, 0x0E1C	; K
	DA	0x0F9F, 0x0F9F, 0x0F9F, 0x0F9F, 0x0F9F, 0x079F, 0x3040	; L
	DA	0x0E1C, 0x061C, 0x0408, 0x0000, 0x0E14, 0x0E1C, 0x0E1C	; M
	DA	0x061C, 0x020C, 0x0804, 0x0C10, 0x0C18, 0x0E1C, 0x0E1C	; N
	DA	0x20E3, 0x0E08, 0x0E1C, 0x0E1C, 0x0E1C, 0x041C, 0x31C1	; O
	DA	0x0083, 0x0E18, 0x0E1C, 0x0098, 0x0F83, 0x0F9F, 0x0F9F	; P
	DA	0x20E3, 0x0E08, 0x0E1C, 0x021C, 0x0C00, 0x0419, 0x31C0	; Q
	DA	0x0083, 0x0E18, 0x0E1C, 0x0098, 0x0983, 0x0C91, 0x0E18	; R
	DA	0x00C3, 0x0E18, 0x238F, 0x38E3, 0x0E78, 0x041C, 0x31C1	; S
	DA	0x0000, 0x33E7, 0x33E7, 0x33E7, 0x33E7, 0x33E7, 0x33E7	; T
	DA	0x0E1C, 0x0E1C, 0x0E1C, 0x0E1C, 0x0E1C, 0x041C, 0x31C1	; U
	DA	0x0E1C, 0x0E1C, 0x260C, 0x24C9, 0x30E1, 0x39E1, 0x39F3	; V
	DA	0x0E1C, 0x0E1C, 0x0A1C, 0x0000, 0x0000, 0x24C9, 0x24C9	; W
	DA	0x0E1C, 0x2488, 0x31C1, 0x39E3, 0x30E3, 0x2441, 0x0E0C	; X
	DA	0x0E1C, 0x0E1C, 0x20C9, 0x39E3, 0x39F3, 0x39F3, 0x39F3	; Y
	DA	0x0001, 0x3E7C, 0x3CF8, 0x39F1, 0x33E3, 0x27C7, 0x0000	; Z
	DA	0x3FFF, 0x3FFF, 0x20E3, 0x3E48, 0x2060, 0x0E0C, 0x2000	; a
	DA	0x0F9F, 0x0F9F, 0x0083, 0x0E18, 0x0E1C, 0x0C1C, 0x0181	; b
	DA	0x3FFF, 0x3FFF, 0x20E3, 0x0E08, 0x0F9F, 0x041C, 0x31C1	; c
	DA	0x3E7C, 0x3E7C, 0x2060, 0x0E0C, 0x0E1C, 0x061C, 0x3040	; d
	DA	0x3FFF, 0x3FFF, 0x20E3, 0x0E08, 0x0000, 0x061F, 0x30C0	; e
	DA	0x3878, 0x39F3, 0x0073, 0x3980, 0x39F3, 0x39F3, 0x39F3	; f
	DA	0x3CFF, 0x30F9, 0x0640, 0x0E1C, 0x200C, 0x38E0, 0x21C1	; g
	DA	0x0F9F, 0x0F9F, 0x0093, 0x0600, 0x0E1C, 0x0E1C, 0x0E1C	; h
	DA	0x30F3, 0x30E1, 0x3FF3, 0x39F3, 0x39F3, 0x39F3, 0x39F3	; i
	DA	0x30F3, 0x30E1, 0x3FF3, 0x39F3, 0x39F3, 0x31F3, 0x0787	; j
	DA	0x0F9F, 0x0F9F, 0x0C1C, 0x0191, 0x0187, 0x0C93, 0x0E18	; k
	DA	0x33E7, 0x33E7, 0x33E7, 0x33E7, 0x33E7, 0x33E7, 0x38E1	; l
	DA	0x3FFF, 0x3FFF, 0x0009, 0x1200, 0x1224, 0x1224, 0x1224	; m
	DA	0x3FFF, 0x3FFF, 0x0081, 0x0E18, 0x0E1C, 0x0E1C, 0x0E1C	; n
	DA	0x3FFF, 0x3FFF, 0x20E3, 0x0E08, 0x0E1C, 0x041C, 0x31C1	; o
	DA	0x3FFF, 0x3FFF, 0x0083, 0x0E18, 0x0C1C, 0x0181, 0x0F9F	; p
	DA	0x3FFF, 0x3FFF, 0x2060, 0x0E0C, 0x061C, 0x3040, 0x3E7C	; q
	DA	0x3FFF, 0x3FFF, 0x2049, 0x2644, 0x26CC, 0x27CF, 0x27CF	; r
	DA	0x3FFF, 0x3FFF, 0x0041, 0x079C, 0x30C3, 0x0E78, 0x2080	; s
	DA	0x33FF, 0x33E7, 0x0081, 0x33E7, 0x33E7, 0x3264, 0x38E0	; t
	DA	0x3FFF, 0x3FFF, 0x0E1C, 0x0E1C, 0x0E1C, 0x0E1C, 0x2080	; u
	DA	0x3FFF, 0x3FFF, 0x0E1C, 0x0C98, 0x2199, 0x23C3, 0x33E7	; v
	DA	0x3FFF, 0x3FFF, 0x0E1C, 0x0A14, 0x0000, 0x24C9, 0x24C9	; w
	DA	0x3FFF, 0x3FFF, 0x041C, 0x31C1, 0x21E7, 0x04C1, 0x0E1C	; x
	DA	0x3FFF, 0x3FFF, 0x0E1C, 0x2088, 0x31C1, 0x33E7, 0x27C7	; y
	DA	0x3FFF, 0x3FFF, 0x0081, 0x39F9, 0x23E3, 0x0FCF, 0x0081	; z
;------------------------------------------------------------------------------
; 電源投入時の初期化
; RA0(O)=RTL8019AS A0
; RA1(O)=RTL8019AS A1
; RA2(O)=RTL8019AS A2
; RA3(O)=RTL8019AS A3
; RA4(I)=RTL8019AS INT(T0CKI)
; RA5(O)=RTL8019AS A4
; RA6-7(I)=OSC 20MHz
; ---
; RB0(I)=FT245BL /RXF(for INT)
; RB1(I)=FT245BL /TXE
; RB2(O)=FT245BL /RD
; RB3(O)=FT245BL WR
; RB4(O)=---
; RB5(I)=RTL8019AS IOCHRDY(RBPU=ON)
; RB6(O)=DEBUG0(ICSP CLK)
; RB7(O)=DEBUG1(ICSP DAT)
; ---
; RC0(O)=LCD SCS
; RC1(O)=LCD EXTCOMIN
; RC2(O)=LCD DISP
; RC3(O)=LCD SCLK
; RC4(I)=---(SDI)
; RC5(O)=LCD SI
; RC6(O)=RTL8019AS RSTDRV
; RC7(O)=---
; ---
; RD0-7(IO)=DATA BUS(TRISTATE)
; ---
; RE0(O)=RTL8019AS /IORB
; RE1(O)=RTL8019AS /IOWB
; RE2(O)=---
; RE3(I)=---(for VPP)
;------------------------------------------------------------------------------
POWER_ON				; I/O初期化 未使用ポートは出力Lにする事
	CLRF	PORTA
	MOVLW	B'11000100'
	MOVWF	PORTB
	MOVLW	B'01000000'		; NICはリセット状態
	MOVWF	PORTC
	CLRF	PORTD
	MOVLW	B'00000011'
	MOVWF	PORTE
	
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	STATUS,RP1
	CLRF	ANSEL			; RA,RB,RE=デジタルIO
	CLRF	ANSELH
	
	BCF	STATUS,RP1		; ◆ RP=1
	MOVLW	B'11010000'		; バス方向決定
	MOVWF	TRISA
	MOVLW	B'00100011'
	MOVWF	TRISB
	MOVLW	B'00010000'
	MOVWF	TRISC
	MOVLW	B'11111111'		; データバスはハイインピーダンスでアイドル状態とする
	MOVWF	TRISD
	MOVLW	B'00001000'
	MOVWF	TRISE

	MOVLW	B'00100000'		; オープンドレインのIOCHRDY入力の内部プルアップを有効
	MOVWF	WPUB
	MOVLW	B'00101111'		; プルアップ有効, /RXF_INT立ち下げエッジ, T0=カウンタモード, T0CKI立ち上げカウント, プリスケーラ=WDT
	MOVWF	OPTION_REG
	MOVLW	B'00000011'		; TMR1IE=COM反転タイマー, TMR2IE=USB受信タイムアウトタイマー
	MOVWF	PIE1
	MOVLW	B'01000000'		; CKE=1
	MOVWF	SSPSTAT

	BCF	STATUS,RP0		; ◆ RP=0
	MOVLW	B'00100000'		; SSP=ON, CKP=0, SPI_Master, Fosc/4=5MHz (規格オーバーで動かしても大丈夫)
	MOVWF	SSPCON
	CLRF	SSPBUF			; ダミーを送信してBFを立てておく(SCSを駆動してないので無視される)
	CLRF	TMR1H			; LCD COM反転タイマー初期化
	CLRF	TMR1L
	MOVLW	COMWAIT
	MOVWF	COMCOUNT
	MOVLW	B'00110001'		; TMR1=ON, Fosc/4/8/65536/COMWAIT(5)=1.91Hz(0.52s)
	MOVWF	T1CON
	MOVLW	0xFF			; あと1カウントでLANの割り込みを発生させる

	MOVWF	TMR0
	MOVLW	B'01111010'		; USB受信タイムアウトタイマー
	MOVWF	T2CON			; 1バイト受信ごとにリセットさせる、T/16/256/16=76.3Hz(13ms)
	MOVLW	B'11000000'		; GIE, PEIE=LCD_COM+USB_TIMEOUT
	MOVWF	INTCON			;  T0IE=RTL8019AS_INT(使わない), INTE=FT245BL_/RXF(使わない)
	;-------------------------------
	LCALL	lcd_cls			; 電源シーケンスT2
	CALL	wait_10ms
	BSF	PORTC,DISP		; 電源シーケンスT3
	CALL	wait_10ms
	CALL	nic_reset
	MOVLW	HIGH $
	MOVWF	PCLATH
	;-------------------------------
	CLRF	FLAG1			; 変数初期化
	MOVLW	MY_IP			; ネットワークパラメータ初期化
	MOVWF	FSR
	MOVLW	DHCP_XID - MY_IP
	MOVWF	TMP00
REG_INIT0
	CLRF	INDF
	INCF	FSR,F
	DECFSZ	TMP00,F
	 GOTO	REG_INIT0
	MOVLW	HIGH LISTEN_UDP
	MOVWF	MY_UDP
	MOVLW	LOW  LISTEN_UDP
	MOVWF	MY_UDP+1
	CLRF	DHCP_STATE
;------------------------------------------------------------------------------
; メイン動作分岐
;------------------------------------------------------------------------------
	CLRF	PCLATH
	MOVLW	LOW txt_title
	MOVWF	TMP20
	MOVLW	HIGH txt_title
	MOVWF	TMP21
	CALL	getstr
	MOVLW	1
	MOVWF	LCD_Y
	CALL	puts
	CLRW
	CALL	wait_10msX		; LANのリンクアップ待機

	MOVLW	31
	MOVWF	LCD_Y
	CALL	nic_linktest
	BTFSS	STATUS,Z
	 GOTO	usb_mode
	GOTO	ether_mode

	END