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/Platform/RvUartDevice.lvt

namespace Eccelerators.RiscV.Platform

using Eccelerators.RiscV.Sequential
using Livt.IO

/**
 * Load/store adapter borrowing a buffered UART in the same clock/reset domain.
 * Registers are aligned words: TX at BASE, status at BASE+4, RX at BASE+8.
 * Status bits are TX space (0), RX available (1), sticky receive error (2).
 * TX writes use lane zero; other enabled lanes fault before effects. A zero
 * mask is a no-op. RX reads consume at most one byte and return zero if empty.
 * TX reads and writes to status/RX fault. Requests and responses remain stable
 * until the caller releases request. A full TX FIFO backpressures a store.
 * The owner may use the UART directly only while this adapter is quiescent.
 */
component RvUartDevice<BASE: uint = 0x40000000> : IRv32LoadStorePort
{
	static assert (BASE & 3) == 0 && BASE <= 0xfffffff4, "UART window must be aligned and must not wrap"

	// Borrowed scheduled transport; this adapter serializes all CPU side effects.
	uart: IBufferedUart

	/**
	 * Borrows an already constructed UART; pins and FIFO sizes remain its owner's choice.
	 */
	new(uart: IBufferedUart)
	{
		this.uart = uart
	}

	/**
	 * Accepts one stable request, performs its effect once, then holds completion.
	 */
	process Serve()
	{
		while (request == 0b0) {
			state {
			}
		}

		var location: uint = 0
		var store: bool = false
		var lanes: logic[4] = 0
		var payload: byte = 0
		state {
			location = address as uint
			store = write == 0b1
			lanes = byteEnable
			payload = writeData as byte
			error = 0b0
			readData = 0
		}

		if (location < BASE || location - BASE >= 12 || (location & 3) != 0) {
			error = 0b1
		} elif (store) {
			if (location != BASE || (lanes & 0b1110) != 0) {
				error = 0b1
			} elif (lanes == 0b0001) {
				while (!uart.TryTransmit(payload)) {
					state {
					}
				}
			}
		} elif (location == BASE + 4) {
			var status: uint = 0
			if (uart.GetTransmitSpace() > 0) {
				status = status | 1
			}
			if (uart.GetReceiveCount() > 0) {
				status = status | 2
			}
			if (uart.GetFrameErrorCount() > 0 || uart.GetReceiveOverflowCount() > 0) {
				status = status | 4
			}
			readData = status as logic[32]
		} elif (location == BASE + 8) {
			var received: byte = 0
			uart.TryReceive(received)
			readData = received as logic[32]
		} else {
			error = 0b1
		}

		state {
			ready = 0b1
		}
		while (request == 0b1) {
			state {
			}
		}
		state {
			ready = 0b0
			error = 0b0
		}
	}
}