// File: CMU-SAFARI[P]ramulator/src/SALP.cpp
// Function: ramulator::SALP::init_lambda()
void SALP::init_lambda()
{
    switch(int(type)){
        case int(Type::SALP_1):
            lambda[int(Level::Bank)][int(Command::ACT)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Opened;
            };
            lambda[int(Level::SubArray)][int(Command::ACT)] = [] (DRAM<SALP>* node, int id) {
              node->state = State::Opened;
              node->row_state[id] = State::Opened;
            };
            lambda[int(Level::Bank)][int(Command::PRE)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                // For SALP_1, we stick to original design that allows
                // only one row in a bank open, so here close subarray id
                // is equivalent to close the whole bank
                node->children[id]->state = State::Closed;
                node->children[id]->row_state.clear();
                };
            lambda[int(Level::Bank)][int(Command::PRE_OTHER)] = lambda[int(Level::Bank)][int(Command::PRE)];
            lambda[int(Level::Rank)][int(Command::PRER)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children) {
                    bank->state = State::Closed;
                    for (auto sa : bank->children){
                        sa->state = State::Closed;
                        sa->row_state.clear();}}};
            lambda[int(Level::Bank)][int(Command::RDA)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->children[id]->state = State::Closed;
                node->children[id]->row_state.clear();};
            lambda[int(Level::Bank)][int(Command::WRA)] = lambda[int(Level::Bank)][int(Command::RDA)];
            lambda[int(Level::Rank)][int(Command::PDE)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children) {
                    if (bank->state == State::Closed)
                        continue;
                    node->state = State::ActPowerDown;
                    return;
                }
                node->state = State::PrePowerDown;};
            break;
        case int(Type::SALP_2):
            lambda[int(Level::SubArray)][int(Command::ACT)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Opened;
                node->row_state[id] = State::Opened;};
            lambda[int(Level::SubArray)][int(Command::PRE)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};
            lambda[int(Level::SubArray)][int(Command::PRE_OTHER)] = lambda[int(Level::SubArray)][int(Command::PRE)];
            lambda[int(Level::Rank)][int(Command::PRER)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children)
                    for (auto sa : bank->children) {
                        sa->state = State::Closed;
                        sa->row_state.clear();}};
            lambda[int(Level::SubArray)][int(Command::RDA)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};
            lambda[int(Level::SubArray)][int(Command::WRA)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};
            lambda[int(Level::Rank)][int(Command::PDE)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children)
                    for (auto sa : bank->children) {
                        if (sa->state == State::Closed)
                            continue;
                        node->state = State::ActPowerDown;
                        return;
                    }
                node->state = State::PrePowerDown;};
            break;
        case int(Type::MASA):
            lambda[int(Level::SubArray)][int(Command::ACT)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Selected;
                node->row_state[id] = State::Opened;
                for (auto sa : node->parent->children)
                    if (sa != node && sa->state == State::Selected) {
                        sa->state = State::Opened;
                        break;}};
            lambda[int(Level::SubArray)][int(Command::SASEL)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Selected;
                for (auto sa : node->parent->children)
                    if (sa != node && sa->state == State::Selected) {
                        sa->state = State::Opened;
                        break;}};
            lambda[int(Level::SubArray)][int(Command::PRE)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};

            lambda[int(Level::Rank)][int(Command::PRER)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children)
                    for (auto sa : bank->children) {
                        sa->state = State::Closed;
                        sa->row_state.clear();}};
            lambda[int(Level::SubArray)][int(Command::RDA)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};
            lambda[int(Level::SubArray)][int(Command::WRA)] = [] (DRAM<SALP>* node, int id) {
                node->state = State::Closed;
                node->row_state.clear();};
            lambda[int(Level::Rank)][int(Command::PDE)] = [] (DRAM<SALP>* node, int id) {
                for (auto bank : node->children)
                    for (auto sa : bank->children) {
                        if (sa->state == State::Closed)
                            continue;
                        node->state = State::ActPowerDown;
                        return;
                    }
                node->state = State::PrePowerDown;};
            break;
        default: assert(false);
    }
    lambda[int(Level::Rank)][int(Command::PDX)] = [] (DRAM<SALP>* node, int id) {
        node->state = State::PowerUp;};
    lambda[int(Level::Rank)][int(Command::SRE)] = [] (DRAM<SALP>* node, int id) {
        node->state = State::SelfRefresh;};
    lambda[int(Level::Rank)][int(Command::SRX)] = [] (DRAM<SALP>* node, int id) {
        node->state = State::PowerUp;};
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x30(%rbp)
movl 0x20(%rax), %eax
movl %eax, -0x24(%rbp)
testl %eax, %eax
je 0x20440f
jmp 0x2043f0
movl -0x24(%rbp), %eax
subl $0x1, %eax
je 0x204535
jmp 0x2043fe
movl -0x24(%rbp), %eax
subl $0x2, %eax
je 0x20462c
jmp 0x20470c
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x380, %rdi            # imm = 0x380
leaq -0x9(%rbp), %rsi
callq 0x206c60
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
leaq -0xa(%rbp), %rsi
callq 0x206cb0
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x380, %rdi            # imm = 0x380
addq $0x40, %rdi
leaq -0xb(%rbp), %rsi
callq 0x206d00
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x29b0, %rsi           # imm = 0x29B0
addq $0x380, %rsi            # imm = 0x380
addq $0x40, %rsi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x380, %rdi            # imm = 0x380
addq $0x1a0, %rdi            # imm = 0x1A0
callq 0x212370
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x60, %rdi
leaq -0xc(%rbp), %rsi
callq 0x206d50
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x380, %rdi            # imm = 0x380
addq $0xc0, %rdi
leaq -0xd(%rbp), %rsi
callq 0x206da0
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x29b0, %rsi           # imm = 0x29B0
addq $0x380, %rsi            # imm = 0x380
addq $0xc0, %rsi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x380, %rdi            # imm = 0x380
addq $0xe0, %rdi
callq 0x212370
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x120, %rdi            # imm = 0x120
leaq -0xe(%rbp), %rsi
callq 0x206df0
jmp 0x20472b
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
leaq -0xf(%rbp), %rsi
callq 0x206e40
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0x40, %rdi
leaq -0x10(%rbp), %rsi
callq 0x206e90
movq -0x30(%rbp), %rdi
movq %rdi, %rsi
addq $0x29b0, %rsi           # imm = 0x29B0
addq $0x540, %rsi            # imm = 0x540
addq $0x40, %rsi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0x1a0, %rdi            # imm = 0x1A0
callq 0x212370
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x60, %rdi
leaq -0x11(%rbp), %rsi
callq 0x206ee0
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0xc0, %rdi
leaq -0x12(%rbp), %rsi
callq 0x206f30
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0xe0, %rdi
leaq -0x13(%rbp), %rsi
callq 0x206f80
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x120, %rdi            # imm = 0x120
leaq -0x14(%rbp), %rsi
callq 0x206fd0
jmp 0x20472b
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
leaq -0x15(%rbp), %rsi
callq 0x207020
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0x20, %rdi
leaq -0x16(%rbp), %rsi
callq 0x207070
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0x40, %rdi
leaq -0x17(%rbp), %rsi
callq 0x2070c0
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x60, %rdi
leaq -0x18(%rbp), %rsi
callq 0x207110
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0xc0, %rdi
leaq -0x19(%rbp), %rsi
callq 0x207160
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x540, %rdi            # imm = 0x540
addq $0xe0, %rdi
leaq -0x1a(%rbp), %rsi
callq 0x2071b0
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x120, %rdi            # imm = 0x120
leaq -0x1b(%rbp), %rsi
callq 0x207200
jmp 0x20472b
leaq 0x4b44e(%rip), %rdi     # 0x24fb61
leaq 0x5e4bb(%rip), %rsi     # 0x262bd5
movl $0x1a8, %edx            # imm = 0x1A8
leaq 0x5e579(%rip), %rcx     # 0x262c9f
callq 0xc280
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x140, %rdi            # imm = 0x140
leaq -0x1c(%rbp), %rsi
callq 0x207250
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x160, %rdi            # imm = 0x160
leaq -0x1d(%rbp), %rsi
callq 0x2072a0
movq -0x30(%rbp), %rdi
addq $0x29b0, %rdi           # imm = 0x29B0
addq $0x1c0, %rdi            # imm = 0x1C0
addq $0x180, %rdi            # imm = 0x180
leaq -0x1e(%rbp), %rsi
callq 0x2072f0
addq $0x30, %rsp
popq %rbp
retq
nopw (%rax,%rax)