package projet

import chisel3._
import chisel3.util._

class Divider(width: Int, nCycles: Int) extends Module {
    require(
        nCycles >= 1 && nCycles <= width,
        "nCycles must be between 1 and width"
    )

    val io = IO(new Bundle {
        val dividend = Input(UInt(width.W))
        val divisor = Input(UInt(width.W))
        val word_mode = Input(Bool())
        val start = Input(Bool())
        val ready = Output(Bool())
        val quotient = Output(UInt(width.W))
        val remainder = Output(UInt(width.W))
    })

    val reg_dividend = Reg(UInt(width.W))
    val reg_divisor = Reg(UInt((width * 2).W))
    val reg_divisor_start = Reg(UInt(width.W))
    val reg_quotient = Reg(UInt(width.W))
    val reg_current_shift = Reg(UInt((log2Ceil(width) + 1).W))

    val bits_per_cycle = ((width + nCycles - 1) / nCycles)

    val cycles_remaining = RegInit(0.U(log2Ceil(nCycles + 1).W))
    val busy = RegInit(false.B)

    io.ready := !busy
    io.quotient := reg_quotient
    io.remainder := reg_dividend(width - 1, 0)

    when(io.start && !busy) {
        reg_dividend := io.dividend
        reg_divisor := io.divisor << (width - 1)
        reg_divisor_start := io.divisor
        reg_quotient := 0.U
        reg_current_shift := (width - 1).U
        cycles_remaining := nCycles.U
        busy := true.B
    }

    when(busy) {
        val stages = Wire(Vec(bits_per_cycle + 1, UInt(width.W)))
        val dstages = Wire(Vec(bits_per_cycle + 1, UInt((width * 2).W)))
        val qstages = Wire(Vec(bits_per_cycle + 1, UInt(width.W)))

        stages(0) := reg_dividend
        dstages(0) := reg_divisor
        qstages(0) := reg_quotient

        for (i <- 0 until bits_per_cycle) {
            val cur = stages(i)
            val curD = dstages(i)
            val curQ = qstages(i)

            when(cur >= curD) {
                stages(i + 1) := cur - curD
                qstages(i + 1) := curQ + (1.U << (reg_current_shift - i.U))
            }.otherwise {
                stages(i + 1) := cur
                qstages(i + 1) := curQ

            }
            dstages(i + 1) := curD >> 1
        }

        reg_dividend := stages(bits_per_cycle)
        reg_divisor := dstages(bits_per_cycle)
        reg_quotient := qstages(bits_per_cycle)
        reg_current_shift := reg_current_shift - bits_per_cycle.U

        cycles_remaining := cycles_remaining - 1.U
        when(cycles_remaining === 1.U) {
            busy := false.B
        }
    }
}
