-
Notifications
You must be signed in to change notification settings - Fork 1
Traits
Andreas Traber edited this page Aug 22, 2017
·
3 revisions
Similar to Rust, FLUTSCH shall support traits. Traits on interface allow generic implementations of peripherals. An example is a UART peripheral that uses the read and write traits of an interface. Since read and write are very generic, any bus system can implement those traits and thus work without modifications with this UART peripheral. Since there is no adaption layer, but rather it is built into the language, this results in more efficient and smaller hardware.
Example
// 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;
}
}
}
}