I am trying to add a MMIO device to rocket-chip in chipyard and I want to use Tilelink interface. This MMIO device is intended to be a slave and the rocket-core as the master. For this, I created a Tilelink Manager Node as the slave node. I want to send a 64-bit value from the core to the slave, then increment the value by 5 a and send back the result to the core.
On the core, I am running this program:
#define MMIO_BASE_ADDR 0x70000000
static inline void reg_write64(unsigned long addr, uint64_t data)
{
volatile uint64_t *ptr = (volatile uint64_t *) addr;
*ptr = data;
}
static inline uint64_t reg_read64(unsigned long addr)
{
volatile uint64_t *ptr = (volatile uint64_t *) addr;
return *ptr;
}
int main() {
uint64_t slave_input_data = 0xDEAD000000000001;
printf("TL MMIO Test\n");
printf("\nTesting Slave Interface:\n");
printf("[CORE] Sending data: 0x%lx\n", slave_input_data);
reg_write64(MMIO_BASE_ADDR , slave_input_data);
printf("[CORE] Issuing GET request...\n");
reg_read64(MMIO_BASE_ADDR , slave_input_data);
return 0;
}
This is how my MMIO device slave node is implemented in chisel:
val slave_node = TLManagerNode(Seq(TLSlavePortParameters.v1(
Seq(TLSlaveParameters.v1(
address = Seq(AddressSet(
0x70000000L,
0x0001ffffL)),
resources = new SimpleDevice("acc-slave", Seq("chip,acc-slave")).reg,
regionType = RegionType.UNCACHED,
supportsGet = TransferSizes(1, 8),
supportsPutFull = TransferSizes(1, 8),
supportsPutPartial = TransferSizes(1, 8),
supportsArithmetic = TransferSizes(1, 8),
supportsLogical = TransferSizes.none,
fifoId = Some(0))), // requests are handled in order
beatBytes = 8)))
And this is the code for the Tilelink protocol:
localparam OP_PUT = 3'b000;
localparam OP_GET = 3'b100;
reg [10:0] temp_source;
reg a_fire;
reg d_fire;
assign a_fire = slave_a_ready && slave_a_valid;
assign d_fire = slave_d_ready && slave_d_valid;
always @(posedge clock) begin
if (reset) begin
state <= IDLE;
accumulator_data <= 64'b0;
slave_a_ready <= 1'b0;
slave_d_valid <= 1'b0;
inflight_request <= 1'b0;
temp_source <= 11'd0;
end else begin
case (state)
IDLE: begin
if (slave_a_valid && slave_a_opcode == OP_PUT) begin
$display("[MMIO] Data 0x%x with OPcode %d Param %d Size %d Source ID %d at address 0x%x time %t", slave_a_data,
slave_a_opcode, slave_a_param, slave_a_size, slave_a_source, slave_a_address, $time);
accumulator_data <= slave_a_data + 5;
slave_a_ready <= 1'b1;
temp_source <= slave_a_source[4:0];
state <= PUT_RESPOND;
end
end
PUT_RESPOND: begin
if (a_fire) begin
$display("[MMIO] PUT response completed: data=0x%x at time %t\n", accumulator_data, $time);
inflight_request <= 1'b1;
slave_a_ready <= 1'b0;
end else if (inflight_request) begin
$display("[MMIO] Request in flight!\n");
slave_d_valid <= 1'b1;
slave_d_opcode <= 3'b000;
slave_d_param <= 3'b000;
slave_d_size <= slave_a_size;
slave_d_source <= temp_sink;
slave_d_sink <= 0;
slave_d_denied <= 1'b0;
slave_d_corrupt <= 1'b0;
end else if (d_fire) begin
$display("[MMIO] D channel RESPONE\n");
state <= IDLE;
slave_d_valid <= 1'b0;
slave_a_ready <= 1'b1;
inflight_request <= 1'b0;
end
end
end
And the output looks like this:
Testing Slave Interface:
[CORE] Sending data: 0xdead000000000001
[MMIO] Data 0xdead000000000001 with OPcode 0 Param 0 Size 3 Source ID 24 at address 0x70000000 time 235275000
[MMIO] PUT response completed: data=0xdead000000000006 at time 235277000
[MMIO] Request in flight!
Assertion failed: 'D' channel acknowledged for nothing inflight (connected at generators/acc/src/main/scala/acc.scala:75:27)
at Monitor.scala:52 assert(cond, message)