// File: CMU-SAFARI[P]ramulator/src/DDR4.cpp
// Function: ramulator::DDR4::init_prereq()
void DDR4::init_prereq()
{
    // RD
    prereq[int(Level::Rank)][int(Command::RD)] = [] (DRAM<DDR4>* node, Command cmd, int id) {
        switch (int(node->state)) {
            case int(State::PowerUp): return Command::MAX;
            case int(State::ActPowerDown): return Command::PDX;
            case int(State::PrePowerDown): return Command::PDX;
            case int(State::SelfRefresh): return Command::SRX;
            default: assert(false);
        }};
    prereq[int(Level::Bank)][int(Command::RD)] = [] (DRAM<DDR4>* node, Command cmd, int id) {
        switch (int(node->state)) {
            case int(State::Closed): return Command::ACT;
            case int(State::Opened):
                if (node->row_state.find(id) != node->row_state.end())
                    return cmd;
                else return Command::PRE;
            default: assert(false);
        }};

    // WR
    prereq[int(Level::Rank)][int(Command::WR)] = prereq[int(Level::Rank)][int(Command::RD)];
    prereq[int(Level::Bank)][int(Command::WR)] = prereq[int(Level::Bank)][int(Command::RD)];

    // REF
    prereq[int(Level::Rank)][int(Command::REF)] = [] (DRAM<DDR4>* node, Command cmd, int id) {
        for (auto bg : node->children)
            for (auto bank: bg->children) {
                if (bank->state == State::Closed)
                    continue;
                return Command::PREA;
            }
        return Command::REF;};

    // PD
    prereq[int(Level::Rank)][int(Command::PDE)] = [] (DRAM<DDR4>* node, Command cmd, int id) {
        switch (int(node->state)) {
            case int(State::PowerUp): return Command::PDE;
            case int(State::ActPowerDown): return Command::PDE;
            case int(State::PrePowerDown): return Command::PDE;
            case int(State::SelfRefresh): return Command::SRX;
            default: assert(false);
        }};

    // SR
    prereq[int(Level::Rank)][int(Command::SRE)] = [] (DRAM<DDR4>* node, Command cmd, int id) {
        switch (int(node->state)) {
            case int(State::PowerUp): return Command::SRE;
            case int(State::ActPowerDown): return Command::PDX;
            case int(State::PrePowerDown): return Command::PDX;
            case int(State::SelfRefresh): return Command::SRE;
            default: assert(false);
        }};
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x18(%rbp)
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x180, %rdi            # imm = 0x180
addq $0x60, %rdi
leaq -0x9(%rbp), %rsi
callq 0x19b0e0
movq -0x18(%rbp), %rdi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x480, %rdi            # imm = 0x480
addq $0x60, %rdi
leaq -0xa(%rbp), %rsi
callq 0x19b130
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x1e0, %rsi            # imm = 0x1E0
addq $0x180, %rsi            # imm = 0x180
addq $0x60, %rsi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x180, %rdi            # imm = 0x180
addq $0x80, %rdi
callq 0x1a0d50
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x1e0, %rsi            # imm = 0x1E0
addq $0x480, %rsi            # imm = 0x480
addq $0x60, %rsi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x480, %rdi            # imm = 0x480
addq $0x80, %rdi
callq 0x1a0d50
movq -0x18(%rbp), %rdi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x180, %rdi            # imm = 0x180
addq $0xe0, %rdi
leaq -0xb(%rbp), %rsi
callq 0x19b180
movq -0x18(%rbp), %rdi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x180, %rdi            # imm = 0x180
addq $0x100, %rdi            # imm = 0x100
leaq -0xc(%rbp), %rsi
callq 0x19b1d0
movq -0x18(%rbp), %rdi
addq $0x1e0, %rdi            # imm = 0x1E0
addq $0x180, %rdi            # imm = 0x180
addq $0x140, %rdi            # imm = 0x140
leaq -0xd(%rbp), %rsi
callq 0x19b220
addq $0x20, %rsp
popq %rbp
retq