Skip to content

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;
			}
		}
	}
}

Clone this wiki locally