Livt packages
Livt.Usb
Version 0.0.5
USB 2.0 low/full-speed PHY, host transfers, device discovery, HID keyboard, and read-only mass storage for Livt.
Published files (57)
src/hid/KeyboardEventQueue.lvt
namespace Livt.Usb.Hid
using Livt.IO
/**
* Bounded scheduled single-producer/single-consumer event queue. One arbiter owns
* storage and indices; independent callers may enqueue and dequeue concurrently.
* Defaults to block RAM; substitute a compatible IRam for register/distributed storage.
*/
component KeyboardEventQueue<CAPACITY: int = 32, STYLE: MemoryStyle = MemoryStyle.Block,
B: IRam<logic[18]> & new() = SequentialRam<logic[18], CAPACITY, STYLE>>
{
static assert CAPACITY > 0, "Event queue capacity must be positive"
// Counts include CAPACITY, so full and empty remain distinct.
const COUNT_BITS: int = Bits.RequiredFor(CAPACITY)
// Owned storage and independent request/result mailboxes.
ram: B
pushRequest: bool
pushSeen: bool
pushValue: logic[18]
pushAccepted: bool
popRequest: bool
popSeen: bool
popValue: logic[18]
popAccepted: bool
head: logic[COUNT_BITS]
tail: logic[COUNT_BITS]
count: logic[COUNT_BITS]
/**
* Creates an empty queue; RAM is read only after an accepted write.
*/
new()
{
ram = new B()
}
/**
* Returns false without mutation if the queue is full at arbitration time.
*/
public fn TryEnqueue(value: logic[18]) bool
{
pushValue = value;
pushRequest = !pushRequest
while (pushSeen != pushRequest) {}
return pushAccepted
}
/**
* Returns the oldest event, or false and zero when empty at arbitration time.
*/
public fn TryDequeue(value: out logic[18]) bool
{
popRequest = !popRequest
while (popSeen != popRequest) {}
value = popValue
return popAccepted
}
/**
* Services each pending operation once per turn; neither caller can starve.
*/
process Service()
{
if (popRequest != popSeen) {
popAccepted = count != 0;
popValue = 0
if (popAccepted) {
popValue = ram.Read((head as uint) as int)
head++
if (head == (CAPACITY as logic[COUNT_BITS])) { head = 0 }
count--
}
popSeen = popRequest
}
if (pushRequest != pushSeen) {
pushAccepted = count != (CAPACITY as logic[COUNT_BITS])
if (pushAccepted) {
ram.Write((tail as uint) as int, pushValue)
tail++
if (tail == (CAPACITY as logic[COUNT_BITS])) { tail = 0 }
count++
}
pushSeen = pushRequest
}
}
}