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
// K5 PLL1 input clock (50 MHz)
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
61 wire i1_valid
, i2_valid
;
62 wire [31:0] i1_pc
, i2_pc
;
69 wire imem_waitrequest
;
70 wire [29:0] imem_address
;
72 wire [31:0] imem_readdata
;
73 wire imem_readdatavalid
;
87 wire d_has_delay_slot
;
88 wire [31:0] d_op1_val
;
89 wire [31:0] d_op2_val
;
94 wire [31:0] d_restart_pc
;
96 wire d_load_use_hazard
;
100 wire x_is_delay_slot
;
102 wire [ 5:0] x_opcode
;
103 wire [31:0] x_op1_val
;
105 wire [31:0] x_rt_val
;
110 wire [31:0] x_synci_a
;
113 wire [31:0] x_restart_pc
;
123 wire [31:0] m_restart_pc
;
125 wire dmem_waitrequest
;
126 wire [29:0] dmem_address
;
129 wire [31:0] dmem_writedata
;
130 wire [ 3:0] dmem_writedatamask
;
131 wire [31:0] dmem_readdata
;
132 wire dmem_readdatavalid
;
134 wire [31:0] perf_branch_hazard
;
135 wire [31:0] perf_dcache_misses
;
136 wire [31:0] perf_delay_slot_bubble
;
137 wire [31:0] perf_div_hazard
;
138 wire [31:0] perf_icache_misses
;
139 wire [31:0] perf_io_load_busy
;
140 wire [31:0] perf_io_store_busy
;
141 wire [31:0] perf_load_hit_store_hazard
;
142 wire [31:0] perf_load_use_hazard
;
143 wire [31:0] perf_mult_hazard
;
144 wire [47:0] perf_retired_inst
;
145 wire [31:0] perf_sb_full
;
148 reg [9:0] initialized
= 0;
149 always @(posedge clock
) initialized
<= {initialized
[8:0],~rst
};
151 // XXX It would be nice to make this a bit more general and merge
152 // it with the interrupt mechanism (still to come)
153 wire boot
= initialized
[7] & ~initialized
[8];
155 wire restart
= d_restart | x_restart | m_restart
;
156 wire [31:0] restart_pc
= (d_restart ? d_restart_pc
:
157 m_restart ? m_restart_pc
:
158 /*********/ x_restart_pc
);
159 wire flush_I
= restart
;
160 wire flush_D
= m_restart | x_flush_D
;
161 wire flush_X
= m_restart | d_flush_X
;
163 stage_I
stI(.
clock(clock
)
164 ,.
kill(~initialized
[8])
166 ,.
restart_pc(restart_pc
)
170 ,.
imem_waitrequest(imem_waitrequest
)
171 ,.
imem_address(imem_address
)
172 ,.
imem_read(imem_read
)
173 ,.
imem_readdata(imem_readdata
)
174 ,.
imem_readdatavalid(imem_readdatavalid
)
186 ,.
perf_icache_misses(perf_icache_misses
));
188 stage_D
stD(.
clock(clock
),
189 .
i_valid(i_valid
& ~flush_I
),
194 .
x_valid(x_valid
& ~flush_X
),
199 .
m_pc(m_pc
), // XXX for debugging only
203 // Outputs, mostly derived from d_instr
216 .
d_has_delay_slot(d_has_delay_slot
),
219 .
d_op1_val(d_op1_val
),
220 .
d_op2_val(d_op2_val
),
223 .
d_restart(d_restart
),
224 .
d_restart_pc(d_restart_pc
),
225 .
d_flush_X(d_flush_X
),
226 .
d_load_use_hazard(d_load_use_hazard
),
229 .
perf_delay_slot_bubble(perf_delay_slot_bubble
),
230 .
perf_retired_inst(perf_retired_inst
)
233 stage_X
stX(.
clock(clock
),
236 .
restart_pc(restart_pc
),
238 .
d_valid(d_valid
& ~flush_D
),
250 .
d_has_delay_slot(d_has_delay_slot
),
252 .
d_op1_val(d_op1_val
),
253 .
d_op2_val(d_op2_val
),
256 .
d_restart(d_restart
),
257 .
d_restart_pc(d_restart_pc
),
258 .
d_load_use_hazard(d_load_use_hazard
),
263 // Results from this stage
265 .
x_instr(x_instr
), // XXX for debugging only
266 .
x_is_delay_slot(x_is_delay_slot
),
269 .
x_op1_val(x_op1_val
),
276 .
x_synci_a(x_synci_a
),
278 .
x_restart(x_restart
),
279 .
x_restart_pc(x_restart_pc
),
280 .
x_flush_D(x_flush_D
),
282 .
perf_branch_hazard(perf_branch_hazard
),
283 .
perf_dcache_misses(perf_dcache_misses
),
284 .
perf_delay_slot_bubble(perf_delay_slot_bubble
),
285 .
perf_div_hazard(perf_div_hazard
),
286 .
perf_icache_misses(perf_icache_misses
),
287 .
perf_io_load_busy(perf_io_load_busy
),
288 .
perf_io_store_busy(perf_io_store_busy
),
289 .
perf_load_hit_store_hazard(perf_load_hit_store_hazard
),
290 .
perf_load_use_hazard(perf_load_use_hazard
),
291 .
perf_mult_hazard(perf_mult_hazard
),
292 .
perf_retired_inst(perf_retired_inst
),
293 .
perf_sb_full(perf_sb_full
)
296 stage_M
stM(.
clock(clock
),
299 .
boot_pc('hBFC00000
),
302 .
d_op1_val(d_op1_val
),
304 .
x_valid(x_valid
& ~flush_X
),
306 .
x_is_delay_slot(x_is_delay_slot
),
309 .
x_op1_val(x_op1_val
),
315 ,.
dmem_waitrequest(dmem_waitrequest
)
316 ,.
dmem_address(dmem_address
)
317 ,.
dmem_read(dmem_read
)
318 ,.
dmem_write(dmem_write
)
319 ,.
dmem_writedata(dmem_writedata
)
320 ,.
dmem_writedatamask(dmem_writedatamask
)
321 ,.
dmem_readdata(dmem_readdata
)
322 ,.
dmem_readdatavalid(dmem_readdatavalid
)
325 .
peripherals_req(peripherals_req
),
326 .
peripherals_res(peripherals_res
),
334 .
m_restart(m_restart
),
335 .
m_restart_pc(m_restart_pc
),
337 .
perf_dcache_misses(perf_dcache_misses
),
338 .
perf_io_load_busy(perf_io_load_busy
),
339 .
perf_io_store_busy(perf_io_store_busy
),
340 .
perf_load_hit_store_hazard(perf_load_hit_store_hazard
),
341 .
perf_sb_full(perf_sb_full
)
346 * Memory arbitration. "Hopefully so simple that I can do it all
348 * Static priority - bad idea in general, but ok here.
349 * Key decision: dmem port gets priority. Why? Imagine it was
350 * the other way around and both miss in their caches. IF will
351 * keep emitting bubbles while filling, but ME will repeatedly
352 * restart the load and flush the pipe. At least with ME filling
353 * first, we get to execute the few instructions already in the
354 * pipe while waiting for IF. One of them could be a MUL!
356 parameter ID_DC
= 2'd1;
357 parameter ID_IC
= 2'd2;
358 wire dmem_strobe
= dmem_read | dmem_write
;
360 assign mem_id
= dmem_strobe ? ID_DC
: ID_IC
;
361 assign mem_address
= dmem_strobe ? dmem_address
: imem_address
;
362 assign mem_read
= dmem_strobe ? dmem_read
: imem_read
;
363 assign mem_write
= dmem_write
;
364 assign mem_writedata
= dmem_writedata
;
365 assign mem_writedatamask
= dmem_writedatamask
;
367 assign dmem_waitrequest
= mem_waitrequest
;
368 assign dmem_readdata
= mem_readdata
;
369 assign dmem_readdatavalid
= mem_readdataid
== ID_DC
;
371 assign imem_waitrequest
= mem_waitrequest | dmem_strobe
;
372 assign imem_readdata
= mem_readdata
;
373 assign imem_readdatavalid
= mem_readdataid
== ID_IC
;
376 always @(posedge clock
) if (debug
) begin
378 $display("%05d restart pipe at %x", $time, restart_pc
);
380 $display("%05d boot vector", $time);
382 $display("%05d from stage ME", $time);
384 $display("%05d from stage EX", $time);
388 "%05dz %x %x/0 I %8x %8x D %8x:%8x X %8x:%8x:%8x>%2x M %8x:%8x>%2x W %8x:%8x>%2x",
393 {flush_X
,flush_D
,flush_I
},
396 i1_valid ? i1_pc
: 'hZ
,
397 i2_valid ? i2_pc
: 'hZ
,
400 i_pc
, i_valid
& ~flush_I ? i_instr
: 'hZ
,
403 d_pc
, d_valid
& ~flush_D ? d_op1_val
: 'hZ
,
404 d_valid
& ~flush_D ? d_op2_val
: 'hZ
,
405 d_valid
& ~flush_D ? d_wbr
: 8'hZ
,
408 x_pc
, x_valid
& ~flush_X ? x_res
: 'hZ
,
409 x_valid
& ~flush_X ? x_wbr
: 8'hZ
,
412 m_pc
, m_valid ? m_res
: 'hZ
,
413 m_valid ? m_wbr
: 8'hZ
);