1 // -----------------------------------------------------------------------
3 // Copyright 2008 Tommy Thorn - All Rights Reserved
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 // Bostom MA 02111-1307, USA; either version 2 of the License, or
9 // (at your option) any later version; incorporated herein by reference.
11 // -----------------------------------------------------------------------
15 `include "../soclib/pipeconnect.h"
19 /* Conditional compilation removes a lot of annoying warnings during synthesis. */
20 module stallcheck(clock
, stall
, a
);
21 parameter which
= "?";
32 always @(posedge clock
) begin
33 {a_
,stall_
} <= {a
,stall
};
34 if (stall_
&& a
!= a_
)
35 $display("** %05d STALLCHECKER violation %d: was %x != now %x (%d)",
36 $time, id
, a_
, a
, stall_
);
41 module yari(input wire clock
45 ,input mem_waitrequest
47 ,output [29:0] mem_address
50 ,output [31:0] mem_writedata
51 ,output [3:0] mem_writedatamask
52 ,input [31:0] mem_readdata
53 ,input [1:0] mem_readdataid
55 ,output wire `REQ peripherals_req
56 ,input wire `RES peripherals_res
59 parameter FREQ
= 0; // Frequency in Hz, should be passed down from the top-level
62 wire i1_valid
, i2_valid
;
63 wire [31:0] i1_pc
, i2_pc
;
68 wire [31:0] i_instr_muxed
;
70 wire [31:0] i_pc_muxed
;
73 wire imem_waitrequest
;
74 wire [29:0] imem_address
;
76 wire [31:0] imem_readdata
;
77 wire imem_readdatavalid
;
92 wire d_has_delay_slot
;
93 wire [31:0] d_op1_val
;
94 wire [31:0] d_op2_val
;
99 wire [31:0] d_restart_pc
;
101 wire d_load_use_hazard
;
105 wire x_is_delay_slot
;
107 wire [ 5:0] x_opcode
;
108 wire [31:0] x_op1_val
;
110 wire [31:0] x_rt_val
;
115 wire [31:0] x_synci_a
;
118 wire [31:0] x_restart_pc
;
128 wire [31:0] m_restart_pc
;
130 wire dmem_waitrequest
;
131 wire [29:0] dmem_address
;
134 wire [31:0] dmem_writedata
;
135 wire [ 3:0] dmem_writedatamask
;
136 wire [31:0] dmem_readdata
;
137 wire dmem_readdatavalid
;
139 wire [31:0] perf_branch_hazard
;
140 wire [31:0] perf_dcache_misses
;
141 wire [31:0] perf_delay_slot_bubble
;
142 wire [31:0] perf_div_hazard
;
143 wire [31:0] perf_icache_misses
;
144 wire [31:0] perf_io_load_busy
;
145 wire [31:0] perf_io_store_busy
;
146 wire [31:0] perf_load_hit_store_hazard
;
147 wire [31:0] perf_load_use_hazard
;
148 wire [31:0] perf_mult_hazard
;
149 wire [47:0] perf_retired_inst
;
150 wire [31:0] perf_sb_full
;
153 reg [9:0] initialized
= 0;
154 always @(posedge clock
) initialized
<= {initialized
[8:0],~rst
};
156 // XXX It would be nice to make this a bit more general and merge
157 // it with the interrupt mechanism (still to come)
158 wire boot
= initialized
[7] & ~initialized
[8];
160 wire restart
= d_restart | x_restart | m_restart
;
161 wire [31:0] restart_pc
= (d_restart ? d_restart_pc
:
162 m_restart ? m_restart_pc
:
163 /*********/ x_restart_pc
);
164 wire flush_I
= restart
;
165 wire flush_D
= m_restart | x_flush_D
;
166 wire flush_X
= m_restart | d_flush_X
;
168 stage_I
stI(.
clock(clock
)
169 ,.
kill(~initialized
[8])
171 ,.
restart_pc(restart_pc
)
175 ,.
imem_waitrequest(imem_waitrequest
)
176 ,.
imem_address(imem_address
)
177 ,.
imem_read(imem_read
)
178 ,.
imem_readdata(imem_readdata
)
179 ,.
imem_readdatavalid(imem_readdatavalid
)
191 ,.
perf_icache_misses(perf_icache_misses
));
193 stage_D
stD(.
clock(clock
),
194 .
i_valid(i_valid
& ~flush_I
),
199 .
i_valid_muxed(i_valid_muxed
),
200 .
i_pc_muxed(i_pc_muxed
),
201 .
i_instr_muxed(i_instr_muxed
),
203 .
x_valid(x_valid
& ~flush_X
),
208 .
m_pc(m_pc
), // XXX for debugging only
212 // Outputs, mostly derived from d_instr
214 .
d_illegal_instr(d_illegal_instr
),
226 .
d_has_delay_slot(d_has_delay_slot
),
229 .
d_op1_val(d_op1_val
),
230 .
d_op2_val(d_op2_val
),
233 .
d_restart(d_restart
),
234 .
d_restart_pc(d_restart_pc
),
235 .
d_flush_X(d_flush_X
),
236 .
d_load_use_hazard(d_load_use_hazard
),
239 .
perf_delay_slot_bubble(perf_delay_slot_bubble
),
240 .
perf_retired_inst(perf_retired_inst
)
243 stage_X
stX(.
clock(clock
),
246 .
restart_pc(restart_pc
),
248 .
d_valid(d_valid
& ~flush_D
),
260 .
d_has_delay_slot(d_has_delay_slot
),
262 .
d_op1_val(d_op1_val
),
263 .
d_op2_val(d_op2_val
),
266 .
d_restart(d_restart
),
267 .
d_restart_pc(d_restart_pc
),
268 .
d_load_use_hazard(d_load_use_hazard
),
273 // Results from this stage
275 .
x_instr(x_instr
), // XXX for debugging only
276 .
x_is_delay_slot(x_is_delay_slot
),
279 .
x_op1_val(x_op1_val
),
286 .
x_synci_a(x_synci_a
),
288 .
x_restart(x_restart
),
289 .
x_restart_pc(x_restart_pc
),
290 .
x_flush_D(x_flush_D
),
292 .
perf_branch_hazard(perf_branch_hazard
),
293 .
perf_dcache_misses(perf_dcache_misses
),
294 .
perf_delay_slot_bubble(perf_delay_slot_bubble
),
295 .
perf_div_hazard(perf_div_hazard
),
296 .
perf_icache_misses(perf_icache_misses
),
297 .
perf_io_load_busy(perf_io_load_busy
),
298 .
perf_io_store_busy(perf_io_store_busy
),
299 .
perf_load_hit_store_hazard(perf_load_hit_store_hazard
),
300 .
perf_load_use_hazard(perf_load_use_hazard
),
301 .
perf_mult_hazard(perf_mult_hazard
),
302 .
perf_retired_inst(perf_retired_inst
),
303 .
perf_sb_full(perf_sb_full
)
305 defparam stX.FREQ
= FREQ
;
307 stage_M
stM(.
clock(clock
),
309 // XXX Rebooting on illegal instruction is harsh
310 .
boot(boot | d_illegal_instr
),
311 .
boot_pc('hBFC00000
),
314 .
d_op1_val(d_op1_val
),
316 .
x_valid(x_valid
& ~flush_X
),
318 .
x_is_delay_slot(x_is_delay_slot
),
321 .
x_op1_val(x_op1_val
),
327 ,.
dmem_waitrequest(dmem_waitrequest
)
328 ,.
dmem_address(dmem_address
)
329 ,.
dmem_read(dmem_read
)
330 ,.
dmem_write(dmem_write
)
331 ,.
dmem_writedata(dmem_writedata
)
332 ,.
dmem_writedatamask(dmem_writedatamask
)
333 ,.
dmem_readdata(dmem_readdata
)
334 ,.
dmem_readdatavalid(dmem_readdatavalid
)
337 .
peripherals_req(peripherals_req
),
338 .
peripherals_res(peripherals_res
),
346 .
m_restart(m_restart
),
347 .
m_restart_pc(m_restart_pc
),
349 .
perf_dcache_misses(perf_dcache_misses
),
350 .
perf_io_load_busy(perf_io_load_busy
),
351 .
perf_io_store_busy(perf_io_store_busy
),
352 .
perf_load_hit_store_hazard(perf_load_hit_store_hazard
),
353 .
perf_sb_full(perf_sb_full
)
358 * Memory arbitration. "Hopefully so simple that I can do it all
360 * Static priority - bad idea in general, but ok here.
361 * Key decision: dmem port gets priority. Why? Imagine it was
362 * the other way around and both miss in their caches. IF will
363 * keep emitting bubbles while filling, but ME will repeatedly
364 * restart the load and flush the pipe. At least with ME filling
365 * first, we get to execute the few instructions already in the
366 * pipe while waiting for IF. One of them could be a MUL!
368 parameter ID_DC
= 2'd1;
369 parameter ID_IC
= 2'd2;
370 wire dmem_strobe
= dmem_read | dmem_write
;
372 assign mem_id
= dmem_strobe ? ID_DC
: ID_IC
;
373 assign mem_address
= dmem_strobe ? dmem_address
: imem_address
;
374 assign mem_read
= dmem_strobe ? dmem_read
: imem_read
;
375 assign mem_write
= dmem_write
;
376 assign mem_writedata
= dmem_writedata
;
377 assign mem_writedatamask
= dmem_writedatamask
;
379 assign dmem_waitrequest
= mem_waitrequest
;
380 assign dmem_readdata
= mem_readdata
;
381 assign dmem_readdatavalid
= mem_readdataid
== ID_DC
;
383 assign imem_waitrequest
= mem_waitrequest | dmem_strobe
;
384 assign imem_readdata
= mem_readdata
;
385 assign imem_readdatavalid
= mem_readdataid
== ID_IC
;
388 always @(posedge clock
) if (debug
) begin
390 $display("%05d RESTART %x FROM DE", $time, d_restart_pc
);
392 $display("%05d RESTART %x FROM ME", $time, m_restart_pc
);
394 $display("%05d RESTART %x FROM EX", $time, x_restart_pc
);
397 "%05dz %x/0 I %8x D %8x:%8x X %8x:%8x:%8x>%2x M %8x:%8x>%2x W %8x:%8x>%2x",
401 {flush_X
,flush_D
,flush_I
},
404 i1_valid ? i1_pc
: 'hZ
,
407 i_pc_muxed
, i_valid_muxed ? i_instr_muxed
: 'hZ
,
410 d_pc
, d_valid
& ~flush_D ? d_op1_val
: 'hZ
,
411 d_valid
& ~flush_D ? d_op2_val
: 'hZ
,
412 d_valid
& ~flush_D ? d_wbr
: 8'hZ
,
415 x_pc
, x_valid
& ~flush_X ? x_res
: 'hZ
,
416 x_valid
& ~flush_X ? x_wbr
: 8'hZ
,
419 m_pc
, m_valid ? m_res
: 'hZ
,
420 m_valid ? m_wbr
: 8'hZ
);