;EXAM13
;93C46 16 BIT READ/WRITE DEMO 00H-3FH

EEPCLK	EQU	P1.0
EEPDI	EQU	P1.1
EEPDO	EQU	P1.2
EEPCS	EQU	P1.3

MAXBUF	EQU	11

	ORG	30H
StrBuff:	DS	1
REGADR:		DS	1
REGDAT1:	DS	1
REGDAT2:	DS	1

buffer:		DS	MAXBUF		;Command Buffer

	ORG	0000H

; *** Power up delay ***
;Wait for other Device
RES:	MOV	R2,#40H
RES1:	MOV	R3,#0
RES2:	DJNZ	R3,RES2
	DJNZ	R2,RES1

;EEPROM 93C46 Initial
	CLR	EEPCLK
	CLR	EEPCS
	MOV	REGADR,#00H


MAIN:	LCALL	InitUART	;Initial UART 9600,n,8,1 no parity

	MOV	DPTR,#Hello
	LCALL	SendSROM 

	LCALL	EPENABLE	;ENABLE EEPROM
	MOV	R2,#00H
	LCALL	EPREAD

	;LCALL	EEPTEST

ScanStr:
	MOV	R0,#buffer	;point to buffer
	LCALL	GetStr

	MOV	R0,#buffer	;load buffer Ptr
	LCALL	GetCmd		;found = 1...n
	JZ	ScanEx		; 0 = isn't Command

	MOV	StrBuff,A	;store result in StrBuff

;Check Command No
;Check Command 1
	XRL	A,#01		;?Compare A=1
	JZ	Cmd1		;switch to x

;Check Command 2
	MOV	A,StrBuff	;Restore
	XRL	A,#02		;?Compare A=2
	JZ	Cmd2

;Check Command 3
	MOV	A,StrBuff	;Restore
	XRL	A,#03		;?Compare A=3
	JZ	Cmd3

	JMP	ScanStr

ScanEx:	MOV	DPTR,#ErrMsg1
	LCALL	SendSROM
	LCALL	LineFeed

	JMP	ScanStr
;Treat Command
Cmd1:	LCALL	DoCmd1
	LJMP	ScanStr

;*** Read EEPROM Command
Cmd2:	LCALL	DoCmd2
	LJMP	ScanStr

Cmd3:	LCALL	EPERALL
	MOV	DPTR,#EraAll
	LCALL	SendSROM

	LJMP	ScanStr

LenErr:	MOV	DPTR,#ErrMsg3
	LCALL	SendSROM
	RET

; ** Wroking Command1 ***
;* Write EEPROM
DoCmd1:
	LCALL	LineFeed

	MOV	R0,#buffer
	LCALL	Strlen
	XRL	A,#10
	JZ	DoCmd1A
	LCALL	LenErr
	RET
DoCmd1A:
	LCALL	GetArg1
	MOV	REGADR,A
	LCALL	SBYTEH

	LCALL	GetArg2
	MOV	REGDAT1,A
	LCALL	SBYTEH

	LCALL	GetArg3
	MOV	REGDAT2,A
	LCALL	SBYTEH

	MOV	R2,REGADR
	LCALL	EPERASE		;ERASE

	MOV	R2,REGADR
	MOV	R3,REGDAT1
	MOV	R4,REGDAT2

	LCALL	EPWRITE		;WRITE
	LCALL	LineFeed
	RET

; ** Wroking Command3 ***
;* Dump EEPROM 64 Byte 00H-3FH *
DoCmd2:
	LCALL	LineFeed
	MOV	R0,#buffer
	LCALL	Strlen
	XRL	A,#04h
	JZ	DoCmd2a
	LCALL	LenErr
	LJMP	ScanStr
DoCmd2a:
	LCALL	GetArg1
	MOV	REGADR,A
;Read EEProm	
	MOV	R2,REGADR
	LCALL	EPREAD

	MOV	A,R3
	LCALL	SBYTEH

	MOV	A,#' '
	LCALL	SBYTE

	MOV	A,R4
	LCALL	SBYTEH

	LCALL	LineFeed
	RET

;********** ATOH SUB **********
; ASCII	TO HEX CONVERT
; IN  =	R2,R3	30H,41H
; OUT =	A	0AH
; REG =	A,R2

ATOH:	MOV	A,R2
	LCALL	ATOHS
	SWAP	A
	MOV	R2,A
	MOV	A,R3
	LCALL	ATOHS
	ORL	A,R2
	RET

ATOHS:	CJNE	A,#'A',$+3
	JC	ATOHS1
	ADD	A,#9
ATOHS1:	ANL	A,#0FH
	RET

;* Get Argument 1 *
;IN R2,R3
;OUT A
GetArg1:
	MOV	A,buffer+2
	MOV	R2,A
	MOV	A,buffer+3
	MOV	R3,A
	LCALL	ATOH
	RET

;* Get Argument 2 *
;IN R2,R3
;OUT A
GetArg2:
	MOV	A,buffer+5
	MOV	R2,A
	MOV	A,buffer+6
	MOV	R3,A
	LCALL	ATOH
	RET

;* Get Argument 3 *
;IN R2,R3
;OUT A
GetArg3:
	MOV	A,buffer+8
	MOV	R2,A
	MOV	A,buffer+9
	MOV	R3,A
	LCALL	ATOH
	RET
;*** Get String ***
;IN R0 pointer to String Buffer
;R3 count n of Str
;
GetStr:	MOV	R3,#0
GetSnx:	CLR	A
	LCALL	RBYTE		;READ -> A

	MOV	StrBuff,A	;Restore char in StrBuff

;check end of str
	XRL	A,#0Dh		;Carriage Return <CR>
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#0Ah		;line feed  LF
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#1Bh		;line feed  LF
	JZ	GetESC

	MOV	A,StrBuff	;Restore char in StrBuff
	LCALL	SBYTE		;A    -> Send ECho
	MOV	@R0,StrBuff	;store in buffer
	INC	R0		;next point
	INC	R3		;count str

;Test buffer full
	MOV	A,R3
	XRL	A,#MAXBUF	;Compare with MAXBUFFER
	JZ	Sendfull	;>= MAXBUFFER

	SJMP	GetSnx

ChkStr:	MOV	A,R3
	JZ	GetDis		;if len = 0
	MOV	@R0,#0		;end of String
	RET
GetDis:
	LCALL	DumpE
	SJMP	GetStr

GetESC:
	MOV	DPTR,#Abortx
	LCALL	SendSROM
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr


Sendfull:
	MOV	DPTR,#ErrMsg2
	LCALL	SendSROM
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr

; *** Get Command ***
;R0    point to Str buffer
;DPTR  point to command
;R2    save
;R7    result
;return command in	A
;	found		1...n
;	not found	0
;
;REG change = R0,R2,R7
;
GetCmd:	MOV	R7,#01		;count
	MOV	A,R0		;save R0->R2
	MOV	R2,A		;Restore Ptr

	MOV	DPTR,#Command1
	LCALL	StrCmp
	JZ	CmdEQU		;A=0 Equ

;If not Equ next Cmp

	INC	R7		;inc result
	MOV	A,R2		;get ptr
	MOV	R0,A		;Reload	Ptr

	MOV	DPTR,#Command2
	LCALL	StrCmp
	JZ	CmdEQU

	INC	R7		;inc result
	MOV	A,R2		;get ptr
	MOV	R0,A		;Reload	Ptr

	MOV	DPTR,#Command3
	LCALL	StrCmp
	JZ	CmdEQU


;not found
	MOV	R7,#0		;result	is NULL

CmdEQU:	MOV	A,R7		;result	in R7
	RET

;StrCmp(@R0,DPTR);
;R0    point to Str buffer
;DPTR  point to command
;reg change  = R0,DPTR
;result in A  0   = Equ
;             FFh = nEqu
StrCmp:	CLR	A
	MOVC	A,@A+dptr
	JZ	StrEq		;end of	str
	XRL	A,@R0		;Compare A=@R0 ?
	JNZ	StrNEq
	       
	INC	R0		;next char in buffer
	INC	dptr		;next command
	JMP	StrCmp
	       
StrNEq:	MOV	A,#0FFh		;not equal
	RET    
StrEq:	CLR	A		;equal ret 0
	RET    

;* EEPTEST
EEPTEST:

	MOV	R2,#00H		;Address
	LCALL	EPERASE		;ERASE

	MOV	R2,#00H		;Address
	MOV	R3,#91H		;Data
	MOV	R4,#92H		;Data
	LCALL	EPWRITE		  ;WRITE


	RET

;*** EEPROM READ SUB ***
;93C46 READ WORD SUBROUTINE
;IN  = R2 ADDRESS (0-63)
;OUT DATA = R3,R4
;REG = A,R2,R3

EPREAD:	MOV	A,R2
	ANL	A,#00111111B	;MAKE	SURE DATA=6 BIT
	ORL	A,#10000000B	;OPCODE

	SETB	EEPCS		;CS=1
	SETB	EEPDI		;START BIT
	LCALL	CLOCK

	MOV	R2,#8		;OPCODE,ADDRESS
EPRD2:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPRD2

;Read 8 bit
	MOV	R2,#8		;READ	DATA (8	BIT FIRST)
EPRD4:	LCALL	CLOCK
	MOV	C,EEPDO
	RLC	A
	DJNZ	R2,EPRD4

	MOV	R3,A		;Save to R3

	MOV	R2,#8		;READ	DATA (8	BIT LAST)
EPRD5:	LCALL	CLOCK
	MOV	C,EEPDO
	RLC	A
	DJNZ	R2,EPRD5
	MOV	R4,A

	CLR	EEPCS		;CS=0
	RET

CLOCK:	SETB	EEPCLK		;SYNC	CLOCK
	NOP
	NOP
	CLR	EEPCLK
	NOP
	NOP
	RET

;*** EPWRITE SUB ***
; 93C46 WRITE WORD SUBROUTINE
; IN  = R2 ADDRESS (0-63)
;     = R3,R4 DATA
; REG = A,R2

EPWRITE:
	MOV	A,R2
	ANL	A,#00111111B	;MAKE	SURE DATA=6 BIT
	ORL	A,#01000000B	;OPCODE

	SETB	EEPCS		;CS=1
	SETB	EEPDI		;START BIT
	LCALL	CLOCK

;Address
	MOV	R2,#8		;OPCODE,ADDRESS
EPWR2:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPWR2

;Data 8
	MOV	R2,#8		;WRITE DATA (8 BIT FIRST)
	MOV	A,R3
EPWR4:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPWR4

	MOV	R2,#8		;WRITE DATA (8 BIT LAST)
	MOV	A,R4		;R4
EPWR5:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPWR5

	CLR	EEPCS		;CS=0
	NOP
	NOP
	SETB	EEPCS		;CS=1	(CHECK STATUS)
	NOP
	NOP
	JNB	EEPDO,$		;WAIT	FOR BUSY
	NOP
	NOP
	CLR	EEPCS		;CS=0
	RET

;*** EPERASE SUB ***
; 93C46 ERASE WORD SUBROUTINE
; IN  = R2 ADDRESS (0-63)
; REG = A,R2

EPERASE:MOV	A,R2
	ANL	A,#00111111B	;MAKE	SURE DATA=6 BIT
	ORL	A,#11000000B	;OPCODE

	SETB	EEPCS		;CS=1
	SETB	EEPDI		;START BIT
	LCALL	CLOCK

	MOV	R2,#8		;OPCODE,ADDRESS
EPERA2:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPERA2

	CLR	EEPCS		;CS=0
	NOP
	NOP
	SETB	EEPCS		;CS=1	(CHECK STATUS)
	NOP
	NOP
	JNB	EEPDO,$		;WAIT	FOR BUSY
	NOP
	NOP
	CLR	EEPCS		;CS=0
	RET

;*** EPERASE ALL ***
; 93C46 ERASE WORD SUBROUTINE
; IN  = R2 ADDRESS (0-63)
; REG = A,R2

EPERALL:
	MOV	R6,#64
	MOV	R2,#00
	MOV	REGADR,#00
EPERALX:
	MOV	R2,REGADR
	MOV	R3,#0FFH
	MOV	R4,#0FFH
	LCALL	EPWRITE		;WRITE
	INC	REGADR
	DJNZ	R6,EPERALX

	RET


;*** EPENABLE SUB ***
;93C46 ENABLE SUBROUTINE
;REG = A,R2

EPENABLE:	
	MOV	A,#00110000B      ;OPCODE
	SETB	EEPCS		;CS=1
	SETB	EEPDI		;START BIT
	LCALL	CLOCK

	MOV	R2,#8		;OPCODE,ADDRESS
EPEN2:	RLC	A
	MOV	EEPDI,C
	LCALL	CLOCK
	DJNZ	R2,EPEN2
	RET

; *** Initial UART ***
InitUART:
	MOV	SCON,#01010010B	;Set SCON Serial Control Mode 1: 8-bit UART (Timer-Based). 
	MOV	TMOD,#00100000B	;Set Mode 2  8-bit Auto-Reload
	MOV	TH1,#0FDH	;Set Baud Rate 9600
	SETB	TR1		;Enable Timer 1
	RET

; ********** SBYTE SUB **********
;SEND BYTE
;IN  =	A
;REG =	NO
SBYTE:	JNB	TI,SBYTE	;Wait For Sending done
	CLR	TI
	MOV	SBUF,A
	RET

; ********** RBYTE SUB **********
;OUT =	A
;REG =	A
RBYTE:	JNB	RI,RBYTE	;Wait For Receive already
	CLR	RI
	MOV	A,SBUF
	RET

; *** Send line feed ***
LineFeed:
	MOV	A,#0Dh
	LCALL	SBYTE
feed:	MOV	A,#0Ah
	LCALL	SBYTE
	RET
; ********** SBYTEH SUB **********
; SEND 2 BYTE HEX FROM A
; IN  = A
; REG = A,R2,R3
SBYTEH:	LCALL	HTOA
	MOV	A,R2
	LCALL	SBYTE
	MOV	A,R3
	LCALL	SBYTE

	RET
; ********** HTOA SUB **********
; CONVERT HEX TO ASCII
; IN  = A
; OUT = R2,R3
; REG = A,R2,R3

HTOA:	PUSH	ACC
	SWAP	A
	LCALL	HTOAS
	MOV	R2,A
	POP	ACC
	LCALL	HTOAS
	MOV	R3,A
	RET

HTOAS:	ANL	A,#0FH
	CJNE	A,#0AH,$+3
	JNC	HTOAS1
	ORL	A,#30H
	RET
HTOAS1:	SUBB	A,#9
	ORL	A,#40H
	RET

; *** Send String in Program Memory ***
;Input 	DPTR
SendSROM:
	CLR	A
	MOVC	A,@A+DPTR	;load char
	JZ	EndStr		;yes end
	LCALL	SBYTE		;send 1	byte
	INC	DPTR		;point to next char
	SJMP	SendSROM		;load next char

EndStr:	RET

; *** String LEN ***
;IN R0
;OUT A
Strlen:	MOV	R2,#0

StrLNx:	MOV	A,@R0
	XRL	A,#0
	JZ	StrLEX
	INC	R0
	INC	R2
	SJMP	StrLNx

StrLEX:	MOV	A,R2
	RET

;*** Dump EEPROM ***
;IN REGADR	ADDRESS
;
DumpE:

	MOV	DPTR,#Header
	LCALL	SendSROM 

	MOV	REGADR,#00
	MOV	R2,REGADR	;Get Address from REGADR
	MOV	R7,#08H		;line = 8

;Header
DumpEa:
	MOV	R6,#08H		;Reload
	MOV	A,REGADR	;Send Dump Header:
	LCALL	SBYTEH
	MOV	A,#':'
	LCALL	SBYTE
	MOV	A,#' '
	LCALL	SBYTE

DumpE2:
	MOV	R2,REGADR
	LCALL	EPREAD	;Read to R3,R4

	MOV	A,R3
	LCALL	SBYTEH
	MOV	A,#' '
	LCALL	SBYTE
	MOV	A,R4
	LCALL	SBYTEH

	MOV	A,#' '
	LCALL	SBYTE
	INC	REGADR

	DJNZ	R6,DumpE2
	LCALL	LineFeed
	DJNZ	R7,DumpEa
	LCALL	LineFeed

	RET


Hello:		DB	0DH,"*** EEPROM 93C46 ***",0DH,0AH,00
Header:		DB	0DH,"93C46 16 Bit Adress (00H-3FH)",0DH,0AH,00
ErrMsg1:	DB	0Dh,0Ah,'Invalid Command',00
ErrMsg2:	DB	0Dh,0Ah,'buffer full',0Dh,0Ah,00
ErrMsg3:	DB	0Dh,0Ah,'Lenght Error',0Dh,0Ah,00
Abortx:		DB	0Dh,0Ah,'*** Abort ***',0Dh,0Ah,00
EraAll:		DB	0Dh,0Ah,'ERASE ALL',0Dh,0Ah,00

Command1:	DB	'w ',00
Command2:	DB	'r ',00
Command3:	DB	'x',00

	END

