Livt packages

Eccelerators.RiscV

Version 0.3.0

Composable RV32I and Zmmul processors, machine-mode support, and reusable FPGA system components written in Livt.

Published files (120)

src/Sequential/Rv32IterativeMultiplier.lvt

namespace Eccelerators.RiscV.Sequential

/**
 * Radix-two 32-bit multiplier with 32 iterations and two high-half correction
 * edges. Owns a shared 32-bit add/subtract datapath with explicit carry; no multiply operator or
 * scheduled calls. All operations have identical latency. Hardware reset clears
 * phase/completion and cancels work; operands are sampled only at acceptance.
 */
component Rv32IterativeMultiplier : IRv32MultiplyPort
{
	// Concrete operation coverage for composition checks.
	public const CAPABILITIES: uint = Rv32MultiplyOperations.CAPABILITY

	// Fixed protocol phases and iteration bound.
	const IDLE: uint = 0
	const ITERATE: uint = 1
	const CORRECT_LEFT: uint = 2
	const CORRECT_RIGHT: uint = 3
	const COMPLETE: uint = 4
	const LAST_BIT: uint = 31

	// Owned operand/product state; the low half also holds unprocessed multiplier bits.
	phase: logic[3]
	bitIndex: logic[5]
	multiplicand: logic[32]
	originalRight: logic[32]
	high: logic[32]
	low: logic[32]
	selectedOperation: logic[2]

	// Combinational arithmetic shared by iterations and signed high-half corrections.
	addend: logic[32]
	subtract: bool
	sum: uint
	carryOut: uint

	/**
	 * Selects the adder inputs; subtraction uses complement plus carry-in.
	 */
	process Calculate[]()
	{
		addend = 0
		subtract = false

		if (phase as uint == ITERATE && (low as uint & 1) != 0) {
			addend = multiplicand
		} elif (phase as uint == CORRECT_LEFT
			&& (selectedOperation as uint == Rv32MultiplyOperations.MULH
			|| selectedOperation as uint == Rv32MultiplyOperations.MULHSU)
			&& (multiplicand as uint >> 31) != 0) {
			addend = originalRight
			subtract = true
		} elif (phase as uint == CORRECT_RIGHT
			&& selectedOperation as uint == Rv32MultiplyOperations.MULH
			&& (originalRight as uint >> 31) != 0) {
			addend = multiplicand
			subtract = true
		}

		var operand = addend as uint
		var carry: uint = 0

		if (subtract) {
			operand = ~(addend as uint)
			carry = 1
		}

		sum = (high as uint) + operand + carry
		carryOut = 0

		if (sum < high as uint) {
			carryOut = 1
		}

		ready = 0b0
		result = high

		if (selectedOperation as uint == Rv32MultiplyOperations.MUL) {
			result = low
		}

		if (phase as uint == COMPLETE) {
			ready = 0b1
		}
	}

	/**
	 * Samples one transaction, iterates, corrects and holds completion until release.
	 */
	process Advance()
	{
		state {
			match (phase as uint)
			{
				IDLE =>
				{
					if (request == 0b1) {
						multiplicand = left
						originalRight = right
						low = right
						high = 0
						selectedOperation = operation
						bitIndex = 0
						phase = ITERATE as logic[3]
					}
				}
				ITERATE =>
				{
					low = ((low as uint >> 1) | ((sum as uint & 1) << 31)) as logic[32]
					high = ((sum >> 1) | (carryOut << 31)) as logic[32]

					if (bitIndex as uint == LAST_BIT) {
						phase = CORRECT_LEFT as logic[3]
					} else {
						bitIndex = (bitIndex as uint + 1) as logic[5]
					}
				}
				CORRECT_LEFT =>
				{
					high = sum as logic[32]
					phase = CORRECT_RIGHT as logic[3]
				}
				CORRECT_RIGHT =>
				{
					high = sum as logic[32]
					phase = COMPLETE as logic[3]
				}
				_ =>
				{
					if (request == 0b0) {
						phase = IDLE as logic[3]
					}
				}
			}
		}
	}
}