-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcpu_functionblocks.ice
523 lines (502 loc) · 22.8 KB
/
cpu_functionblocks.ice
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
// RISC V INSTRUCTION DECODER
algorithm decode(
input uint32 instruction,
output uint5 opCode,
output uint3 function3,
output uint7 function7,
output uint5 rs1,
output uint5 rs2,
output uint5 rs3,
output uint5 rd,
output int32 immediateValue,
output uint1 AMO
) <autorun> {
always_after {
opCode = instruction[2,5];
AMO = ( instruction[2,5] == 5b01011 );
function3 = Rtype(instruction).function3;
function7 = Rtype(instruction).function7;
rs1 = Rtype(instruction).sourceReg1;
rs2 = Rtype(instruction).sourceReg2;
rs3 = R4type(instruction).sourceReg3;
rd = Rtype(instruction).destReg;
immediateValue = { {20{instruction[31,1]}}, Itype(instruction).immediate };
}
}
// DETERMINE IF MEMORY LOAD OR STORE
// AMO AND FLOAT LOAD/STORE ARE 32 BIT
algorithm memoryaccess(
input uint5 opCode,
input uint5 function7,
input uint3 function3,
input uint1 AMO,
output uint1 memoryload,
output uint1 memorystore,
output uint2 accesssize
) <autorun> {
uint1 FLOAD <:: opCode == 5b00001; uint1 FSTORE <:: opCode == 5b01001;
always_after {
memoryload = ( ~|opCode ) | FLOAD | ( AMO & ( function7 != 5b00011 ) );
memorystore = ( opCode == 5b01000 ) | FSTORE | ( AMO & ( function7 != 5b00010 ) );
accesssize = AMO | FLOAD | FSTORE ? 2b10 : function3[0,2];
}
}
// DETERMINE IF FAST OR SLOW INSTRUCTION
// SET CPU CONTROLS DEPENDING UPON INSTRUCTION TYPE
algorithm Iclass(
input uint5 opCode,
input uint3 function3,
input uint1 isALUM,
output uint1 frd,
output uint1 writeRegister,
output uint1 incPC,
output uint1 FASTPATH
) <autorun> {
// CHECK FOR FLOATING POINT, OR INTEGER DIVIDE
frd := 0; writeRegister := 1; incPC := 1; FASTPATH := 1;
always_after {
switch( opCode ) {
case 5b01101: {} // LUI
case 5b00101: {} // AUIPC
case 5b11011: { incPC = 0; } // JAL
case 5b11001: { incPC = 0; } // JALR
case 5b11000: { writeRegister = 0; } // BRANCH
case 5b00000: {} // LOAD
case 5b01000: { writeRegister = 0; } // STORE
case 5b00001: { frd = 1; } // FLOAT LOAD
case 5b01001: { writeRegister = 0; } // FLOAT STORE
case 5b00011: {} // FENCE[I]
case 5b11100: { FASTPATH = 0; } // CSR
case 5b01011: { FASTPATH = 0; } // LR.W SC.W ATOMIC LOAD - MODIFY - STORE
default: { FASTPATH = ~( opCode[4,1] | ( opCode[3,1] & isALUM & function3[2,1]) ); } // FPU OR INTEGER DIVIDE -> SLOWPATH ALL ELSE TO FASTPATH
}
}
}
// DETERMINE IN FAST OR SLOW FPU INSTRUCTION
algorithm Fclass(
input uint1 is2FPU,
input uint1 isFPUFAST,
output uint1 FASTPATHFPU
) <autorun> {
// FUSED OPERATIONS + CALCULATIONS & CONVERSIONS GO VIA SLOW PATH
// SIGN MANIPULATION, COMPARISONS + MIN/MAX, MOVE AND CLASSIFICATION GO VIA FAST PATH
always_after {
FASTPATHFPU = is2FPU & isFPUFAST; // is2FPU DETERMINES IF NORMAL OR FUSED, THEN isFPUFAST DETERMINES IF FAST OR SLOW
}
}
// PERFORM SIGN EXTENSION FOR 8 AND 16 BIT LOADS
algorithm signextend(
input uint16 readdata,
input uint1 is16or8,
input uint1 byteaccess,
input uint1 dounsigned,
output uint32 memory168
) <autorun> {
uint4 byteoffset <:: { byteaccess, 3b000 };
uint1 sign <:: ~dounsigned & ( is16or8 ? readdata[15,1] : readdata[ { byteaccess, 3b111 }, 1] );
always_after {
memory168 = is16or8 ? { {16{sign}}, readdata[0,16] } : { {24{sign}}, readdata[byteoffset, 8] };
}
}
// FIND THE ABSOLUTE VALUE FOR A SIGNED 32 BIT NUMBER
algorithm absolute(
input int32 number,
input int32 negative,
output int32 value
) <autorun> {
always_after {
value = number[31,1] ? negative : number;
}
}
// ADD 2 TO AN ADDRESS FOR 32 BIT LOAD/STORES
algorithm addrplus2(
input uint27 address,
output uint27 addressplus2
) <autorun> {
always_after {
addressplus2 = address + 2;
}
}
// RISC-V ADDRESS GENERATOR
algorithm addressgenerator(
input uint32 instruction,
input int32 immediateValue,
input uint27 PC,
input int32 sourceReg1,
output uint32 AUIPCLUI,
output uint27 branchAddress,
output uint27 jumpAddress,
output uint27 loadAddress,
output uint27 storeAddress,
input uint1 AMO
) <autorun> {
always_after {
AUIPCLUI = { Utype(instruction).immediate_bits_31_12, 12b0 } + ( instruction[5,1] ? 0 : PC );
branchAddress = { {20{Btype(instruction).immediate_bits_12}}, Btype(instruction).immediate_bits_11, Btype(instruction).immediate_bits_10_5, Btype(instruction).immediate_bits_4_1, 1b0 } + PC;
jumpAddress = { {12{Jtype(instruction).immediate_bits_20}}, Jtype(instruction).immediate_bits_19_12, Jtype(instruction).immediate_bits_11, Jtype(instruction).immediate_bits_10_1, 1b0 } + PC;
loadAddress = ( AMO ? 0 : immediateValue ) + sourceReg1;
storeAddress = ( AMO ? 0 : { {20{instruction[31,1]}}, Stype(instruction).immediate_bits_11_5, Stype(instruction).immediate_bits_4_0 } ) + sourceReg1;
}
}
// RISC-V SELECT THE NEXT INSTRUCTION BASED ON CPU STATE FLAGS
algorithm newpc(
input uint5 opCode,
input uint27 PC,
input uint1 compressed,
input uint1 incPC,
input uint1 takeBranch,
input uint27 branchAddress,
input uint27 jumpAddress,
input uint27 loadAddress,
output uint27 nextPC,
output uint27 newPC
) <autorun> {
always_after {
nextPC = PC + ( compressed ? 2 : 4 );
newPC = ( incPC ) ? ( takeBranch ? branchAddress : nextPC ) : ( opCode[1,1] ? jumpAddress : loadAddress );
}
}
// RISC-V REGISTERS
algorithm registers(
input uint1 SMT,
input uint5 rs,
input uint5 rd,
input uint1 write,
input uint32 result,
output uint32 contents
) <autorun> {
simple_dualport_bram int32 registers[64] = { 0, pad(uninitialized) };
registers.addr0 := { SMT, rs }; contents := registers.rdata0;
registers.addr1 := { SMT, rd }; registers.wdata1 := result;
registers.wenable1 := write;
}
// RISC-V REGISTERS - INTEGERS
algorithm registersI(
input uint1 SMT,
input uint5 rs1,
input uint5 rs2,
input uint5 rd,
input uint1 write,
input int32 result,
output int32 sourceReg1,
output int32 sourceReg2
) <autorun> {
// RISC-V REGISTERS
registers RS1( SMT <: SMT, rs <: rs1, rd <: rd, write <: write, result <: result, contents :> sourceReg1 );
registers RS2( SMT <: SMT, rs <: rs2, rd <: rd, write <: write, result <: result, contents :> sourceReg2 );
}
// RISC-V REGISTERS - FLOATING POINT
algorithm registersF(
input uint1 SMT,
input uint5 rs1,
input uint5 rs2,
input uint5 rs3,
input uint5 rd,
input uint1 write,
input int32 result,
output int32 sourceReg1,
output int32 sourceReg2,
output int32 sourceReg3
) <autorun> {
// RISC-V REGISTERS
registers RS1F( SMT <: SMT, rs <: rs1, rd <: rd, write <: write, result <: result, contents :> sourceReg1 );
registers RS2F( SMT <: SMT, rs <: rs2, rd <: rd, write <: write, result <: result, contents :> sourceReg2 );
registers RS3F( SMT <: SMT, rs <: rs3, rd <: rd, write <: write, result <: result, contents :> sourceReg3 );
}
// BRANCH COMPARISIONS
algorithm branchcomparison(
input uint3 function3,
input int32 sourceReg1,
input int32 sourceReg2,
output uint1 takeBranch
) <autorun> {
uint4 flags <:: { ( __unsigned(sourceReg1) < __unsigned(sourceReg2) ), ( __signed(sourceReg1) < __signed(sourceReg2) ), 1b0, ( sourceReg1 == sourceReg2 ) };
always_after {
takeBranch = function3[0,1] ^ flags[ function3[1,2], 1 ];
}
}
// COMPRESSED INSTRUCTION EXPANSION
algorithm compressed00(
input uint16 i16,
output uint30 i32
) <autorun> {
always_after {
if( |i16[13,3] ) {
if( i16[15,1] ) {
// SW -> sw rs2', offset[6:2](rs1') { 110 uimm[5:3] rs1' uimm[2][6] rs2' 00 } -> { imm[11:5] rs2 rs1 010 imm[4:0] 0100011 }
// FSW -> fsw rs2', offset[6:2](rs1') { 110 uimm[5:3] rs1' uimm[2][6] rs2' 00 } -> { imm[11:5] rs2 rs1 010 imm[4:0] 0100111 }
i32 = { 5b0, CS(i16).ib_6, CS(i16).ib_5, {2b01,CS(i16).rs2_alt}, {2b01,CS(i16).rs1_alt}, 3b010, CS(i16).ib_4_3, CS(i16).ib_2, 2b0, { 4b0100, i16[13,1] } };
} else {
// LW -> lw rd', offset[6:2](rs1') { 010 uimm[5:3] rs1' uimm[2][6] rd' 00 } -> { imm[11:0] rs1 010 rd 0000011 }
// FLW -> flw rd', offset[6:2](rs1') { 010 uimm[5:3] rs1' uimm[2][6] rd' 00 } -> { imm[11:0] rs1 010 rd 0000111 }
i32 = { 5b0, CL(i16).ib_6, CL(i16).ib_5_3, CL(i16).ib_2, 2b00, {2b01,CL(i16).rs1_alt}, 3b010, {2b01,CL(i16).rd_alt}, { 4b0000, i16[13,1] } };
}
} else {
// ADDI4SPN -> addi rd', x2, nzuimm[9:2] { 000, nzuimm[5:4|9:6|2|3] rd' 00 } -> { imm[11:0] rs1 000 rd 0010011 }
i32 = { 2b0, CIu94(i16).ib_9_6, CIu94(i16).ib_5_4, CIu94(i16).ib_3, CIu94(i16).ib_2, 2b00, 5h2, 3b000, {2b01,CIu94(i16).rd_alt}, 5b00100 };
}
}
}
algorithm compressed01(
input uint16 i16,
output uint30 i32
) <autorun> {
always_after {
switch( i16[13,3] ) {
case 3b000: {
// ADDI -> addi rd, rd, nzimm[5:0] { 000 nzimm[5] rs1/rd!=0 nzimm[4:0] 01 } -> { imm[11:0] rs1 000 rd 0010011 }
// NOP if rd == 0 and nzimm == 5b000000
i32 = { {7{CI50(i16).ib_5}}, CI50(i16).ib_4_0, CI50(i16).rd, 3b000, CI50(i16).rd, 5b00100 };
}
case 3b001: {
// JAL -> jal x1, offset[11:1] { 001, imm[11|4|9:8|10|6|7|3:1|5] 01 } -> { imm[20|10:1|11|19:12] rd 1101111 }
i32 = { CJ(i16).ib_11, CJ(i16).ib_10, CJ(i16).ib_9_8, CJ(i16).ib_7, CJ(i16).ib_6, CJ(i16).ib_5, CJ(i16).ib_4, CJ(i16).ib_3_1, {8{CJ(i16).ib_11}}, 5h1, 5b11011 };
}
case 3b010: {
// LI -> addi rd, x0, imm[5:0] { 010 imm[5] rd!=0 imm[4:0] 01 } -> { imm[11:0] rs1 000 rd 0010011 }
i32 = { {7{CI50(i16).ib_5}}, CI50(i16).ib_4_0, 5h0, 3b000, CI(i16).rd, 5b00100 };
}
case 3b011: {
if( CI(i16).rd == 2 ) {
// ADDI16SP -> addi x2, x2, nzimm[9:4] { 011 nzimm[9] 00010 nzimm[4|6|8:7|5] 01 } -> { imm[11:0] rs1 000 rd 0010011 }
i32 = { {3{CI94(i16).ib_9}}, CI94(i16).ib_8_7, CI94(i16).ib_6, CI94(i16).ib_5, CI94(i16).ib_4, 4b0000, 5h2, 3b000, 5h2, 5b00100 };
} else {
// LUI -> lui rd, nzuimm[17:12] { 011 nzimm[17] rd!={0,2} nzimm[16:12] 01 } -> { imm[31:12] rd 0110111 }
i32 = { {15{CIlui(i16).ib_17}}, CIlui(i16).ib_16_12, CIlui(i16).rd, 5b01101 };
}
}
case 3b100: {
// MISC-ALU
if( CBalu(i16).function2[1,1] ) {
if( CBalu(i16).function2[0,1] ) {
// CBalu(i16).logical2 -> SUB XOR OR AND
// 2b00 -> SUB -> sub rd', rd', rs2' { 100 0 11 rs1'/rd' 00 rs2' 01 } -> { 0100000 rs2 rs1 000 rd 0110011 }
// 2b01 -> XOR -> xor rd', rd', rs2' { 100 0 11 rs1'/rd' 01 rs2' 01 } -> { 0000000 rs2 rs1 100 rd 0110011 }
// 2b10 -> OR -> or rd', rd', rd2' { 100 0 11 rs1'/rd' 10 rs2' 01 } -> { 0000000 rs2 rs1 110 rd 0110011 }
// 2b11 -> AND -> and rd', rd', rs2' { 100 0 11 rs1'/rd' 11 rs2' 01 } -> { 0000000 rs2 rs1 111 rd 0110011 }
i32 = { { 1b0, ~|CBalu(i16).logical2, 5b00000 }, { 2b01, CBalu(i16).rs2_alt }, { 2b01, CBalu(i16).rd_alt },
( ^CBalu(i16).logical2 ) ? { 1b1, CBalu(i16).logical2[1,1], 1b0 } : {3{CBalu(i16).logical2[0,1]}}, { 2b01, CBalu(i16).rd_alt }, 5b01100 };
} else {
// ANDI -> andi rd', rd', imm[5:0] { 100 imm[5], 10 rs1'/rd' imm[4:0] 01 } -> { imm[11:0] rs1 111 rd 0010011 }
i32 = { {7{CBalu50(i16).ib_5}}, CBalu50(i16).ib_4_0, { 2b01, CBalu50(i16).rd_alt }, 3b111, { 2b01, CBalu50(i16).rd_alt }, 5b00100 };
}
} else {
// i16[10,1] -> SRLI SRAI
// 1b0 -> SRLI -> srli rd', rd', shamt[5:0] { 100 nzuimm[5] 00 rs1'/rd' nzuimm[4:0] 01 } -> { 0000000 shamt rs1 101 rd 0010011 }
// 1b1 -> SRAI -> srai rd', rd', shamt[5:0] { 100 nzuimm[5] 01 rs1'/rd' nzuimm[4:0] 01 } -> { 0100000 shamt rs1 101 rd 0010011 }
i32 = { { 1b0, i16[10,1], 5b00000 }, CBalu50(i16).ib_4_0, { 2b01, CBalu50(i16).rd_alt }, 3b101, { 2b01, CBalu50(i16).rd_alt }, 5b00100 };
}
}
case 3b101: {
// J -> jal, x0, offset[11:1] { 101, imm[11|4|9:8|10|6|7|3:1|5] 01 } -> { imm[20|10:1|11|19:12] rd 1101111 }
i32 = { CJ(i16).ib_11, CJ(i16).ib_10, CJ(i16).ib_9_8, CJ(i16).ib_7, CJ(i16).ib_6, CJ(i16).ib_5, CJ(i16).ib_4, CJ(i16).ib_3_1, {9{CJ(i16).ib_11}}, 5h0, 5b11011 };
}
default: {
// 3b110 -> BEQZ -> beq rs1', x0, offset[8:1] { 110, imm[8|4:3] rs1' imm[7:6|2:1|5] 01 } -> { imm[12|10:5] rs2 rs1 000 imm[4:1|11] 1100011 }
// 3b111 -> BNEZ -> bne rs1', x0, offset[8:1] { 111, imm[8|4:3] rs1' imm[7:6|2:1|5] 01 } -> { imm[12|10:5] rs2 rs1 001 imm[4:1|11] 1100011 }
i32 = { {4{CB(i16).offset_8}}, CB(i16).offset_7_6, CB(i16).offset_5, 5h0, {2b01,CB(i16).rs1_alt}, { 2b00, i16[13,1] }, CB(i16).offset_4_3, CB(i16).offset_2_1, CB(i16).offset_8, 5b11000 };
}
}
}
}
algorithm compressed10(
input uint16 i16,
output uint30 i32
) <autorun> {
always_after {
switch( i16[13,3] ) {
case 3b000: {
// SLLI -> slli rd, rd, shamt[5:0] { 000, nzuimm[5], rs1/rd!=0 nzuimm[4:0] 10 } -> { 0000000 shamt rs1 001 rd 0010011 }
i32 = { 7b0000000, CI50(i16).ib_4_0, CI50(i16).rd, 3b001, CI50(i16).rd, 5b00100 };
}
case 3b100: {
// J[AL]R / MV / ADD
if( ~|CR(i16).rs2 ) {
// JR -> jalr x0, rs1, 0 { 100 0 rs1 00000 10 } -> { imm[11:0] rs1 000 rd 1100111 }
// JALR -> jalr x1, rs1, 0 { 100 1 rs1 00000 10 } -> { imm[11:0] rs1 000 rd 1100111 }
i32 = { 12b0, CR(i16).rs1, 3b000, { 4b0000, i16[12,1]}, 5b11001 };
} else {
// MV -> add rd, x0, rs2 { 100 0 rd!=0 rs2!=0 10 } -> { 0000000 rs2 rs1 000 rd 0110011 }
// ADD -> add rd, rd, rs2 { 100 1 rs1/rd!=0 rs2!=0 10 } -> { 0000000 rs2 rs1 000 rd 0110011 }
i32 = { 7b0000000, CR(i16).rs2, i16[12,1] ? CR(i16).rs1 : 5h0, 3b000, CR(i16).rs1, 5b01100 };
}
}
default: {
if( i16[15,1] ) {
// SWSP -> sw rs2, offset[7:2](x2) { 110 uimm[5][4:2][7:6] rs2 10 } -> { imm[11:5] rs2 rs1 010 imm[4:0] 0100011 }
// FSWSP -> fsw rs2, offset[7:2](x2) { 110 uimm[5][4:2][7:6] rs2 10 } -> { imm[11:5] rs2 rs1 010 imm[4:0] 0100111 }
i32 = { 4b0, CSS(i16).ib_7_6, CSS(i16).ib_5, CSS(i16).rs2, 5h2, 3b010, CSS(i16).ib_4_2, 2b00, { 4b0100, i16[13,1] } };
} else {
// LWSP -> lw rd, offset[7:2](x2) { 011 uimm[5] rd uimm[4:2|7:6] 10 } -> { imm[11:0] rs1 010 rd 0000011 }
// FLWSP -> flw rd, offset[7:2](x2) { 011 uimm[5] rd uimm[4:2|7:6] 10 } -> { imm[11:0] rs1 010 rd 0000111 }
i32 = { 4b0, CI(i16).ib_7_6, CI(i16).ib_5, CI(i16).ib_4_2, 2b0, 5h2 ,3b010, CI(i16).rd, { 4b0000, i16[13,1] } };
}
}
}
}
}
// RISC-V MANDATORY CSR REGISTERS
algorithm counter40(
input uint1 update,
output uint40 counter(0)
) <autorun,reginputs> {
always_after {
counter = counter + update;
}
}
algorithm counter40always(
output uint40 counter(0)
) <autorun,reginputs> {
always_after {
counter = counter + 1;
}
}
algorithm csrf(
output uint8 CSRf(0),
input uint2 csr,
input uint8 writevalue,
input uint2 writetype,
input uint1 update,
input uint5 newflags
) <autorun,reginputs> {
always_after {
if( update ) {
CSRf = newflags;
} else {
switch( csr ) {
case 1: {
// CSRRW / CSRRWI
switch( writetype ) {
case 1: { CSRf[0,5] = writevalue[0,5]; }
case 2: { CSRf[5,3] = writevalue[0,3]; }
case 3: { CSRf = writevalue[0,8]; }
default: {}
}
}
case 2: {
// CSRRS / CSRRSI
switch( writetype ) {
case 1: { CSRf[0,5] = CSRf[0,5] | writevalue[0,5]; }
case 2: { CSRf[5,3] = CSRf[5,3] | writevalue[0,3]; }
case 3: { CSRf = CSRf | writevalue[0,8]; }
default: {}
}
}
case 3: {
// CSRRC / CSRRCI
switch( writetype ) {
case 1: { CSRf[0,5] = CSRf[0,5] & ~writevalue[0,5]; }
case 2: { CSRf[5,3] = CSRf[5,3] & ~writevalue[0,3]; }
case 3: { CSRf = CSRf & ~writevalue[0,8]; }
default: {}
}
}
default: {}
}
}
}
}
algorithm CSRblock(
input uint1 start,
input uint1 SMT,
input uint32 instruction,
input uint3 function3,
input uint5 rs1,
input uint32 sourceReg1,
input uint1 incCSRinstret,
input uint1 updateFPUflags,
input uint5 FPUnewflags,
output uint5 FPUflags,
output uint32 result
) <autorun,reginputs> {
// MAIN SYSTEM TIMER
counter40always TIMER();
// CPU HART CYCLE TIMERS
counter40 CYCLE(); counter40 CYCLESMT();
// CPU HART INSTRUCTION RETIRED COUNTERS
counter40 INSTRET(); counter40 INSTRETSMT();
// SWITCH BETWEEN IMMEDIATE OR REGISTER VALUE TO WRITE TO CSR
uint32 writevalue <:: function3[2,1] ? rs1 : sourceReg1;
// FLOATING-POINT CSR FOR BOTH THREADS
csrf CSRF0( csr <: instruction[20,2], writevalue <: writevalue ); // MAIN CSRf ( CSR(instruction).csr[0,2] )
csrf CSRF1( csr <: instruction[20,2], writevalue <: writevalue ); // SMT CSRf ( CSR(instruction).csr[0,2] )
// UPDATE FLAGS FOR TIMERS, COUNTERS AND FPU-FLAGS
CYCLE.update := ~SMT; CYCLESMT.update := SMT;
INSTRET.update := incCSRinstret & ~SMT; INSTRETSMT.update := incCSRinstret & SMT;
CSRF0.writetype := 0; CSRF1.writetype := 0; CSRF0.update := updateFPUflags & ~SMT; CSRF1.update := updateFPUflags & SMT;
// PASS PRESENT FPU FLAGS TO THE FPU
FPUflags := SMT ? CSRF1.CSRf[0,5] : CSRF0.CSRf[0,5];
always_after {
if( start ) {
result = 0;
switch( CSR(instruction).csr[8,4] ) {
case 4h0: {
switch( CSR(instruction).csr[0,2] ) {
case 2h1: { result = SMT ? CSRF1.CSRf[0,5] : CSRF0.CSRf[0,5]; } // frflags
case 2h2: { result = SMT ? CSRF1.CSRf[5,3] : CSRF0.CSRf[5,3]; } // frrm
case 2h3: { result = SMT ? CSRF1.CSRf : CSRF0.CSRf; } // frcsr
default: {}
}
}
case 4h3: { result = $CPUISA$; }
case 4hc: {
switch( { CSR(instruction).csr[7,1], CSR(instruction).csr[0,2] } ) {
case 5h00: { result = SMT ? CYCLESMT.counter[0,32] : CYCLE.counter[0,32]; }
case 5h10: { result = SMT ? CYCLESMT.counter[32,8] : CYCLE.counter[32,8]; }
case 5h01: { result = TIMER.counter[0,32]; }
case 5h11: { result = TIMER.counter[32,8]; }
case 5h02: { result = SMT ? INSTRETSMT.counter[0,32] : INSTRET.counter[0,32]; }
case 5h12: { result = SMT ? INSTRETSMT.counter[32,8] : INSTRET.counter[32,8]; }
default: {}
}
}
case 4hf: { result = SMT; } // HART ID
default: { result = 0; }
}
if( ~|CSR(instruction).csr[4,8] ) {
switch( function3[0,2] ) {
case 2b00: {
// ECALL / EBBREAK
}
case 2b01: {
// CSRRW / CSRRWI
switch( { ~|rs1, function3[2,1] } ) {
case 2b10: {}
default: {
if( SMT ) { CSRF1.writetype = 1; } else { CSRF0.writetype = 1; }
}
}
}
default: {
if( |rs1 ) {
if( SMT ) { CSRF1.writetype = function3[0,2]; } else { CSRF0.writetype = function3[0,2]; }
}
}
}
}
}
}
}
// ATOMIC A EXTENSION ALU
algorithm aluA (
input uint7 function7,
input uint32 memoryinput,
input uint32 sourceReg2,
output uint32 result
) <autorun> {
uint1 comparison <:: function7[3,1] ? ( __unsigned(memoryinput) < __unsigned(sourceReg2) ) : ( __signed(memoryinput) < __signed(sourceReg2) );
alulogic LOGIC( sourceReg1 <: memoryinput, operand2 <: sourceReg2 );
always_after {
if( function7[4,1] ) {
result = ( function7[2,1] ^ comparison ) ? memoryinput : sourceReg2; // AMOMAX[U] AMOMIN[U]
} else {
switch( function7[0,4] ) {
default: { result = memoryinput + sourceReg2; } // AMOADD
case 4b0001: { result = sourceReg2; } // AMOSWAP
case 4b0100: { result = LOGIC.XOR; } // AMOXOR
case 4b1000: { result = LOGIC.OR; } // AMOOR
case 4b1100: { result = LOGIC.AND; } // AMOAND
}
}
}
}