Created
December 23, 2024 19:25
-
-
Save zaun/80a4f47645e35f75b8d6a75efea5c56f to your computer and use it in GitHub Desktop.
CPU <--> TileLink-UL interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`timescale 1ns / 1ps | |
`default_nettype none | |
module cpu_mem_interface #( | |
parameter XLEN = 32, // Bus data width | |
parameter SLEN = 2, // Source ID length | |
parameter MAX_RETRIES = 3 // Maximum number of retry attempts | |
) ( | |
input wire clk, | |
input wire reset, | |
// CPU Interface | |
input wire cpu_valid, | |
input wire [XLEN-1:0] cpu_address, | |
input wire [XLEN-1:0] cpu_wdata, | |
input wire [XLEN/8-1:0] cpu_wstrb, | |
input wire [2:0] cpu_size, // 0:byte, 1:halfword, 2:word, 3:doubleword | |
input wire cpu_read, | |
output reg [XLEN-1:0] cpu_rdata, | |
output reg cpu_ready, // Indicates cpu_rdata valid | |
output reg mem_ready, // Indicates memory operation completed when data is stable | |
// TileLink A Channel | |
output reg tl_a_valid, | |
input wire tl_a_ready, | |
output reg [2:0] tl_a_opcode, // Operation type | |
output reg [2:0] tl_a_param, // Parameters for operation | |
output reg [2:0] tl_a_size, // Log2(Bytes per beat) | |
output wire [SLEN-1:0] tl_a_source, // Source ID | |
output reg [XLEN-1:0] tl_a_address, // Address | |
output reg [XLEN/8-1:0] tl_a_mask, // Write byte mask | |
output reg [XLEN-1:0] tl_a_data, // Data for write ops | |
// TileLink D Channel | |
input wire tl_d_valid, | |
output reg tl_d_ready, | |
input wire [2:0] tl_d_opcode, // Response type | |
input wire [1:0] tl_d_param, // Response params | |
input wire [2:0] tl_d_size, | |
input wire [SLEN-1:0] tl_d_source, | |
input wire [XLEN-1:0] tl_d_data, | |
input wire tl_d_corrupt, | |
input wire tl_d_denied, | |
// Non-Maskable IRQs (Edge-Triggered) | |
output reg nmi_denied, | |
output reg nmi_corrupt | |
); | |
// Local parameters for TileLink opcodes | |
localparam GET_OPCODE = 3'b100; // Get (Read) | |
localparam PUT_FULL_DATA_OPCODE = 3'b000; // PutFullData (Write) | |
localparam DEFAULT_PARAM = 3'b000; // Default TL param | |
// FSM States | |
typedef enum logic [2:0] { | |
IDLE, | |
SEND_REQ, | |
WAIT_RESP, | |
WRITE_RDATA, | |
COMPLETE | |
} state_t; | |
state_t current_state, next_state; | |
// Registers to hold CPU request data | |
reg [XLEN-1:0] req_address; | |
reg [XLEN-1:0] req_wdata; | |
reg [7:0] req_wstrb; | |
reg [2:0] req_size; | |
reg req_read; | |
// Retry mechanism | |
reg [1:0] retry_count; | |
// NMI states | |
reg do_nmi_retry_max; | |
reg do_nmi_denied; | |
reg do_nmi_corrupt; | |
// Read data hold | |
reg [XLEN-1:0] read_data_hold; | |
// Assign fixed source ID since only one request is handled at a time | |
assign tl_a_source = {SLEN{1'b0}}; | |
// Initialize all registers on reset | |
always_ff @(posedge clk or posedge reset) begin | |
if (reset) begin | |
current_state <= IDLE; | |
tl_a_valid <= 1'b0; | |
tl_a_opcode <= 3'b000; | |
tl_a_param <= 3'b000; | |
tl_a_size <= 3'b000; | |
tl_a_address <= {XLEN{1'b0}}; | |
tl_a_mask <= 8'h00; | |
tl_a_data <= {XLEN{1'b0}}; | |
tl_d_ready <= 1'b0; | |
cpu_rdata <= {XLEN{1'b0}}; | |
cpu_ready <= 1'b0; | |
mem_ready <= 1'b0; | |
retry_count <= 2'd0; | |
do_nmi_retry_max <= 1'b0; | |
do_nmi_denied <= 1'b0; | |
do_nmi_corrupt <= 1'b0; | |
nmi_denied <= 1'b0; | |
nmi_corrupt <= 1'b0; | |
read_data_hold <= {XLEN{1'b0}}; | |
end else begin | |
// Default assignments | |
tl_a_valid <= 1'b0; | |
tl_d_ready <= 1'b0; | |
cpu_ready <= 1'b0; | |
mem_ready <= 1'b0; | |
do_nmi_retry_max <= 1'b0; | |
do_nmi_denied <= 1'b0; | |
do_nmi_corrupt <= 1'b0; | |
case (current_state) | |
IDLE: begin | |
if (cpu_valid) begin | |
// Capture CPU request | |
req_address <= cpu_address; | |
req_wdata <= cpu_wdata; | |
req_wstrb <= cpu_wstrb; | |
req_size <= cpu_size; | |
req_read <= cpu_read; | |
// Prepare TileLink A Channel signals | |
tl_a_opcode <= cpu_read ? GET_OPCODE : PUT_FULL_DATA_OPCODE; | |
tl_a_param <= DEFAULT_PARAM; | |
tl_a_size <= cpu_size; | |
tl_a_address <= cpu_address; | |
tl_a_mask <= cpu_wstrb; | |
tl_a_data <= cpu_wdata; | |
tl_a_valid <= 1'b1; | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Captured CPU request - Read: %0d, Address: 0x%h, Size: %0d", | |
$time, cpu_read, cpu_address, cpu_size); `endif | |
if (tl_a_ready) begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: TileLink A Channel ready, transitioning to WAIT_RESP", $time); `endif | |
next_state <= WAIT_RESP; | |
end else begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: TileLink A Channel not ready, transitioning to SEND_REQ", $time); `endif | |
next_state <= SEND_REQ; | |
end | |
end else begin | |
next_state <= IDLE; | |
end | |
end | |
SEND_REQ: begin | |
// Resend TileLink A Channel request until tl_a_ready is asserted | |
tl_a_valid <= 1'b1; | |
tl_a_opcode <= req_read ? GET_OPCODE : PUT_FULL_DATA_OPCODE; | |
tl_a_param <= DEFAULT_PARAM; | |
tl_a_size <= req_size; | |
tl_a_address <= req_address; | |
tl_a_mask <= req_wstrb; | |
tl_a_data <= req_wdata; | |
`ifdef LOG | |
$display("[cpu_mem_interface] Time %0t: Sending TileLink A Channel PUT_FULL_DATA request - Address: 0x%h, Data: 0x%h, Mask: 0x%h", | |
$time, req_read, req_address, req_wstrb); | |
`endif | |
if (tl_a_ready) begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: TileLink A Channel accepted, transitioning to WAIT_RESP", $time); `endif | |
next_state <= WAIT_RESP; | |
end else if (retry_count < MAX_RETRIES) begin | |
retry_count <= retry_count + 1; | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: TileLink A Channel not ready, retrying (%0d/%0d)", | |
$time, retry_count, MAX_RETRIES); `endif | |
next_state <= SEND_REQ; | |
end else begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: TileLink A Channel failed after max retries, transitioning to WRITE_RDATA", $time); `endif | |
do_nmi_retry_max <= 1'b1; | |
// mem_ready <= 1'b1; | |
// cpu_ready <= 1'b1; | |
read_data_hold <= {XLEN{1'b0}}; | |
next_state <= WRITE_RDATA; | |
end | |
end | |
WAIT_RESP: begin | |
if (tl_d_valid) begin | |
// Acknowledge the response | |
tl_d_ready <= 1'b1; | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Received TileLink D Channel response - Opcode: %0b, Data: 0x%h", | |
$time, tl_d_opcode, tl_d_data); `endif | |
if (tl_d_denied || tl_d_corrupt) begin | |
if (retry_count < MAX_RETRIES) begin | |
retry_count <= retry_count + 1; | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Response denied/corrupt, retrying (%0d/%0d)", | |
$time, retry_count, MAX_RETRIES); `endif | |
next_state <= SEND_REQ; | |
end else begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Response denied/corrupt after max retries, transitioning to WRITE_RDATA", $time); `endif | |
read_data_hold <= {XLEN{1'b0}}; | |
if (tl_d_denied) do_nmi_denied <= 1'b1; | |
if (tl_d_corrupt) do_nmi_corrupt <= 1'b1; | |
next_state <= WRITE_RDATA; | |
end | |
end else begin | |
// Successful response | |
if (req_read) begin | |
case (req_size) | |
3'b000: read_data_hold <= { {(XLEN-8){1'b0}}, tl_d_data[7:0] }; | |
3'b001: read_data_hold <= { {(XLEN-16){1'b0}}, tl_d_data[7:0], tl_d_data[15:8] }; | |
3'b010: read_data_hold <= { {(XLEN-32){1'b0}}, tl_d_data[7:0], tl_d_data[15:8], tl_d_data[23:16], tl_d_data[31:24] }; | |
3'b011: read_data_hold <= { tl_d_data[7:0], tl_d_data[15:8], tl_d_data[23:16], tl_d_data[31:24], | |
tl_d_data[39:32], tl_d_data[47:40], tl_d_data[55:48], tl_d_data[63:56] }; | |
default: read_data_hold <= {XLEN{1'b0}}; // For simplicity, handle only up to word | |
endcase | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Read data received - 0x%h", $time, tl_d_data); `endif | |
end else begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Write operation acknowledged", $time); `endif | |
end | |
retry_count <= 2'd0; | |
next_state <= WRITE_RDATA; | |
end | |
end else begin | |
// Waiting for D Channel response | |
next_state <= WAIT_RESP; | |
end | |
end | |
WRITE_RDATA: begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Assigning read data to CPU - 0x%h nmi_denied=%0d nmi_corrupt=%0d", $time, read_data_hold, do_nmi_denied || do_nmi_retry_max, do_nmi_corrupt); `endif | |
if (req_read) begin | |
cpu_rdata <= read_data_hold; | |
end else begin | |
cpu_rdata <= {XLEN{1'b0}}; | |
end | |
if (do_nmi_denied || do_nmi_retry_max) nmi_denied <= 1'b1; | |
if (do_nmi_corrupt) nmi_corrupt <= 1'b1; | |
next_state <= COMPLETE; | |
end | |
COMPLETE: begin | |
`ifdef LOG $display("[cpu_mem_interface] Time %0t: Memory operation complete, ready signals asserted", $time); `endif | |
cpu_ready <= 1'b1; | |
mem_ready <= 1'b1; | |
nmi_denied <= 1'b0; | |
nmi_corrupt <= 1'b0; | |
do_nmi_retry_max <= 1'b0; | |
do_nmi_denied <= 1'b0; | |
do_nmi_corrupt <= 1'b0; | |
next_state <= IDLE; | |
end | |
default: begin | |
next_state <= IDLE; | |
end | |
endcase | |
end | |
end | |
// FSM State Transition | |
always_ff @(posedge clk or posedge reset) begin | |
if (reset) begin | |
current_state <= IDLE; | |
end else begin | |
current_state <= next_state; | |
end | |
end | |
endmodule |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`timescale 1ns / 1ps | |
`default_nettype none | |
module mock_memory #( | |
parameter XLEN = 32, | |
parameter SLEN = 2, | |
parameter MEM_SIZE = 2048 | |
) ( | |
input wire clk, | |
input wire reset, | |
// TileLink A Channel | |
input wire tl_a_valid, | |
output reg tl_a_ready, | |
input wire [2:0] tl_a_opcode, | |
input wire [2:0] tl_a_param, | |
input wire [2:0] tl_a_size, | |
input wire [SLEN-1:0] tl_a_source, | |
input wire [XLEN-1:0] tl_a_address, | |
input wire [XLEN/8-1:0] tl_a_mask, | |
input wire [XLEN-1:0] tl_a_data, | |
// TileLink D Channel | |
output reg tl_d_valid, | |
input wire tl_d_ready, | |
output reg [2:0] tl_d_opcode, | |
output reg [1:0] tl_d_param, | |
output reg [2:0] tl_d_size, | |
output reg [SLEN-1:0] tl_d_source, | |
output reg [XLEN-1:0] tl_d_data, | |
output reg tl_d_corrupt, | |
output reg tl_d_denied | |
`ifdef DEBUG | |
// Debug inputs | |
,input wire dbg_wait | |
,input wire [XLEN-1:0] dbg_corrupt_read_address | |
,input wire [XLEN-1:0] dbg_denied_read_address | |
,input wire [XLEN-1:0] dbg_corrupt_write_address | |
,input wire [XLEN-1:0] dbg_denied_write_address | |
`endif | |
); | |
// Memory array | |
reg [7:0] memory [0:MEM_SIZE-1]; | |
initial begin | |
integer i; | |
for (i=0; i<MEM_SIZE; i=i+1) begin | |
memory[i] = 8'h00; | |
end | |
@(posedge clk); | |
end | |
// Local parameters | |
localparam [2:0] TL_ACCESS_ACK = 3'b000; | |
localparam [2:0] TL_ACCESS_ACK_DATA = 3'b010; | |
localparam [2:0] PUT_FULL_DATA_OPCODE = 3'b000; | |
localparam [2:0] GET_OPCODE = 3'b100; | |
localparam [2:0] TL_ACCESS_ACK_DATA_CORRUPT = 3'b101; | |
localparam [2:0] TL_ACCESS_ACK_ERROR = 3'b111; | |
// States | |
typedef enum logic [1:0] { | |
IDLE, | |
WAIT_CYCLE, | |
RESPOND | |
} mem_state_t; | |
mem_state_t state; | |
// Registers to hold request info | |
reg [XLEN-1:0] req_address; | |
reg [2:0] req_size; | |
reg req_read; | |
reg [SLEN-1:0] req_source; | |
reg [XLEN/8-1:0] req_wstrb; | |
reg [XLEN-1:0] req_wdata; | |
// Registers to hold computed response data before asserting tl_d_valid | |
reg [XLEN-1:0] resp_data; | |
reg [2:0] resp_opcode; | |
reg [1:0] resp_param; | |
reg [2:0] resp_size; | |
reg [SLEN-1:0] resp_source; | |
reg resp_denied; | |
reg resp_corrupt; | |
// Capture A-Channel request | |
always @(posedge clk or posedge reset) begin | |
if (reset) begin | |
state <= IDLE; | |
tl_a_ready <= 1'b0; | |
tl_d_valid <= 1'b0; | |
tl_d_opcode <= 3'b000; | |
tl_d_param <= 2'b00; | |
tl_d_size <= 3'b000; | |
tl_d_source <= {SLEN{1'b0}}; | |
tl_d_data <= {XLEN{1'b0}}; | |
tl_d_corrupt <= 1'b0; | |
tl_d_denied <= 1'b0; | |
`ifdef DEBUG | |
end else if (dbg_wait == 1) begin | |
// Do nothing | |
`endif | |
end else begin | |
// Defaults | |
tl_a_ready <= (state == IDLE); | |
tl_d_valid <= (state == RESPOND); | |
case (state) | |
IDLE: begin | |
if (tl_a_valid && tl_a_ready) begin | |
// Capture request | |
req_address <= tl_a_address; | |
req_size <= tl_a_size; | |
req_read <= (tl_a_opcode == GET_OPCODE); | |
req_source <= tl_a_source; | |
req_wstrb <= tl_a_mask; | |
req_wdata <= tl_a_data; | |
`ifdef LOG $display("[mock_memory] time %0t: IDLE tl_a_address=%0h", $time, tl_a_address); `endif | |
state <= WAIT_CYCLE; | |
end | |
end | |
WAIT_CYCLE: begin | |
// Initialize response flags | |
resp_denied = 1'b0; | |
resp_corrupt = 1'b0; | |
resp_param = 2'b00; | |
resp_source = req_source; | |
// Check for debug conditions | |
`ifdef DEBUG | |
if (req_read) begin | |
// For read requests | |
if (req_address == dbg_corrupt_read_address) begin | |
resp_corrupt = 1'b1; | |
`ifdef LOG $display("[mock_memory] Corrupt read at address %h", req_address); `endif | |
end | |
if (req_address == dbg_denied_read_address) begin | |
resp_denied = 1'b1; | |
`ifdef LOG $display("[mock_memory] Denied read at address %h", req_address); `endif | |
end | |
end else begin | |
// For write requests | |
if (req_address == dbg_corrupt_write_address) begin | |
resp_corrupt = 1'b1; | |
`ifdef LOG $display("[mock_memory] Corrupt write at address %h", req_address); `endif | |
end | |
if (req_address == dbg_denied_write_address) begin | |
resp_denied = 1'b1; | |
`ifdef LOG $display("[mock_memory] Denied write at address %h", req_address); `endif | |
end | |
end | |
`endif | |
// If denied or corrupted, set response accordingly | |
if (resp_denied) begin | |
resp_opcode = TL_ACCESS_ACK_ERROR; | |
resp_data = {XLEN{1'b0}}; | |
end else if (resp_corrupt) begin | |
resp_opcode = TL_ACCESS_ACK_DATA_CORRUPT; | |
// Optionally, set resp_data to a corrupted value | |
// For demonstration, flipping the LSB | |
resp_data = req_read ? resp_data ^ 32'h00000001 : {XLEN{1'b1}}; | |
end else begin | |
// Handle normal read or write | |
if (req_read) begin | |
// Handle read | |
case (req_size) | |
3'b000: begin | |
// Byte | |
resp_data = {{(XLEN-8){1'b0}}, memory[req_address]}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
3'b001: begin | |
// Halfword | |
resp_data = {{(XLEN-16){1'b0}}, memory[req_address], memory[req_address + 1]}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
3'b010: begin | |
// Word | |
resp_data = {{(XLEN-32){1'b0}}, memory[req_address], memory[req_address + 1], memory[req_address + 2], memory[req_address + 3]}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
3'b011: begin | |
// Double-word | |
if (XLEN >= 64) begin | |
resp_data = {memory[req_address], memory[req_address + 1], | |
memory[req_address + 2], memory[req_address + 3], | |
memory[req_address + 4], memory[req_address + 5], | |
memory[req_address + 6], memory[req_address + 7]}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end else begin | |
resp_data = {(XLEN){1'b0}}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
end | |
3'b100: if (XLEN >= 128) begin | |
resp_data = {memory[req_address], memory[req_address + 1], | |
memory[req_address + 2], memory[req_address + 3], | |
memory[req_address + 4], memory[req_address + 5], | |
memory[req_address + 6], memory[req_address + 7], | |
memory[req_address + 8], memory[req_address + 9], | |
memory[req_address + 10], memory[req_address + 11], | |
memory[req_address + 12], memory[req_address + 13], | |
memory[req_address + 14], memory[req_address + 15]}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
default: begin | |
resp_data = {(XLEN){1'b0}}; | |
resp_opcode = TL_ACCESS_ACK_DATA; | |
end | |
endcase | |
`ifdef LOG $display("[mock_memory] Time %0t: /WAIT_CYCLE/ READ req_address=%0h, resp_data=%0h", $time, req_address, resp_data); `endif | |
end else begin | |
// Handle write operations based on store size | |
case (req_size) | |
3'b000: begin // Store Byte (SB) | |
if (req_wstrb[0] || req_wstrb[1] || req_wstrb[2] || req_wstrb[3]) begin | |
memory[req_address] <= req_wdata[7:0]; | |
end else if ((req_wstrb[0] + req_wstrb[1] + req_wstrb[2] + req_wstrb[3]) != 0) begin | |
resp_denied = 1'b1; | |
end | |
if (XLEN >=64 ) begin | |
if (req_wstrb[4] || req_wstrb[5] || req_wstrb[6] || req_wstrb[7]) begin | |
memory[req_address] <= req_wdata[7:0]; | |
end else if ((req_wstrb[4] + req_wstrb[5] + req_wstrb[6] + req_wstrb[7]) != 0) begin | |
resp_denied = 1'b1; | |
end | |
end | |
end | |
3'b001: begin // Store Half-Word (SH) | |
if ((req_wstrb[0] && req_wstrb[1]) || (req_wstrb[2] && req_wstrb[3])) begin | |
memory[req_address + 0] <= req_wdata[7:0]; | |
memory[req_address + 1] <= req_wdata[15:8]; | |
end else if (req_wstrb[0] || req_wstrb[1] || req_wstrb[2] || req_wstrb[3]) begin | |
resp_denied = 1'b1; | |
end | |
if (XLEN >=64 ) begin | |
if ((req_wstrb[4] && req_wstrb[5]) || (req_wstrb[6] && req_wstrb[7])) begin | |
memory[req_address + 0] <= req_wdata[7:0]; | |
memory[req_address + 1] <= req_wdata[15:8]; | |
end else if (req_wstrb[4] || req_wstrb[5] || req_wstrb[6] || req_wstrb[7]) begin | |
resp_denied = 1'b1; | |
end | |
end | |
end | |
3'b010: begin // Store Word (SW) | |
// Check each bit of mem_wstrb and write the word data accordingly | |
if (req_wstrb[0]) begin | |
memory[req_address + 0] <= req_wdata[7:0]; | |
end | |
if (req_wstrb[1]) begin | |
memory[req_address + 1] <= req_wdata[15:8]; | |
end | |
if (req_wstrb[2]) begin | |
memory[req_address + 2] <= req_wdata[23:16]; | |
end | |
if (req_wstrb[3]) begin | |
memory[req_address + 3] <= req_wdata[31:24]; | |
end | |
// if (req_wstrb[4]) begin | |
// memory[req_address + 0] <= req_wdata[7:0]; | |
// end | |
// if (req_wstrb[5]) begin | |
// memory[req_address + 1] <= req_wdata[15:8]; | |
// end | |
// if (req_wstrb[6]) begin | |
// memory[req_address + 2] <= req_wdata[23:16]; | |
// end | |
// if (req_wstrb[7]) begin | |
// memory[req_address + 3] <= req_wdata[31:24]; | |
// end | |
end | |
3'b011: begin // Store Double-Word (SD) - 8 bytes | |
// Check each bit of mem_wstrb and write the word data accordingly | |
// $display("%00d-bit: SD mask=%00b address=%00h data=%00h", XLEN, req_wstrb, req_address, req_wdata); | |
if (req_wstrb[0]) begin | |
memory[req_address + 0] <= req_wdata[7:0]; | |
end | |
if (req_wstrb[1]) begin | |
memory[req_address + 1] <= req_wdata[15:8]; | |
end | |
if (req_wstrb[2]) begin | |
memory[req_address + 2] <= req_wdata[23:16]; | |
end | |
if (req_wstrb[3]) begin | |
memory[req_address + 3] <= req_wdata[31:24]; | |
end | |
if (req_wstrb[4]) begin | |
memory[req_address + 4] <= req_wdata[39:32]; | |
end | |
if (req_wstrb[5]) begin | |
memory[req_address + 5] <= req_wdata[47:40]; | |
end | |
if (req_wstrb[6]) begin | |
memory[req_address + 6] <= req_wdata[55:48]; | |
end | |
if (req_wstrb[7]) begin | |
memory[req_address + 7] <= req_wdata[63:56]; | |
end | |
end | |
default: begin | |
end | |
endcase | |
`ifdef LOG $display("[mock_memory] Time %0t: /WAIT_CYCLE/ WRITE req_address=%0h, req_wdata=%0h", $time, req_address, req_wdata); `endif | |
resp_opcode = TL_ACCESS_ACK; | |
resp_data = {XLEN{1'b0}}; | |
end | |
end | |
// Assign response signals | |
tl_d_opcode <= resp_opcode; | |
tl_d_param <= resp_param; | |
tl_d_size <= req_size; | |
tl_d_source <= resp_source; | |
tl_d_data <= resp_data; | |
tl_d_corrupt <= resp_corrupt; | |
tl_d_denied <= resp_denied; | |
`ifdef LOG $display("[mock_memory] Time %0t: /WAIT_CYCLE/ Computed resp_data=0x%08h resp_opcode=%0b", | |
$time, resp_data, resp_opcode); `endif | |
state <= RESPOND; | |
end | |
RESPOND: begin | |
// tl_d_valid is 1 here, wait for tl_d_ready handshake | |
if (tl_d_valid && tl_d_ready) begin | |
// Handshake done, go back to IDLE | |
tl_d_opcode <= 3'b000; | |
tl_d_param <= 2'b00; | |
tl_d_size <= 3'b000; | |
tl_d_source <= {SLEN{1'b0}}; | |
tl_d_data <= {XLEN{1'b0}}; | |
tl_d_corrupt <= 1'b0; | |
tl_d_denied <= 1'b0; | |
state <= IDLE; | |
end | |
end | |
default: state <= IDLE; | |
endcase | |
end | |
end | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment