rlm@8
|
1 import CBusUtils::*;
|
rlm@8
|
2 import Register::*;
|
rlm@8
|
3
|
rlm@8
|
4 import Trace::*;
|
rlm@8
|
5 import MemTypes::*;
|
rlm@8
|
6 import IProc::*;
|
rlm@8
|
7 import ProcTypes::*;
|
rlm@8
|
8 import FPGATypes::*;
|
rlm@8
|
9 import RegFile::*;
|
rlm@8
|
10 import FIFO::*;
|
rlm@8
|
11 import BFIFO::*;
|
rlm@8
|
12 import Assert::*;
|
rlm@8
|
13
|
rlm@8
|
14 import GetPut::*;
|
rlm@8
|
15 import GetPutExt::*;
|
rlm@8
|
16 import ClientServer::*;
|
rlm@8
|
17 import CBus::*;
|
rlm@8
|
18
|
rlm@8
|
19
|
rlm@8
|
20 interface IProc;
|
rlm@8
|
21
|
rlm@8
|
22 // Interface for testrig
|
rlm@8
|
23 interface Put#(Bit#(8)) testrig_fromhost;
|
rlm@8
|
24 interface Get#(Bit#(8)) testrig_tohost;
|
rlm@8
|
25
|
rlm@8
|
26 // Interface from processor to caches
|
rlm@8
|
27 interface Client#(DataReq,DataResp) dmem_client;
|
rlm@8
|
28 interface Client#(InstReq,InstResp) imem_client;
|
rlm@8
|
29
|
rlm@8
|
30 // Interface for enabling/disabling statistics on the rest of the core
|
rlm@8
|
31 interface Get#(Bool) statsEn_get;
|
rlm@8
|
32
|
rlm@8
|
33 endinterface
|
rlm@8
|
34
|
rlm@8
|
35
|
rlm@8
|
36 typedef enum { PCgen, Exec, Writeback } Stage deriving(Eq,Bits);
|
rlm@8
|
37
|
rlm@8
|
38 //-----------------------------------------------------------
|
rlm@8
|
39 // Register file module
|
rlm@8
|
40 //-----------------------------------------------------------
|
rlm@8
|
41
|
rlm@8
|
42 interface RFile;
|
rlm@8
|
43 method Action wr( Rindx rindx, Bit#(32) data );
|
rlm@8
|
44 method Bit#(32) rd1( Rindx rindx );
|
rlm@8
|
45 method Bit#(32) rd2( Rindx rindx );
|
rlm@8
|
46 endinterface
|
rlm@8
|
47
|
rlm@8
|
48 module mkRFile( RFile );
|
rlm@8
|
49
|
rlm@8
|
50 RegFile#(Rindx,Bit#(32)) rfile <- mkRegFileFull();
|
rlm@8
|
51
|
rlm@8
|
52 method Action wr( Rindx rindx, Bit#(32) data );
|
rlm@8
|
53 rfile.upd( rindx, data );
|
rlm@8
|
54 endmethod
|
rlm@8
|
55
|
rlm@8
|
56 method Bit#(32) rd1( Rindx rindx );
|
rlm@8
|
57 return ( rindx == 0 ) ? 0 : rfile.sub(rindx);
|
rlm@8
|
58 endmethod
|
rlm@8
|
59
|
rlm@8
|
60 method Bit#(32) rd2( Rindx rindx );
|
rlm@8
|
61 return ( rindx == 0 ) ? 0 : rfile.sub(rindx);
|
rlm@8
|
62 endmethod
|
rlm@8
|
63
|
rlm@8
|
64 endmodule
|
rlm@8
|
65
|
rlm@8
|
66 //-----------------------------------------------------------
|
rlm@8
|
67 // Helper functions
|
rlm@8
|
68 //-----------------------------------------------------------
|
rlm@8
|
69
|
rlm@8
|
70 function Bit#(32) slt( Bit#(32) val1, Bit#(32) val2 );
|
rlm@8
|
71 return zeroExtend( pack( signedLT(val1,val2) ) );
|
rlm@8
|
72 endfunction
|
rlm@8
|
73
|
rlm@8
|
74 function Bit#(32) sltu( Bit#(32) val1, Bit#(32) val2 );
|
rlm@8
|
75 return zeroExtend( pack( val1 < val2 ) );
|
rlm@8
|
76 endfunction
|
rlm@8
|
77
|
rlm@8
|
78 function Bit#(32) rshft( Bit#(32) val );
|
rlm@8
|
79 return zeroExtend(val[4:0]);
|
rlm@8
|
80 endfunction
|
rlm@8
|
81
|
rlm@8
|
82 //-----------------------------------------------------------
|
rlm@8
|
83 // Reference processor
|
rlm@8
|
84 //-----------------------------------------------------------
|
rlm@8
|
85
|
rlm@8
|
86
|
rlm@8
|
87 module [ModWithCBus#(AvalonAddressWidth,AvalonDataWidth)] mkProc( IProc );
|
rlm@8
|
88
|
rlm@8
|
89 //-----------------------------------------------------------
|
rlm@8
|
90 // State
|
rlm@8
|
91
|
rlm@8
|
92 // Standard processor state
|
rlm@8
|
93
|
rlm@8
|
94 Reg#(Addr) pc <- mkReg(32'h00001000);
|
rlm@8
|
95 Reg#(Stage) stage <- mkReg(PCgen);
|
rlm@8
|
96 RFile rf <- mkRFile;
|
rlm@8
|
97
|
rlm@8
|
98 // Coprocessor state
|
rlm@8
|
99
|
rlm@8
|
100 Reg#(Bit#(8)) cp0_tohost <- mkReg(0);
|
rlm@8
|
101 mkCBusWideRegRW(valueof(ToHostRegAddr),cp0_tohost);
|
rlm@8
|
102 Reg#(Bit#(8)) cp0_fromhost <- mkReg(0);
|
rlm@8
|
103 mkCBusWideRegRW(valueof(FromHostRegAddr),cp0_fromhost);
|
rlm@8
|
104 Reg#(Bool) cp0_statsEn <- mkReg(False);
|
rlm@8
|
105 mkCBusWideRegRW(valueof(StatsEnRegAddr),cp0_statsEn);
|
rlm@8
|
106 // Memory request/response state
|
rlm@8
|
107
|
rlm@8
|
108 FIFO#(InstReq) instReqQ <- mkBFIFO1();
|
rlm@8
|
109 FIFO#(InstResp) instRespQ <- mkFIFO();
|
rlm@8
|
110
|
rlm@8
|
111 FIFO#(DataReq) dataReqQ <- mkBFIFO1();
|
rlm@8
|
112 FIFO#(DataResp) dataRespQ <- mkFIFO();
|
rlm@8
|
113
|
rlm@8
|
114 // Statistics state
|
rlm@8
|
115
|
rlm@8
|
116 Reg#(Int#(25)) num_cycles <- mkReg(25'h0);
|
rlm@8
|
117 Reg#(Int#(25)) num_inst <- mkReg(25'h0);
|
rlm@8
|
118
|
rlm@8
|
119 //-----------------------------------------------------------
|
rlm@8
|
120 // Rules
|
rlm@8
|
121
|
rlm@8
|
122 let pc_plus4 = pc + 4;
|
rlm@8
|
123
|
rlm@8
|
124 rule pcgen ( stage == PCgen );
|
rlm@8
|
125 traceTiny("pc",pc);
|
rlm@8
|
126 traceTiny("stage","P");
|
rlm@8
|
127 instReqQ.enq( LoadReq{ addr:pc, tag:0 } );
|
rlm@8
|
128 stage <= Exec;
|
rlm@8
|
129 endrule
|
rlm@8
|
130
|
rlm@8
|
131 rule exec ( stage == Exec );
|
rlm@8
|
132
|
rlm@8
|
133 // Some abbreviations
|
rlm@8
|
134 let sext = signExtend;
|
rlm@8
|
135 let zext = zeroExtend;
|
rlm@8
|
136 let sra = signedShiftRight;
|
rlm@8
|
137
|
rlm@8
|
138 // Get the instruction
|
rlm@8
|
139
|
rlm@8
|
140 instRespQ.deq();
|
rlm@8
|
141 Instr inst
|
rlm@8
|
142 = case ( instRespQ.first() ) matches
|
rlm@8
|
143 tagged LoadResp .ld : return unpack(ld.data);
|
rlm@8
|
144 tagged StoreResp .st : return ?;
|
rlm@8
|
145 endcase;
|
rlm@8
|
146
|
rlm@8
|
147 // Some default variables
|
rlm@8
|
148 Stage next_stage = PCgen;
|
rlm@8
|
149 Addr next_pc = pc_plus4;
|
rlm@8
|
150
|
rlm@8
|
151 // Tracing
|
rlm@8
|
152 traceTiny("stage","X");
|
rlm@8
|
153 traceTiny("exInstTiny",inst);
|
rlm@8
|
154 traceFull("exInstFull",inst);
|
rlm@8
|
155
|
rlm@8
|
156 case ( inst ) matches
|
rlm@8
|
157
|
rlm@8
|
158 // -- Memory Ops ------------------------------------------------
|
rlm@8
|
159
|
rlm@8
|
160 tagged LW .it :
|
rlm@8
|
161 begin
|
rlm@8
|
162 Addr addr = rf.rd1(it.rbase) + sext(it.offset);
|
rlm@8
|
163 dataReqQ.enq( LoadReq{ addr:addr, tag:zeroExtend(it.rdst) } );
|
rlm@8
|
164 next_stage = Writeback;
|
rlm@8
|
165 end
|
rlm@8
|
166
|
rlm@8
|
167 tagged SW .it :
|
rlm@8
|
168 begin
|
rlm@8
|
169 Addr addr = rf.rd1(it.rbase) + sext(it.offset);
|
rlm@8
|
170 dataReqQ.enq( StoreReq{ tag:0, addr:addr, data:rf.rd1(it.rsrc) } );
|
rlm@8
|
171 next_stage = Writeback;
|
rlm@8
|
172 end
|
rlm@8
|
173
|
rlm@8
|
174 // -- Simple Ops ------------------------------------------------
|
rlm@8
|
175
|
rlm@8
|
176 tagged ADDIU .it : rf.wr( it.rdst, rf.rd1(it.rsrc) + sext(it.imm) );
|
rlm@8
|
177 tagged SLTI .it : rf.wr( it.rdst, slt( rf.rd1(it.rsrc), sext(it.imm) ) );
|
rlm@8
|
178 tagged SLTIU .it : rf.wr( it.rdst, sltu( rf.rd1(it.rsrc), sext(it.imm) ) );
|
rlm@8
|
179 tagged ANDI .it :
|
rlm@8
|
180 begin
|
rlm@8
|
181 Bit#(32) zext_it_imm = zext(it.imm);
|
rlm@8
|
182 rf.wr( it.rdst, rf.rd1(it.rsrc) & zext_it_imm );
|
rlm@8
|
183 end
|
rlm@8
|
184 tagged ORI .it :
|
rlm@8
|
185 begin
|
rlm@8
|
186 Bit#(32) zext_it_imm = zext(it.imm);
|
rlm@8
|
187 rf.wr( it.rdst, rf.rd1(it.rsrc) | zext_it_imm );
|
rlm@8
|
188 end
|
rlm@8
|
189 tagged XORI .it :
|
rlm@8
|
190 begin
|
rlm@8
|
191 Bit#(32) zext_it_imm = zext(it.imm);
|
rlm@8
|
192 rf.wr( it.rdst, rf.rd1(it.rsrc) ^ zext_it_imm );
|
rlm@8
|
193 end
|
rlm@8
|
194 tagged LUI .it :
|
rlm@8
|
195 begin
|
rlm@8
|
196 Bit#(32) zext_it_imm = zext(it.imm);
|
rlm@8
|
197 rf.wr( it.rdst, (zext_it_imm << 32'd16) );
|
rlm@8
|
198 end
|
rlm@8
|
199
|
rlm@8
|
200 tagged SLL .it :
|
rlm@8
|
201 begin
|
rlm@8
|
202 Bit#(32) zext_it_shamt = zext(it.shamt);
|
rlm@8
|
203 rf.wr( it.rdst, rf.rd1(it.rsrc) << zext_it_shamt );
|
rlm@8
|
204 end
|
rlm@8
|
205 tagged SRL .it :
|
rlm@8
|
206 begin
|
rlm@8
|
207 Bit#(32) zext_it_shamt = zext(it.shamt);
|
rlm@8
|
208 rf.wr( it.rdst, rf.rd1(it.rsrc) >> zext_it_shamt );
|
rlm@8
|
209 end
|
rlm@8
|
210 tagged SRA .it :
|
rlm@8
|
211 begin
|
rlm@8
|
212 Bit#(32) zext_it_shamt = zext(it.shamt);
|
rlm@8
|
213 rf.wr( it.rdst, sra( rf.rd1(it.rsrc), zext_it_shamt ));
|
rlm@8
|
214 end
|
rlm@8
|
215 tagged SLLV .it : rf.wr( it.rdst, rf.rd1(it.rsrc) << rshft(rf.rd2(it.rshamt)) );
|
rlm@8
|
216 tagged SRLV .it : rf.wr( it.rdst, rf.rd1(it.rsrc) >> rshft(rf.rd2(it.rshamt)) );
|
rlm@8
|
217 tagged SRAV .it : rf.wr( it.rdst, sra( rf.rd1(it.rsrc), rshft(rf.rd2(it.rshamt)) ) );
|
rlm@8
|
218 tagged ADDU .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) + rf.rd2(it.rsrc2) );
|
rlm@8
|
219 tagged SUBU .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) - rf.rd2(it.rsrc2) );
|
rlm@8
|
220 tagged AND .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) & rf.rd2(it.rsrc2) );
|
rlm@8
|
221 tagged OR .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2) );
|
rlm@8
|
222 tagged XOR .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) ^ rf.rd2(it.rsrc2) );
|
rlm@8
|
223 tagged NOR .it : rf.wr( it.rdst, ~(rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2)) );
|
rlm@8
|
224 tagged SLT .it : rf.wr( it.rdst, slt( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ) );
|
rlm@8
|
225 tagged SLTU .it : rf.wr( it.rdst, sltu( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ) );
|
rlm@8
|
226
|
rlm@8
|
227 // -- Branches --------------------------------------------------
|
rlm@8
|
228
|
rlm@8
|
229 tagged BLEZ .it :
|
rlm@8
|
230 if ( signedLE( rf.rd1(it.rsrc), 0 ) )
|
rlm@8
|
231 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
232
|
rlm@8
|
233 tagged BGTZ .it :
|
rlm@8
|
234 if ( signedGT( rf.rd1(it.rsrc), 0 ) )
|
rlm@8
|
235 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
236
|
rlm@8
|
237 tagged BLTZ .it :
|
rlm@8
|
238 if ( signedLT( rf.rd1(it.rsrc), 0 ) )
|
rlm@8
|
239 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
240
|
rlm@8
|
241 tagged BGEZ .it :
|
rlm@8
|
242 if ( signedGE( rf.rd1(it.rsrc), 0 ) )
|
rlm@8
|
243 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
244
|
rlm@8
|
245 tagged BEQ .it :
|
rlm@8
|
246 if ( rf.rd1(it.rsrc1) == rf.rd2(it.rsrc2) )
|
rlm@8
|
247 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
248
|
rlm@8
|
249 tagged BNE .it :
|
rlm@8
|
250 if ( rf.rd1(it.rsrc1) != rf.rd2(it.rsrc2) )
|
rlm@8
|
251 next_pc = pc_plus4 + (sext(it.offset) << 2);
|
rlm@8
|
252
|
rlm@8
|
253 // -- Jumps -----------------------------------------------------
|
rlm@8
|
254
|
rlm@8
|
255 tagged J .it :
|
rlm@8
|
256 next_pc = { pc_plus4[31:28], it.target, 2'b0 };
|
rlm@8
|
257
|
rlm@8
|
258 tagged JR .it :
|
rlm@8
|
259 next_pc = rf.rd1(it.rsrc);
|
rlm@8
|
260
|
rlm@8
|
261 tagged JAL .it :
|
rlm@8
|
262 begin
|
rlm@8
|
263 rf.wr( 31, pc_plus4 );
|
rlm@8
|
264 next_pc = { pc_plus4[31:28], it.target, 2'b0 };
|
rlm@8
|
265 end
|
rlm@8
|
266
|
rlm@8
|
267 tagged JALR .it :
|
rlm@8
|
268 begin
|
rlm@8
|
269 rf.wr( it.rdst, pc_plus4 );
|
rlm@8
|
270 next_pc = rf.rd1(it.rsrc);
|
rlm@8
|
271 end
|
rlm@8
|
272
|
rlm@8
|
273 // -- Cop0 ------------------------------------------------------
|
rlm@8
|
274
|
rlm@8
|
275 tagged MTC0 .it :
|
rlm@8
|
276 case ( it.cop0dst )
|
rlm@8
|
277 5'd10 : cp0_statsEn <= unpack(truncate(rf.rd1(it.rsrc)));
|
rlm@8
|
278 5'd21 : cp0_tohost <= truncate(rf.rd1(it.rsrc));
|
rlm@8
|
279 default :
|
rlm@8
|
280 $display( " RTL-ERROR : %m : Illegal MTC0 cop0dst register!" );
|
rlm@8
|
281 endcase
|
rlm@8
|
282
|
rlm@8
|
283 tagged MFC0 .it :
|
rlm@8
|
284 case ( it.cop0src )
|
rlm@8
|
285 5'd10 : rf.wr( it.rdst, zext(pack(cp0_statsEn)) );
|
rlm@8
|
286 5'd20 : rf.wr( it.rdst, zext(cp0_fromhost) );
|
rlm@8
|
287 5'd21 : rf.wr( it.rdst, zext(cp0_tohost) );
|
rlm@8
|
288 default :
|
rlm@8
|
289 $display( " RTL-ERROR : %m : Illegal MFC0 cop0src register!" );
|
rlm@8
|
290 endcase
|
rlm@8
|
291
|
rlm@8
|
292 // -- Illegal ---------------------------------------------------
|
rlm@8
|
293
|
rlm@8
|
294 default :
|
rlm@8
|
295 $display( " RTL-ERROR : %m : Illegal instruction !" );
|
rlm@8
|
296
|
rlm@8
|
297 endcase
|
rlm@8
|
298
|
rlm@8
|
299 stage <= next_stage;
|
rlm@8
|
300 pc <= next_pc;
|
rlm@8
|
301
|
rlm@8
|
302 if ( cp0_statsEn )
|
rlm@8
|
303 num_inst <= num_inst + 1;
|
rlm@8
|
304
|
rlm@8
|
305 endrule
|
rlm@8
|
306
|
rlm@8
|
307 rule writeback ( stage == Writeback );
|
rlm@8
|
308 traceTiny("stage","W");
|
rlm@8
|
309
|
rlm@8
|
310 dataRespQ.deq();
|
rlm@8
|
311 case ( dataRespQ.first() ) matches
|
rlm@8
|
312 tagged LoadResp .ld : rf.wr( truncate(ld.tag), ld.data );
|
rlm@8
|
313 tagged StoreResp .st : noAction;
|
rlm@8
|
314 endcase
|
rlm@8
|
315
|
rlm@8
|
316 stage <= PCgen;
|
rlm@8
|
317 endrule
|
rlm@8
|
318
|
rlm@8
|
319 rule inc_num_cycles;
|
rlm@8
|
320 if ( cp0_statsEn )
|
rlm@8
|
321 num_cycles <= num_cycles + 1;
|
rlm@8
|
322 endrule
|
rlm@8
|
323
|
rlm@8
|
324 //-----------------------------------------------------------
|
rlm@8
|
325 // Methods
|
rlm@8
|
326
|
rlm@8
|
327 interface Client imem_client;
|
rlm@8
|
328 interface Get request = fifoToGet(instReqQ);
|
rlm@8
|
329 interface Put response = fifoToPut(instRespQ);
|
rlm@8
|
330 endinterface
|
rlm@8
|
331
|
rlm@8
|
332 interface Client dmem_client;
|
rlm@8
|
333 interface Get request = fifoToGet(dataReqQ);
|
rlm@8
|
334 interface Put response = fifoToPut(dataRespQ);
|
rlm@8
|
335 endinterface
|
rlm@8
|
336
|
rlm@8
|
337 interface Get testrig_tohost = regToGet(cp0_tohost);
|
rlm@8
|
338 interface Put testrig_fromhost = regToPut(cp0_fromhost);
|
rlm@8
|
339 interface Get statsEn_get = regToGet(cp0_statsEn);
|
rlm@8
|
340
|
rlm@8
|
341 endmodule
|
rlm@8
|
342
|