;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  Project:  TwlSDK - MATH - libraries
;  File:     sha1.s
;
;  Copyright 2008 Nintendo.  All rights reserved.
;
;  These coded instructions, statements, and computer programs contain
;  proprietary information of Nintendo of America Inc. and/or Nintendo
;  Company Ltd., and are protected by Federal copyright law.  They may
;  not be disclosed to third parties or copied or duplicated in any form,
;  in whole or in part, without the prior written consent of Nintendo.
;
;  $Date:$
;  $Rev:$
;  $Author:$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

#define MATH_SHA1_SMALL_STACK

#define EXPAND_FUNC
#define USE_LDMIA

; メモ
;   構造体 MATHSHA1Context のメンバのアライメントは現状以下の通り
;     h - 0 ～ 20
;     block - 20 ～ 84
;   メンバが変更になった場合は要修正

;rfp	.req	r9
;sl	.req	r10
;fp	.req	r11
;ip	.req	r12
;sp	.req	r13
;lr	.req	r14
;pc	.req	r15
    .text
.L100:
.L101:
    .word 0x5A827999
.L102:
    .word 0x6ED9EBA1
.L103:
    .word 0x8F1BBCDC
.L104:
    .word 0xCA62C1D6
.text
	.align 0
	.globl MATHi_SHA1ProcessBlock
	.type MATHi_SHA1ProcessBlock,@function
MATHi_SHA1ProcessBlock:
	stmfd sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr}
	; r3, lr  : 汎用
    ; r4-r8   : a-e
	; r9      : t
	; r10     : tmp
	; r11     : r0バックアップ
	; r12     : wのアドレス

	; 引数をバックアップ
	mov r11, r0
	; ローカル変数を確保
#if !defined(MATH_SHA1_SMALL_STACK)
	;      u32   w[80];
	sub sp, sp, #320
	mov r12, sp
#else
	;      u32   w[16];
	sub sp, sp, #64
	mov r12, sp
#endif

	; r3      : NETSwapBytes32用定数
	; r9      : t
	; r11     : r0バックアップ
	; r12     : wのアドレス
	; r2, lr  : 汎用
	; r4-r7   : ロード値
	; r1, r8  : w[t], context->block[t] のアドレス
	; r0,r1,r2,r8,r10 : not use
	mvn r3, #0x0000FF00
	add r8, r11, #20
	mov r1, r12
	ldmia r8!, {r4, r5, r6, r7}
	; tをセット
    mov r9, #16
.L105:
	; w[t] = NETConvert32HToBE(((u32*)context->block)[t]);
	; w[t+1] = NETConvert32HToBE(((u32*)context->block)[t+1]);
	; w[t+2] = NETConvert32HToBE(((u32*)context->block)[t+2]);
	; w[t+3] = NETConvert32HToBE(((u32*)context->block)[t+3]);
	; NETConvert32HToBEを展開したもの
	eor r2, r4, r4, ror #16
    and r2, r3, r2, lsr #8
    eor r4, r2, r4, ror #8

	; NETConvert32HToBEを展開したもの
	eor r2, r5, r5, ror #16
    and r2, r3, r2, lsr #8
    eor r5, r2, r5, ror #8

	; NETConvert32HToBEを展開したもの
	eor r2, r6, r6, ror #16
    and r2, r3, r2, lsr #8
    eor r6, r2, r6, ror #8

	; NETConvert32HToBEを展開したもの
	eor r2, r7, r7, ror #16
    and r2, r3, r2, lsr #8
    eor r7, r2, r7, ror #8

	stmia r1!, {r4, r5, r6, r7}
	; for (t = 0; t < 16; t+=4)
	subs r9, r9, #4
	ldmneia r8!, {r4, r5, r6, r7}
	bne .L105

#if !defined(MATH_SHA1_SMALL_STACK)
	; r0 - r3, lr  : 汎用
	; r8      : prev
	; r9      : t
	; r11     : r0バックアップ
	; r12     : wのアドレス
	; r4 - r7 : w[t]に書き戻す値
	; r10     : not use
	mov r9, #16

	sub r8, r9, #16
	add r8, r12, r8, lsl #2
	ldr r1, [r8]
	ldr lr, [r8, #8]
.L106:
	; u32    *prev = &w[t - 16];
	; w[t] = NETRotateLeft32(1, prev[ 0] ^ prev[ 2] ^ prev[ 8] ^ prev[13]);
	ldr r3, [r8, #32]
	eor r1, r1, lr
	ldr r2, [r8, #52]
	eor r1, r1, r3
	eor r1, r1, r2
	; NETRotateLeft32
	mov r4, r1, ror #31

	; w[t+1] = NETRotateLeft32(1, prev[ 1] ^ prev[ 3] ^ prev[ 9] ^ prev[14]);
	ldr r1, [r8, #4]
	ldr lr, [r8, #12]
	ldr r3, [r8, #36]
	eor r1, r1, lr
	ldr r2, [r8, #56]
	eor r1, r1, r3
	eor r1, r1, r2
	; NETRotateLeft32
	mov r5, r1, ror #31

	; w[t+2] = NETRotateLeft32(1, prev[ 2] ^ prev[ 4] ^ prev[10] ^ prev[15]);
	ldr r1, [r8, #8]
	ldr lr, [r8, #16]
	ldr r3, [r8, #40]
	eor r1, r1, lr
	ldr r2, [r8, #60]
	eor r1, r1, r3
	eor r1, r1, r2
	; NETRotateLeft32
	mov r6, r1, ror #31

	; w[t+3] = NETRotateLeft32(1, prev[ 3] ^ prev[ 5] ^ prev[11] ^ prev[16]);
	ldr r1, [r8, #12]
	ldr lr, [r8, #20]
	ldr r3, [r8, #44]
	eor r1, r1, lr
	eor r1, r1, r3
	eor r1, r1, r4
	; NETRotateLeft32
	mov r7, r1, ror #31

	add lr, r12, r9, lsl #2
	stmia lr, {r4, r5, r6, r7}

	; for (; t < 80; ++t)
	add r9, r9, #4
    cmp r9, #80
	subne r8, r9, #16
	addne r8, r12, r8, lsl #2
	ldrne r1, [r8]
	ldrne lr, [r8, #8]
	bne .L106
#endif

    ; a,b,c,d,e をロード
#if !defined(USE_LDMIA)
	ldr r4, [r11]
	ldr r5, [r11, #4]
	ldr r6, [r11, #8]
	ldr r7, [r11, #12]
	ldr r8, [r11, #16]
#else
	ldmia r11, {r4, r5, r6, r7, r8}
#endif

	; r3, r2, r1, lr  : 汎用
    ; r4-r8   : a-e
	; r9      : t
	; r10     : tmp
	; r11     : r0バックアップ
	; sp      : wのアドレス
	; r12     : 固定値
	ldr r12, .L101
	mov r9, #0
.L107:
    ; u32     tmp = 0x5A827999UL + ((b & c) | (~b & d));
	and r10, r5, r6
	mvn lr, r5
	and lr, lr, r7
	orr r10, r10, lr
	add r10, r10, r12
    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr lr, [sp, r9, lsl #2]
#else
	and lr, r9, #15
	ldr lr, [sp, lr, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, lr
	add r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

	; for (; t < 16; ++t)
	add r9, r9, #1
    cmp r9, #16
	bne .L107

.L108:
    ; u32     tmp = 0x5A827999UL + ((b & c) | (~b & d));
	and r10, r5, r6
	mvn lr, r5
	and lr, lr, r7
	orr r10, r10, lr
	add r10, r10, r12
#if defined(MATH_SHA1_SMALL_STACK)
    ; w_alias(t) = NETRotateLeft32(1, 
    ;                       w_alias(t - 16 +  0) ^
    ;                       w_alias(t - 16 +  2) ^
    ;                       w_alias(t - 16 +  8) ^
    ;                       w_alias(t - 16 + 13) );
	sub r2, r9, #16
	and r2, r2, #0xF
	sub lr, r9, #14
	and lr, lr, #0xF
	ldr r3, [sp, r2, lsl #2]
	ldr r1, [sp, lr, lsl #2]
	sub lr, r9, #8
	eor r3, r3, r1
	and lr, lr, #0xF
	ldr r1, [sp, lr, lsl #2]
	sub r2, r9, #3
	eor r3, r3, r1
	and r2, r2, #0xF
	ldr r1, [sp, r2, lsl #2]
	and r2, r9, #0xF
	eor r3, r3, r1
	mov r3, r3, ror #31
	str r3, [sp, r2, lsl #2]
#endif
    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr lr, [sp, r9, lsl #2]
#else
	and lr, r9, #15
	ldr lr, [sp, lr, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, lr
	add r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

	; for (; t < 20; ++t)
	add r9, r9, #1
    cmp r9, #20
	bne .L108

	ldr r12, .L102
.L109:
    ; u32     tmp = 0x6ED9EBA1UL + (b ^ c ^ d);
	eor r10, r5, r6
	eor r10, r10, r7
	add r10, r10, r12
#if defined(MATH_SHA1_SMALL_STACK)
    ; w_alias(t) = NETRotateLeft32(1, 
    ;                       w_alias(t - 16 +  0) ^
    ;                       w_alias(t - 16 +  2) ^
    ;                       w_alias(t - 16 +  8) ^
    ;                       w_alias(t - 16 + 13) );
	sub r2, r9, #16
	and r2, r2, #0xF
	sub lr, r9, #14
	and lr, lr, #0xF
	ldr r3, [sp, r2, lsl #2]
	ldr r1, [sp, lr, lsl #2]
	sub lr, r9, #8
	eor r3, r3, r1
	and lr, lr, #0xF
	ldr r1, [sp, lr, lsl #2]
	sub r2, r9, #3
	eor r3, r3, r1
	and r2, r2, #0xF
	ldr r1, [sp, r2, lsl #2]
	and r2, r9, #0xF
	eor r3, r3, r1
	mov r3, r3, ror #31
	str r3, [sp, r2, lsl #2]
#endif
    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr lr, [sp, r9, lsl #2]
#else
	and lr, r9, #15
	ldr lr, [sp, lr, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, lr
	add r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

	; for (; t < 40; ++t)
	add r9, r9, #1
    cmp r9, #40
	bne .L109

	ldr r12, .L103
.L110:
    ; u32     tmp = 0x8F1BBCDCUL + ((b & c) | (b & d) | (c & d));
	and r10, r5, r6
	and lr, r5, r7
	orr r10, r10, lr
	and lr, r6, r7
	orr r10, r10, lr
	add r10, r10, r12
#if defined(MATH_SHA1_SMALL_STACK)
    ; w_alias(t) = NETRotateLeft32(1, 
    ;                       w_alias(t - 16 +  0) ^
    ;                       w_alias(t - 16 +  2) ^
    ;                       w_alias(t - 16 +  8) ^
    ;                       w_alias(t - 16 + 13) );
	sub r2, r9, #16
	and r2, r2, #0xF
	sub lr, r9, #14
	and lr, lr, #0xF
	ldr r3, [sp, r2, lsl #2]
	ldr r1, [sp, lr, lsl #2]
	sub lr, r9, #8
	eor r3, r3, r1
	and lr, lr, #0xF
	ldr r1, [sp, lr, lsl #2]
	sub r2, r9, #3
	eor r3, r3, r1
	and r2, r2, #0xF
	ldr r1, [sp, r2, lsl #2]
	and r2, r9, #0xF
	eor r3, r3, r1
	mov r3, r3, ror #31
	str r3, [sp, r2, lsl #2]
#endif
    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr lr, [sp, r9, lsl #2]
#else
	and lr, r9, #15
	ldr lr, [sp, lr, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, lr
	add r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

	; for (; t < 60; ++t)
	add r9, r9, #1
    cmp r9, #60
	bne .L110

	ldr r12, .L104
.L111:
	; u32     tmp = 0xCA62C1D6UL + (b ^ c ^ d);
	eor r10, r5, r6
	eor r10, r10, r7
	add r10, r10, r12
#if defined(MATH_SHA1_SMALL_STACK)
    ; w_alias(t) = NETRotateLeft32(1, 
    ;                       w_alias(t - 16 +  0) ^
    ;                       w_alias(t - 16 +  2) ^
    ;                       w_alias(t - 16 +  8) ^
    ;                       w_alias(t - 16 + 13) );
	sub r2, r9, #16
	and r2, r2, #0xF
	sub lr, r9, #14
	and lr, lr, #0xF
	ldr r3, [sp, r2, lsl #2]
	ldr r1, [sp, lr, lsl #2]
	sub lr, r9, #8
	eor r3, r3, r1
	and lr, lr, #0xF
	ldr r1, [sp, lr, lsl #2]
	sub r2, r9, #3
	eor r3, r3, r1
	and r2, r2, #0xF
	ldr r1, [sp, r2, lsl #2]
	and r2, r9, #0xF
	eor r3, r3, r1
	mov r3, r3, ror #31
	str r3, [sp, r2, lsl #2]
#endif
    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr lr, [sp, r9, lsl #2]
#else
	and lr, r9, #15
	ldr lr, [sp, lr, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, lr
	add r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

	; for(t=60; t<80; ++t)
	add r9, r9, #1
    cmp r9, #80
	bne .L111

	; r3, r2, r1, lr  : 汎用
	; r9, r10, r12    : 汎用
    ; r4-r8   : a-e
	; r11     : r0バックアップ

    ; a,b,c,d,e をcontext->hに増分する
#if !defined(USE_LDMIA)
	ldr r3, [r11]
	add r3, r3, r4
	str r3, [r11]
	ldr r3, [r11, #4]
	add r3, r3, r5
	str r3, [r11, #4]
	ldr r3, [r11, #8]
	add r3, r3, r6
	str r3, [r11, #8]
	ldr r3, [r11, #12]
	add r3, r3, r7
	str r3, [r11, #12]
	ldr r3, [r11, #16]
	add r3, r3, r8
	str r3, [r11, #16]
#else
	ldmia r11, {r1, r2, r3, r9, r10}
	add r1, r1, r4
	add r2, r2, r5
	add r3, r3, r6
	add r9, r9, r7
	add r10, r10, r8
	stmia r11, {r1, r2, r3, r9, r10}
#endif

	; ローカル変数を解放する
#if !defined(MATH_SHA1_SMALL_STACK)
	;      u32   w[80];
	add sp, sp, #320
#else
	;      u32   w[16];
	add sp, sp, #64
#endif

	ldmfd sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,pc}
.L112:
	.size	MATHi_SHA1ProcessBlock,.L112-.L100


#if !defined(EXPAND_FUNC)
; 注意！ この関数はAPCSに準拠していません！
;        C言語からは利用できません！
.text
    .align 0
    .globl rotate_values
    .type rotate_values,@function
rotate_values:
	; r3, r2  : 汎用
    ; r4-r8   : a-e
	; r9      : t
	; r10     : tmp
	; r11     : r0バックアップ
	; r12     : wのアドレス
	; 呼び出し元であるMATHi_SHA1ProcessBlockに準拠している (lr→r2のみ変更)
	; レジスタのバックアップはとっていない

    ; tmp += w_alias(t) + NETRotateLeft32(5, a) + e;
#if !defined(MATH_SHA1_SMALL_STACK)
	ldr r3, [r12, r9, lsl #2]
#else
	and r3, r9, #15
	ldr r3, [r12, r3, lsl #2]
#endif
	add r10, r10, r8
	add r10, r10, r3
	and r10, r10, r4, ror #27
    ; e = d;
	mov r8, r7
    ; d = c;
	mov r7, r6
    ; c = NETRotateLeft32(30, b);
	mov r6, r5, ror #2
    ; b = a;
	mov r5, r4
    ; a = tmp;
	mov r4, r10

    mov pc, lr
.L113:
    .size   rotate_values,.L113-rotate_values


#if defined(MATH_SHA1_SMALL_STACK)
; 注意！ この関数はAPCSに準拠していません！
;        C言語からは利用できません！
.text
    .align 0
    .globl update_values
    .type update_values,@function
update_values:
	; r3, r2, r1  : 汎用
    ; r4-r8   : a-e
	; r9      : t
	; r10     : tmp
	; r11     : r0バックアップ
	; r12     : wのアドレス
	; 呼び出し元であるMATHi_SHA1ProcessBlockに準拠している (lr→r2のみ変更)
	; レジスタのバックアップはとっていない

    ; w_alias(t) = NETRotateLeft32(1, 
    ;                       w_alias(t - 16 +  0) ^
    ;                       w_alias(t - 16 +  2) ^
    ;                       w_alias(t - 16 +  8) ^
    ;                       w_alias(t - 16 + 13) );
	sub r2, r9, #16
	and r2, r2, #0xF
	ldr r3, [r12, r2, lsl #2]
	sub r2, r9, #14
	and r2, r2, #0xF
	ldr r1, [r12, r2, lsl #2]
	eor r3, r3, r1
	sub r2, r9, #8
	and r2, r2, #0xF
	ldr r1, [r12, r2, lsl #2]
	eor r3, r3, r1
	sub r2, r9, #3
	and r2, r2, #0xF
	ldr r1, [r12, r2, lsl #2]
	eor r3, r3, r1
	mov r3, r3, ror #31
	and r2, r9, #0xF
	str r3, [r12, r2, lsl #2]

    mov pc, lr
.L114:
    .size   update_values,.L114-update_values
#endif
#endif  ; !defined(EXPAND_FUNC)


#if 0
.text
    .align 0
    .globl NETSwapBytes32
    .type NETSwapBytes32,@function
NETSwapBytes32:
    ; r0:n, r1:m, r2:t
    mvn r1, #0x0000FF00
    eor r2, r0, r0, ror #16
    and r2, r1, r2, lsr #8
    eor r0, r2, r0, ror #8
    mov pc, lr
.L115:
    .size   NETSwapBytes32,.L115-NETSwapBytes32


.text
    .align 0
	.globl NETRotateLeft32
	.type NETRotateLeft32,@function
NETRotateLeft32:
	rsb r2, r0, #32
	mov r0, r1, ror r2
	mov pc, lr
.L116:
    .size   NETRotateLeft32,.L116-NETRotateLeft32
#endif
