// -*- c++ -*-
//
// muldiv.h:
// multiplier/divider unit
//
#ifndef	MULDIV_H
#define	MULDIV_H

#include "sim.h"

//
// muldiv class
//
class muldiv {
public:
    // operation type
    enum OP_TYPE {
        OP_MUL,                 // multiply
        OP_MULU,                // multiply unsigned
        OP_DIV,                 // divide
        OP_DIVU,                // divide unsigned
    };
    
    // accumulation mode
    enum ACC_MODE {
        ACC_SUB_MODE = -1,      // accumulate SUB
        NO_ACC_MODE = 0,        // no accumulate
        ACC_ADD_MODE = 1,       // accumulate ADD
    };

private:
    //
    // constants
    //
    static const int multiply_delay  = 4;	// multiplier delay
    static const int multiply_interval = 1;	// multiplier interval (can issue every cycle)

    static const int divide_delay = 16; 	// divider delay
    static const int divide_interval = 16; 	// divider interval (no pipelined activity allowed)

    //
    // member variables
    //
    sim_word    Hi;             // HI register (for Mul/Div)
    sim_word    Lo;             // LO register (for Mul/Div)

    int         busy_count;     // busy-counter for current operation
    int         interval_count; // interval-counter for waiting until next issue time

    // buffer for input
    ACC_MODE    acc_mode;       // accumulation mode
    OP_TYPE     op_type;        // operation type
    sim_word    A;              // input value 1
    sim_word    B;              // input value 2

public:

    // constructor
    muldiv() {
        reset();
    };

    // destructor
    ~muldiv() {
        // nothing to do
    }

    // reset
    void reset();

    // check mul/div unit's readiness
    bool is_done() { return busy_count <= 0; }		// operation complete
    bool is_ready() { return interval_count <= 0; }	// ready to issue

    // accessor to HI/LO registers
    sim_word &HI() { return Hi; }
    sim_word &LO() { return Lo; }

    // request operation
    void initiate(sim_word a, sim_word b, OP_TYPE op, ACC_MODE acc = NO_ACC_MODE);

    // update muldiv's internal state (to be called in every cycle)
    void update();
};

#endif
// end of muldiv.h