// File: CMU-SAFARI[P]ramulator/src/DDR4.cpp
// Function: ramulator::DDR4::init_speed()
void DDR4::init_speed()
{
    const static int RRDS_TABLE[2][5] = {
        {4, 4, 4, 4, 4},
        {5, 5, 6, 7, 9}
    };
    const static int RRDL_TABLE[2][5] = {
        {5, 5, 6, 6, 8},
        {6, 6, 7, 8, 11}
    };
    const static int FAW_TABLE[3][5] = {
        {16, 16, 16, 16, 16},
        {20, 22, 23, 26, 34},
        {28, 28, 32, 36, 48}
    };
    const static int RFC_TABLE[int(RefreshMode::MAX)][3][5] = {{   
            {128, 150, 171, 192, 256},
            {208, 243, 278, 312, 416},
            {280, 327, 374, 420, 560}
        },{
            {88, 103, 118, 132,  176},
            {128, 150, 171, 192, 256},
            {208, 243, 278, 312, 416} 
        },{
            {72, 84, 96, 108, 144},
            {88, 103, 118, 132, 176},
            {128, 150, 171, 192, 256}  
        }
    };
    const static int REFI_TABLE[5] = {
        6240, 7280, 8320, 9360, 12480
    };
    const static int XS_TABLE[3][5] = {
        {136, 159, 182, 204, 272},
        {216, 252, 288, 324, 432},
        {288, 336, 384, 432, 576}
    };

    int speed = 0, density = 0;
    switch (speed_entry.rate) {
        case 1600: speed = 0; break;
        case 1866: speed = 1; break;
        case 2133: speed = 2; break;
        case 2400: speed = 3; break;
        case 3200: speed = 4; break;
        default: assert(false);
    };
    switch (org_entry.size >> 10){
        case 2: density = 0; break;
        case 4: density = 1; break;
        case 8: density = 2; break;
        default: assert(false);
    }
    speed_entry.nRRDS = RRDS_TABLE[org_entry.dq == 16? 1: 0][speed];
    speed_entry.nRRDL = RRDL_TABLE[org_entry.dq == 16? 1: 0][speed];
    speed_entry.nFAW = FAW_TABLE[org_entry.dq == 4? 0: org_entry.dq == 8? 1: 2][speed];
    speed_entry.nRFC = RFC_TABLE[(int)refresh_mode][density][speed];
    speed_entry.nREFI = (REFI_TABLE[speed] >> int(refresh_mode));
    speed_entry.nXS = XS_TABLE[density][speed];
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x20(%rbp)
movl $0x0, -0xc(%rbp)
movl $0x0, -0x10(%rbp)
movl 0x3270(%rax), %eax
movl %eax, -0x14(%rbp)
subl $0x640, %eax            # imm = 0x640
je 0x1990a4
jmp 0x199074
movl -0x14(%rbp), %eax
subl $0x74a, %eax            # imm = 0x74A
je 0x1990ad
jmp 0x199080
movl -0x14(%rbp), %eax
subl $0x855, %eax            # imm = 0x855
je 0x1990b6
jmp 0x19908c
movl -0x14(%rbp), %eax
subl $0x960, %eax            # imm = 0x960
je 0x1990bf
jmp 0x199098
movl -0x14(%rbp), %eax
subl $0xc80, %eax            # imm = 0xC80
je 0x1990c8
jmp 0x1990d1
movl $0x0, -0xc(%rbp)
jmp 0x1990f0
movl $0x1, -0xc(%rbp)
jmp 0x1990f0
movl $0x2, -0xc(%rbp)
jmp 0x1990f0
movl $0x3, -0xc(%rbp)
jmp 0x1990f0
movl $0x4, -0xc(%rbp)
jmp 0x1990f0
leaq 0xb6a89(%rip), %rdi     # 0x24fb61
leaq 0xc3bc2(%rip), %rsi     # 0x25cca1
movl $0x64, %edx
leaq 0xc3bc3(%rip), %rcx     # 0x25ccae
callq 0xc280
movq -0x20(%rbp), %rax
movl 0x2dc0(%rax), %eax
sarl $0xa, %eax
movl %eax, -0x24(%rbp)
subl $0x2, %eax
je 0x19911b
jmp 0x199107
movl -0x24(%rbp), %eax
subl $0x4, %eax
je 0x199124
jmp 0x199111
movl -0x24(%rbp), %eax
subl $0x8, %eax
je 0x19912d
jmp 0x199136
movl $0x0, -0x10(%rbp)
jmp 0x199155
movl $0x1, -0x10(%rbp)
jmp 0x199155
movl $0x2, -0x10(%rbp)
jmp 0x199155
leaq 0xb6a24(%rip), %rdi     # 0x24fb61
leaq 0xc3b5d(%rip), %rsi     # 0x25cca1
movl $0x6a, %edx
leaq 0xc3b5e(%rip), %rcx     # 0x25ccae
callq 0xc280
movq -0x20(%rbp), %rax
movl 0x2dc4(%rax), %esi
xorl %ecx, %ecx
movl $0x1, %edx
cmpl $0x10, %esi
cmovel %edx, %ecx
movslq %ecx, %rdx
leaq 0xc35ea(%rip), %rcx     # 0x25c760
imulq $0x14, %rdx, %rdx
addq %rdx, %rcx
movslq -0xc(%rbp), %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x32c0(%rax)
movl 0x2dc4(%rax), %esi
xorl %ecx, %ecx
movl $0x1, %edx
cmpl $0x10, %esi
cmovel %edx, %ecx
movslq %ecx, %rdx
leaq 0xc35e9(%rip), %rcx     # 0x25c790
imulq $0x14, %rdx, %rdx
addq %rdx, %rcx
movslq -0xc(%rbp), %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x32c4(%rax)
cmpl $0x4, 0x2dc4(%rax)
jne 0x1991cb
xorl %eax, %eax
movl %eax, -0x28(%rbp)
jmp 0x1991e8
movq -0x20(%rbp), %rax
movl 0x2dc4(%rax), %edx
movl $0x2, %eax
movl $0x1, %ecx
cmpl $0x8, %edx
cmovel %ecx, %eax
movl %eax, -0x28(%rbp)
movq -0x20(%rbp), %rax
movl -0x28(%rbp), %ecx
movslq %ecx, %rdx
leaq 0xc35c7(%rip), %rcx     # 0x25c7c0
imulq $0x14, %rdx, %rdx
addq %rdx, %rcx
movslq -0xc(%rbp), %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x32c8(%rax)
movslq 0x2de0(%rax), %rdx
leaq 0xc35e5(%rip), %rcx     # 0x25c800
imulq $0x3c, %rdx, %rdx
addq %rdx, %rcx
movslq -0x10(%rbp), %rdx
imulq $0x14, %rdx, %rdx
addq %rdx, %rcx
movslq -0xc(%rbp), %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x32cc(%rax)
movslq -0xc(%rbp), %rdx
leaq 0xc367b(%rip), %rcx     # 0x25c8c0
movl (%rcx,%rdx,4), %edx
movl 0x2de0(%rax), %ecx
sarl %cl, %edx
movl %edx, %ecx
movl %ecx, 0x32d0(%rax)
movslq -0x10(%rbp), %rdx
leaq 0xc367d(%rip), %rcx     # 0x25c8e0
imulq $0x14, %rdx, %rdx
addq %rdx, %rcx
movslq -0xc(%rbp), %rdx
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x32e4(%rax)
addq $0x30, %rsp
popq %rbp
retq
nopl (%rax)