Problem with Tilelink protocol handshake between Rocket Core and a MMIO device

36 views
Skip to first unread message

amoon_ea

unread,
Jun 11, 2025, 10:14:22 AMJun 11
to Chipyard

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)

Could you please tell me what I am doing wrong, or how I am violating the protocol?

Reply all
Reply to author
Forward
0 new messages