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)

tests/RvMachineSystemTest.lvt

namespace Eccelerators.RiscV.Tests

using Eccelerators.RiscV.System
using Eccelerators.RiscV.Storage
using Eccelerators.RiscV.Presets

/** Tests the machine wrapper's interrupt, trap, step and return boundary. */
@Test
component RvMachineSystemTest
{
	// Explicit providers and a machine pipeline with forwarded pending inputs.
	fetch: RvFetchRom<16, 4>
	data: RvLoadStoreRam<16, 4>
	system: RvMachineSystem<Rv32iZmmulPipelineMachineCore>
	trapCount: uint
	lastCause: logic[32]

	/** Constructs the same public assembly used by an interrupt-capable platform. */
	new()
	{
		fetch = new RvFetchRom<16, 4>()
		data = new RvLoadStoreRam<16, 4>()
		system = new RvMachineSystem<Rv32iZmmulPipelineMachineCore>(fetch, data)
	}

	/** Captures trap pulses independently of scheduled test execution. */
	process Observe()
	{
		state {
			if (system.trapped == 0b1) {
				trapCount++
				lastCause = system.trapCause
			}
		}
	}

	/** Provisions an instruction while the core is paused and drained. */
	fn Load(index: uint, word: uint)
	{
		state {
			fetch.programWrite = 0b1
			fetch.programIndex = index as logic[4]
			fetch.programData = word as logic[32]
		}
		state {
			fetch.programWrite = 0b0
		}
	}

	/** Completes one bounded instruction attempt or accepted interrupt. */
	fn Step()
	{
		var ticket = ~system.stepAck
		state {
			system.stepRequest = ticket
		}
		var elapsed: uint = 0
		while (system.stepAck != ticket && elapsed < 300) {
			state {
				elapsed++
			}
		}
		assert system.stepAck == ticket && system.idle == 0b1
	}

	/** Both timer and external levels enter the handler and return precisely. */
	@Test
	fn TestInterruptInputs()
	{
		state {
			system.run = 0b0
			system.timerPending = 0b0
			system.externalPending = 0b0
		}
		Simulation.Wait(150)
		assert system.idle == 0b1
		Load(0, 0x03000093) // ADDI x1,x0,48
		Load(1, 0x30509073) // CSRRW x0,mtvec,x1
		Load(2, 0x000010b7) // LUI x1,1
		Load(3, 0x88008093) // ADDI x1,x1,-1920: timer and external enable bits
		Load(4, 0x3040a073) // CSRRS x0,mie,x1
		Load(5, 0x00800093) // ADDI x1,x0,8
		Load(6, 0x3000a073) // CSRRS x0,mstatus,x1
		Load(7, 0x0000006f) // JAL x0,0
		Load(12, 0x00700293) // ADDI x5,x0,7
		Load(13, 0x30200073) // MRET
		for (var index = 0; index < 7; index++) {
			Step()
		}
		assert system.pc == 28
		state {
			system.timerPending = 0b1
		}
		Simulation.Wait(4)
		Step()
		assert system.pc == 48 && system.halted == 0b0
		assert trapCount == 1 && lastCause == 0x80000007
		state {
			system.timerPending = 0b0
		}
		Step()
		Step()
		assert system.pc == 28
		state {
			system.externalPending = 0b1
		}
		Simulation.Wait(4)
		Step()
		assert system.pc == 48 && system.halted == 0b0
		assert trapCount == 2 && lastCause == 0x8000000b
		state {
			system.externalPending = 0b0
		}
		Step()
		Step()
		assert system.pc == 28
	}
}