Livt packages

Livt.IO

Version 1.8.1

Memory, UART, I2C, SPI, and Ethernet input/output components for Livt hardware designs.

Published files (126)

tests/spi/SPIFlashTest.lvt

namespace Livt.IO.Tests

using Livt.IO

/**
 * Verifies command sequencing, range rejection and context-timed busy handling.
 */
@Test
@Context(ClockFrequency = 50MHz)
component SPIFlashTest
{
	// Owned deterministic transport and production flash command engine.
	transport: SPIFlashTestTransport
	flash: SPIFlash<SPIFlashTestTransport, 1048576, 256, 4096, 0x20, 20us>

	/**
	 * Constructs the command engine in a 50 MHz test context.
	 */
	new()
	{
		transport = new SPIFlashTestTransport()
		flash = new SPIFlash<SPIFlashTestTransport, 1048576, 256, 4096, 0x20, 20us>(transport)
	}

	/**
	 * Reads sequential bytes with a big-endian 24-bit address across a page boundary.
	 */
	@Test
	fn ReadsAcrossPageBoundary()
	{
		transport.Reset()
		assert flash.Read(0x0123FE, 4)
		assert transport.GetCapturedByte(1) == 0x01
		assert transport.GetCapturedByte(2) == 0x23
		assert transport.GetCapturedByte(3) == 0xFE
		assert flash.GetByte(0) == 0x00
		assert flash.GetByte(3) == 0x03
		assert !transport.selected
	}

	/**
	 * Checks WREN and staging byte order for a partial page.
	 */
	@Test
	fn ProgramsPageFragment()
	{
		transport.Reset()
		assert flash.SetByte(0, 0xAB)
		assert flash.SetByte(1, 0xCD)
		assert flash.ProgramPage(254, 2)
		assert transport.lastCommand == 0x02
		assert transport.capturedLength == 6
		assert transport.GetCapturedByte(3) == 0xFE
		assert transport.GetCapturedByte(4) == 0xAB
		assert transport.GetCapturedByte(5) == 0xCD
		assert !transport.selected
	}

	/**
	 * Invalid ranges never start a bus transaction or wrap a page.
	 */
	@Test
	fn RejectsInvalidRangesWithoutBusAccess()
	{
		transport.Reset()
		assert !flash.ProgramPage(255, 2)
		assert !flash.Read(-1, 1)
		assert !flash.Read(1048576, 1)
		assert !flash.Read(0, 257)
		assert !flash.Read(0, 0)
		assert !flash.EraseSector(1)
		assert !flash.EraseSector(1048576)
		assert transport.selections == 0
		assert !flash.SetByte(256, 0x01)
		assert flash.GetByte(-1) == 0x00
	}

	/**
	 * Erases an aligned sector with exactly three address bytes.
	 */
	@Test
	fn ErasesOneSector()
	{
		transport.Reset()
		assert flash.EraseSector(4096)
		assert transport.lastCommand == 0x20
		assert transport.capturedLength == 4
		assert transport.GetCapturedByte(2) == 0x10
		assert !transport.selected
	}

	/**
	 * A rejected WREN cannot issue a page-program command.
	 */
	@Test
	fn RejectsDisabledWrites()
	{
		transport.Reset()
		transport.rejectWrites = true
		assert !flash.ProgramPage(0, 1)
		assert transport.lastCommand == 0x00
		assert !transport.selected
	}

	/**
	 * A stuck busy flag returns failure and leaves chip select released.
	 */
	@Test
	fn TimesOutBusyDevice()
	{
		transport.Reset()
		transport.busy = true
		assert !flash.Read(0, 1)
		assert transport.selections > 1
		assert !transport.selected
	}
	/**
	 * Identity is read in manufacturer/type/capacity order without write enable.
	 */
	@Test
	fn ReadsJedecIdentity()
	{
		transport.Reset()
		assert flash.ReadJedecId() == 0xEF4017
		assert transport.selections == 1
		assert !transport.selected
		assert transport.capturedLength == 0
	}

}