-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmulti_port_example.sv
More file actions
266 lines (228 loc) · 8.9 KB
/
multi_port_example.sv
File metadata and controls
266 lines (228 loc) · 8.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/**
* NeoRAM Multi-Port Usage Example (Updated for v1.3.0)
*
* This example demonstrates how to use the NeoRAM controller in a
* dual-port configuration with round-robin arbitration and proper
* ready signal handling. Suitable for cache or shared memory systems.
*/
module neoram_multi_port_example (
input clk, // System clock
input rst_n, // Active-low reset
// Port 0 interface (e.g., for CPU)
input [7:0] cpu_addr, // Address from CPU
input [31:0] cpu_data_in, // Data from CPU
input cpu_write_req, // Write request from CPU
input cpu_read_req, // Read request from CPU
output [31:0] cpu_data_out, // Data to CPU
output cpu_ready, // CPU operation complete
// Port 1 interface (e.g., for DMA)
input [7:0] dma_addr, // Address from DMA
input [31:0] dma_data_in, // Data from DMA
input dma_write_req, // Write request from DMA
input dma_read_req, // Read request from DMA
output [31:0] dma_data_out, // Data to DMA
output dma_ready, // DMA operation complete
// Common status signals
output error_detected // Error detected on any port
);
// Internal signals for NeoRAM interface
logic [1:0][7:0] neoram_addr;
logic [1:0][31:0] neoram_write_data;
logic [1:0] neoram_write_en;
logic [1:0][31:0] neoram_read_data;
logic [1:0] neoram_ready;
logic neoram_error;
// State machine for each port
typedef enum {IDLE, WRITING, READING, WAIT_READY} state_t;
state_t cpu_state, next_cpu_state;
state_t dma_state, next_dma_state;
// CPU port state registers
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cpu_state <= IDLE;
end else begin
cpu_state <= next_cpu_state;
end
end
// DMA port state registers
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dma_state <= IDLE;
end else begin
dma_state <= next_dma_state;
end
end
// CPU port next state logic
always_comb begin
next_cpu_state = cpu_state; // Default: stay in current state
case (cpu_state)
IDLE: begin
if (cpu_write_req) begin
next_cpu_state = WRITING;
end else if (cpu_read_req) begin
next_cpu_state = READING;
end
end
WRITING, READING: begin
next_cpu_state = WAIT_READY;
end
WAIT_READY: begin
if (neoram_ready[0]) begin
next_cpu_state = IDLE;
end
end
default: next_cpu_state = IDLE;
endcase
end
// DMA port next state logic
always_comb begin
next_dma_state = dma_state; // Default: stay in current state
case (dma_state)
IDLE: begin
if (dma_write_req) begin
next_dma_state = WRITING;
end else if (dma_read_req) begin
next_dma_state = READING;
end
end
WRITING, READING: begin
next_dma_state = WAIT_READY;
end
WAIT_READY: begin
if (neoram_ready[1]) begin
next_dma_state = IDLE;
end
end
default: next_dma_state = IDLE;
endcase
end
// CPU port output logic
always_comb begin
// Default values
neoram_addr[0] = 8'd0;
neoram_write_data[0] = 32'd0;
neoram_write_en[0] = 1'b0;
case (cpu_state)
IDLE: begin
// Idle state, no signals active
end
WRITING: begin
neoram_addr[0] = cpu_addr;
neoram_write_data[0] = cpu_data_in;
neoram_write_en[0] = 1'b1;
end
READING: begin
neoram_addr[0] = cpu_addr;
neoram_write_en[0] = 1'b0;
end
WAIT_READY: begin
// Hold signals steady while waiting
if (cpu_write_req) begin
neoram_addr[0] = cpu_addr;
neoram_write_data[0] = cpu_data_in;
neoram_write_en[0] = 1'b1;
end else if (cpu_read_req) begin
neoram_addr[0] = cpu_addr;
neoram_write_en[0] = 1'b0;
end
end
endcase
end
// DMA port output logic
always_comb begin
// Default values
neoram_addr[1] = 8'd0;
neoram_write_data[1] = 32'd0;
neoram_write_en[1] = 1'b0;
case (dma_state)
IDLE: begin
// Idle state, no signals active
end
WRITING: begin
neoram_addr[1] = dma_addr;
neoram_write_data[1] = dma_data_in;
neoram_write_en[1] = 1'b1;
end
READING: begin
neoram_addr[1] = dma_addr;
neoram_write_en[1] = 1'b0;
end
WAIT_READY: begin
// Hold signals steady while waiting
if (dma_write_req) begin
neoram_addr[1] = dma_addr;
neoram_write_data[1] = dma_data_in;
neoram_write_en[1] = 1'b1;
end else if (dma_read_req) begin
neoram_addr[1] = dma_addr;
neoram_write_en[1] = 1'b0;
end
end
endcase
end
// Output assignments
assign cpu_data_out = neoram_read_data[0];
assign cpu_ready = (cpu_state == IDLE);
assign dma_data_out = neoram_read_data[1];
assign dma_ready = (dma_state == IDLE);
assign error_detected = neoram_error;
// Instantiate NeoRAM controller with 2 ports
neoram_controller #(
.ADDR_WIDTH(8), // 8-bit address
.DATA_WIDTH(32), // 32-bit data
.NUM_PORTS(2) // Dual port configuration
) neoram_inst (
.clk (clk),
.rst_n (rst_n),
.addr (neoram_addr), // Connect your address buses
.write_data (neoram_write_data), // Connect your write data buses
.write_en (neoram_write_en), // Connect your write enable signals
.read_data (neoram_read_data), // Connect to your read data outputs
.ready (neoram_ready), // Connect to your ready signals
.error (neoram_error) // Connect to error handling logic
);
// Performance monitoring (optional) - Enhanced for v1.3.0
logic [31:0] access_count [1:0];
logic [31:0] conflict_count;
logic [31:0] arbitration_cycles;
// Count accesses, conflicts, and arbitration fairness
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_count[0] <= 32'd0;
access_count[1] <= 32'd0;
conflict_count <= 32'd0;
arbitration_cycles <= 32'd0;
end else begin
// Count CPU access
if ((cpu_state == WRITING || cpu_state == READING) &&
next_cpu_state == WAIT_READY) begin
access_count[0] <= access_count[0] + 1;
end
// Count DMA access
if ((dma_state == WRITING || dma_state == READING) &&
next_dma_state == WAIT_READY) begin
access_count[1] <= access_count[1] + 1;
end
// Count conflicts (both ports accessing same address simultaneously)
// Note: v1.3.0 uses round-robin arbitration for fair conflict resolution
if ((cpu_state == WRITING || cpu_state == READING) &&
(dma_state == WRITING || dma_state == READING) &&
(cpu_addr == dma_addr)) begin
conflict_count <= conflict_count + 1;
end
// Monitor arbitration cycles for performance analysis
if ((cpu_state != IDLE) || (dma_state != IDLE)) begin
arbitration_cycles <= arbitration_cycles + 1;
end
end
end
// v1.3.0 Features demonstration
initial begin
$display("NeoRAM Multi-Port Example - v1.3.0");
$display("Features:");
$display(" - Round-robin arbitration for fair port access");
$display(" - Proper ready signal initialization (no 'x' states)");
$display(" - 32-bit data width consistency");
$display(" - Enhanced conflict resolution");
end
endmodule