;===================================================================
;
;		MemoryStick plugin
;		PHYSICAL FORMAT ONE BLOCK
;
; This code receives a set of parameter lists to perform its operation
; A parameter list have 3 parts
;	1. One byte of the TPC code.
;		If the value is 0x00, the operation finishes
;		If the value is 0xFF, then perform a INT detection
;	2. One byte expresses the number of bytes to be transfered
;		If the value is 0x01, a page operation is taken
;		Otherwise the upper nibble is the number of data bytes
;		The lower nibble must be 0 in the 2nd case
;		In case of INT detection, two bytes of timeout value
;		 the value of 30000 will timeout in 10ms
;		 the value of 3000 will timeout in 1ms
;		 the maximum timeout is 16.38ms
;	3. Multiple bytes of the data
;		In case of page operation,
;		 one byte start address and one byte end address
;		In case of normal operation,
;		 the space for reading has to be reserved
;===================================================================
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INT Detection
; :Detect_INT_Transfer
;-------------------
LD	CMP10
SUB16	CMP1		; Apply the maximum timeout duration, 0xFFFF
 
; :Wait_INT_Transfer
;-----------------
LD	A CMP01
LD	Y
 
CP	ADR_BUFFER1=>CMP1
JP :INT_Timeout
 
ADDER16	ADR_BUFFER1
; :Test_INT_Signal
;---------------
LD	A DR_MPEG
BCLR2
JP :Wait_INT_Transfer
DECY			; Test the INT in a loop to remove the noise
JP :Test_INT_Signal
 
JP :Loop_Beginning
 
; :INT_Timeout
STATUS	ERROR STOP
 
;===================================================================
;	Starting point of the code
;===================================================================
 
; :Init_IO
;--------
LD	MSB 0
LD	LSB 4
LD	CTRL_FCI
 
LD	LSB 5
LD	DDR_MPEG	; Port = CLK(PC3), BS(PC1) OUTPUT
 
 
LD	CMP01		; CMP01=5, is used for Y to count cycles
 
LD	LSB 1
LD	X		; Used for adder increase
 
LD	ADR_BUFFER01	; Buffer pointer 0 = 0x0100 (1650)
 
 
LD	MSB 2		; Do not care the LSB
LD	BUFFER_MNGT	; Will use Y for increase the address
 
LD	MSB 15
LD	LSB 15		; The start address is in 0x01FF
LD	ADR_BUFFER00	; We can load the address for retry certain TPC
; :Start_Beginning
LD	A DATA_BUFFER0	; Load the start address
LD	ADR_BUFFER00
 
; :Loop_Beginning
;=========================================================================
; Switch to BS0, toggle the clock first to inform the Memory Stick
LD	LSB 0
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) Low
LD	LSB 4
LD	DR_MPEG		; CLK(PC3) High, SDIO(PC2) Low, BS(PC1) Low
LD	LSB 0
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) Low
 
LD	MSB 0
LD	CMP11		; Clear CMP11
 
; :Get_TPC_Code
;---------------------------------------------------------------------------
; Try to get a code
; code = 0xFF; waiting for the interrupt,
;	the next 2 bytes will be timeout value followed by expect INT value
; code = 0x00; Stop the execution
; code = TPC; start BS1 and send the TPC 
;---------------------------------------------------------------------------
LD	A DATA_BUFFER0
ADDER16	ADR_BUFFER0
CP	A=>X
JP :Check_Valid_TPC
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Increase the page number
;---------------------------------------------------------------------------
LD	A ADR_BUFFER01
LD	ADR_BUFFER11	; Set ADR1 points to parameter segment
 
LD	A DATA_BUFFER0
SUB8	X		; Decrease the loop counter
LD	DATA_BUFFER0	; Restore it to the RAM
CP	A=>X		; Stop the loop when A=0
ADDER16	ADR_BUFFER0
 
LD	A DATA_BUFFER0
LD	ADR_BUFFER10	; Load the 1st address of the page number
ADDER16	ADR_BUFFER0
 
LD	A DATA_BUFFER0
LD	Y		; Load the 2nd address of the page number
 
LD	A <Y>
ADDER8	X
LD	<Y>		; Increase the current page number for read
LD	DATA_BUFFER1	; Increase the current page number for write
 
ADDER16	ADR_BUFFER0	; Repeat address follows
JP :Start_Beginning
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; The following code loads more parameter after all pages have been formated
ADDER16	ADR_BUFFER0	; Skip the repeat address
LD	A DATA_BUFFER0
ADDER16	ADR_BUFFER0
CP	A=>X		; Check this code is not 0x00
JP :Check_Valid_TPC
 
; :Format_Block_Done		; When loop counter counts to 0
STATUS	STOP		; Stop the exection if the following code is 0
;-----------------------------------------------------------------------------
 
; :Check_Valid_TPC
;---------------
LD	CMP00		; Save this code, it maybe a TPC
ADDER8	X
CP	A<X		; When A=0, make a branch
 
LD	A CMP11
LD	ADR_BUFFER10	; Clear Buffer pointer counting parameters
LD	ADR_BUFFER11	; Clear Buffer pointer counting parameters
BRANCH :Detect_INT_Transfer
 
;----------------
; TPC STATE (BS1)
;----------------
LD	MSB 4		; Shifter Pin0 Controled by the shifter
LD	LSB 10		; Shifter rising edge
LD	CTRL_MPEG	; Shifter prescaler /2
 
LD	A X		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) HIGH
LD	DR_MPEG		; Switch to BS1
 
; send out one clock pulse to let the Memory Stick detects the BS1
LD	LSB 5
LD	DR_MPEG		; CLK(PC3) High, SDIO(PC2) Low, BS(PC1) High
LD	LSB 1
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) HIGH
 
LD	A CMP00		; Get saved TPC
LD	SHIFT_MPEG	; send the TPC code
 
;----------------------------
; Initialize CRC calculation
;----------------------------
LD	LSB 4
 
SHIFT	MPEG OUT=>PIN1	; shift out TPC
 
LD	MSB 2		; Reset CRC Reg
LD	CTRL_FCI
LD	MSB 0		; CRC mode
LD	CTRL_FCI
 
LD	Y
; :Wait_TPC_7th_bit
;----------------
DECY			; Y=4 delays 10 cycles
JP :Wait_TPC_7th_bit
 
;;; Set BS to low now to align with the 7th falling edge of TPC code
LD	LSB 0
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) Low
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LD	A DATA_BUFFER0	; Get the number of parameter bytes
ADDER16	ADR_BUFFER0
LD	CMP10
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Check the TPC code for data direction
LD	A CMP00
BSET4			; Test TPC3
LD	MSB 9
LD	LSB 5
BRANCH :Wait_Ready_Busy
 
;------------------------------------------
; DATA TRANSFER STATE (BS2 in WRITE Packet)
;------------------------------------------
LD	A CMP10
CP	A=>X
JP :BS2_Write_Packet
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; When number of parameter is 0, it is a page
LD	LSB 2
LD	CMP11		; Set CMP1=0x200 for page counting
 
; :BS2_Write_Page
;--------------
ADDER16	ADR_BUFFER1
 
LD	A CMP10		; A=0
LD	SHIFT_MPEG
LD	ECC_CRC
SHIFT	MPEG OUT=>PIN1	; Write Packet: shift out 0's
 
LD	LSB 5
LD	Y		; Y=5
; :Shift_Write_Data_Byte
;---------------------
DECY			; Y counts 12 cycles
JP :Shift_Write_Data_Byte
 
CP	ADR_BUFFER1<CMP1
JP :BS2_Write_Page
 
JP :BS2_Write_CRC
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Write Packet: send data from parameter list
; :BS2_Write_Packet
;----------------
LD	A DATA_BUFFER0
LD	SHIFT_MPEG
SHIFT	MPEG OUT=>PIN1	; Write Packet: one byte from parameter list
LD	ECC_CRC
ADDER16	ADR_BUFFER0
ADDER16	ADR_BUFFER1
 
LD	MSB 0
LD	LSB 3
LD	Y
; :Delay_Shift_Data_Out
;--------------------
DECY			; Y=3 delays 8 cycles
JP :Delay_Shift_Data_Out
 
CP	ADR_BUFFER1<CMP1
JP :BS2_Write_Packet
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Write Packet: send 2 bytes CRC
; :BS2_Write_CRC
;-------------
LD	LSB 7
LD	Y
 
LD	A ECC_CRC	; First CRC Byte
LD	SHIFT_MPEG
SHIFT	MPEG OUT=>PIN1	; shift data MPEG Out
 
LD	A Y
; :Delay_Write_1st_CRC
;----------------------
DECY			; Y=7 delays 16 cycles
JP :Delay_Write_1st_CRC
LD	Y
 
LD	A ECC_CRC	; Second CRC Byte
LD	SHIFT_MPEG
LD	A X
SHIFT	MPEG OUT=>PIN1	; shift out the 2nd CRC byte
 
; :Delay_Write_2nd_CRC
;-------------------
DECY			; Y=7 counts 16 cycles
JP :Delay_Write_2nd_CRC
 
; Set BS to high, move to BS3 state
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) High
 
;==========================================================
;==========================================================
; HANDSHAKE STATE (BS2 in Read Packet, BS3 in Write Packet)
;==========================================================
;==========================================================
; :Wait_Ready_Busy
;---------------
;; Switch to reading mode
LD	MSB 4		; Shifter Pin0 Controled by the shifter
LD	LSB 2		; Shifter falling edge, prescaler /2
LD	CTRL_MPEG
 
LD	MSB 0
LD	Y		; Y=2 to control testing RDY signal
 
; :Loop_Waiting
;------------
DECY
JP :Are_You_Ready
 
STATUS ERROR STOP		; Stop when the READY/BUSY timeout
 
; :Are_You_Ready
;-------------
SHIFT	MPEG PIN1=>IN	; shift data in
; :Wait_shift_Ready_Busy
;---------------------
LD	A CTRL_FCI	; load CTRL_FCI
REVERSE
BCLR1			; test shifter status bit
JP :Wait_shift_Ready_Busy
 
LD	A SHIFT_MPEG
LD	MASK
BCLR4
JP :test_ready0
LD	LSB 10		; MASK=XXXX1010b
JP :test_ready
; :test_ready0
;-----------
LD	LSB 5		; MASK=XXXX0101b
; :test_ready
;----------
XOR
CP	A=>X
JP :Loop_Waiting
 
LD	A CMP00
BCLR4			; Test TPC3 for the data direction
LD	MSB 1
LD	LSB 14		; Branch on Write packet
BRANCH	:Loop_Beginning
 
;------------------------------------------
; DATA TRANSFER STATE (BS3 in Read Packet)
;------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Switch to BS3
LD	A X
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) High
 
SHIFT	MPEG PIN1=>IN	; Read Packet: shift 1st data byte in
 
LD	A CMP10
CP	A=>X
 
JP :BS3_Read_Registers
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; When the code after TPC is 0, this is a page
LD	LSB 2
LD	CMP11		; Set CMP1=0x200 for page counting
;;;;;;;;;;;;;;;;;;;;;;;;; Read one page. It should be all 0xFF's or all 0's
 
; :BS3_Read_Page
;-------------
LD	A CMP01
LD	Y
; :Delay_Shift_Page_In
DECY			; Y=5 counts 12 cycles
JP :Delay_Shift_Page_In
LD	Y
 
LD	A SHIFT_MPEG
SHIFT	MPEG PIN1=>IN	; Read Packet: shift data byte in
LD	ECC_CRC
 
ADDER16	ADR_BUFFER1
CP	ADR_BUFFER1<CMP1
JP :BS3_Read_Page
 
JP :BS3_Read_CRC
 
; :BS3_Read_Registers
;======================= The only possible code is GET_INT ==========
LD	LSB 6
LD	Y
; :Delay_Shift_Data_In
;-------------------
DECY			; Y=6 counts 14 cycles
JP :Delay_Shift_Data_In
LD	Y
 
LD	A SHIFT_MPEG
LD	ECC_CRC
SHIFT	MPEG PIN1=>IN	; Read Packet: shift 1st CRC
LD	DATA_BUFFER0
 
; :BS3_Read_CRC
;------------
DECY			; Y=5/6 counts 12/14 cycles
JP :BS3_Read_CRC
 
LD	A ECC_CRC
LD	CMP11		; 1st CRC for compare
LD	A SHIFT_MPEG
LD	ADR_BUFFER11	; 1st CRC
 
SHIFT	MPEG PIN1=>IN	; Read Packet: shift 2nd CRC in
LD	A CMP01
LD	Y
; :Shift_CRC_2nd_Bytes
DECY			; Y=5 counts 12 cycles
JP :Shift_CRC_2nd_Bytes
 
; Set BS to low, move to BS0 state
LD	LSB 0
LD	DR_MPEG		; CLK(PC3) Low, SDIO(PC2) Low, BS(PC1) Low
 
LD	A ECC_CRC
LD	MASK		; 2nd CRC for compare
LD	A SHIFT_MPEG
LD	ADR_BUFFER10	; 2nd CRC
 
XOR
CP	A=>X		; Check 2nd CRC
JP :Read_CRC_Error
 
LD	A CMP11
LD	MASK
LD	A ADR_BUFFER11
XOR
CP	A<X		; Check 1st CRC
JP :CRC_Good
; :Read_CRC_Error
;--------------
STATUS	ERROR STOP
 
; :CRC_Good
;--------
LD	A CMP10		; The number of parameter
CP	A<X		; If it is a 0, this is a page read
JP :Check_CRC_Value
 
LD	A DATA_BUFFER0	; Load the code read by GET_INT
REVERSE
BCLR2
JP :Check_CRC_Done
; :INT_Error
;---------
STATUS	ERROR STOP
 
; :Check_CRC_Value
;---------------
LD	A DATA_BUFFER0	; Get the 2nd CRC from parameter list
ADDER16	ADR_BUFFER0
XOR
CP	A=>X		; Check 2nd CRC value
JP :Page_CRC_Error
 
LD	A DATA_BUFFER0	; Get the 1st CRC from parameter list
LD	MASK
LD	A ADR_BUFFER10
XOR
CP	A<X
 
; :Check_CRC_Done
;--------------
ADDER16	ADR_BUFFER0
LD	MSB 1
LD	LSB 14
BRANCH	:Loop_Beginning
 
; :Page_CRC_Error
;--------------
STATUS ERROR STOP
