-
Notifications
You must be signed in to change notification settings - Fork 1
Transactions
Fabian Schuiki edited this page Aug 22, 2017
·
1 revision
Transactions provide an abstraction that map a combination of signal values and other transactions into a single event that can be triggered or waited upon.
// Define a simple memory bus with request and respond transactions.
struct Bus<'dir> {
clk: in async rise logic,
req_addr: 'dir logic[32],
req_valid: 'dir logic,
req_ready: !'dir logic,
rsp_data: !'dir logic[32],
rsp_valid: !'dir logic,
rsp_ready: 'dir logic,
}
impl Bus {
tran req(addr: logic[32]) {
self.req_valid == '1';
self.req_ready == '1';
self.req_addr == addr;
self.clk.trigger();
}
tran rsp(data: logic[32]) {
self.rsp_valid == '1';
self.rsp_ready == '1';
self.rsp_data == data;
self.clk.trigger();
}
}
// Define a 1024 word ROM that can be accessed via the bus. It is implemented
// with an automaton (`auto`) and can only handle one outstanding request at
// once.
struct Rom {
clk: in async rise logic,
rst: in async low logic,
bus: in Bus,
mem: logic[1024][32],
}
impl Rom {
auto handler {
let data: logic[32];
upon self.rst.trigger() {
data = 0;
goto READY;
}
state READY {
upon self.bus.req(addr) {
data = self.mem[some_conversion(addr)];
goto RESPOND;
}
}
state RESPOND {
self.bus.rsp(data);
goto READY;
}
}
}
// Define a requester that reads from the ROM. It emits two requests in
// sequence, then waits for the two responses. This will deadlock. Can we
// statically catch this?
struct Broken {
clk: in async rise logic,
rst: in async low logic,
bus: out bus,
}
impl Broken {
auto deadbeef {
let addr: uint[32];
upon self.rst.trigger() {
addr = 0;
goto REQ_FIRST;
}
state REQ_FIRST {
addr = addr + 1;
self.bus.req(addr.to_logic());
goto REQ_SECOND;
}
state REQ_SECOND {
addr = addr + 1;
self.bus.req(addr.to_logic());
goto RECV_FIRST;
}
state RECV_FIRST {
upon self.bus.rsp(_) {
goto RECV_SECOND;
}
}
state RECV_SECOND {
upon self.bus.rsp(_) {
goto REQ_FIRST;
}
}
}
}