OpenCores
URL https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [cpu_fnc_plugin/] [riscv-ext-c.cpp] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 sergeykhbr
/**
2
 * @file
3
 * @copyright  Copyright 2017 GNSS Sensor Ltd. All right reserved.
4
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
5
 * @brief      RISC-V extension-C (Comporessed Instructions).
6
 */
7
 
8
#include "api_utils.h"
9
#include "riscv-isa.h"
10
#include "cpu_riscv_func.h"
11
 
12
namespace debugger {
13
 
14
/**
15
 * @brief Add register to register
16
 *
17
 * C.ADD adds the values in registers rd and rs2 and writes the result to
18
 * register rd. C.ADD expands into add rd, rd, rs2.
19
 */
20
class C_ADD : public RiscvInstruction16 {
21
public:
22
    C_ADD(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
23
        "C_ADD", "????????????????1001??????????10") {}
24
 
25
    virtual bool parse(uint32_t *payload) {
26
        ISA_CR_type u;
27
        u.value = static_cast<uint16_t>(payload[0]);
28
        return RiscvInstruction::parse(payload)
29
                && u.bits.rdrs1 && u.bits.rs2;
30
    }
31
 
32
    virtual int exec(Reg64Type *payload) {
33
        ISA_CR_type u;
34
        u.value = payload->buf16[0];
35
        if (u.bits.rdrs1) {
36
            R[u.bits.rdrs1] += R[u.bits.rs2];
37
        }
38
        return 2;
39
    }
40
};
41
 
42
/**
43
 * @brief Add immediate
44
 *
45
 * C.ADDI adds the non-zero sign-extended 6-bit immediate to the value in
46
 * register rd then writes the result to rd. C.ADDI expands into
47
 * addi rd, rd, nzimm[5:0].
48
 */
49
class C_ADDI : public RiscvInstruction16 {
50
public:
51
    C_ADDI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
52
        "C_ADDI", "????????????????000???????????01") {}
53
 
54
    virtual bool parse(uint32_t *payload) {
55
        ISA_CR_type u;
56
        u.value = static_cast<uint16_t>(payload[0]);
57
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
58
    }
59
 
60
    virtual int exec(Reg64Type *payload) {
61
        ISA_CI_type u;
62
        u.value = payload->buf16[0];
63
 
64
        uint64_t imm = u.bits.imm;
65
        if (u.bits.imm6) {
66
            imm |= EXT_SIGN_6;
67
        }
68
        R[u.bits.rdrs] = R[u.bits.rdrs] + imm;
69
        return 2;
70
    }
71
};
72
 
73
/**
74
 * @brief Stack-relative Add immediate
75
 *
76
 * C.ADDI16SP shares the opcode with C.LUI, but has a destination field of x2.
77
 * C.ADDI16SP adds the non-zero sign-extended 6-bit immediate to the value in
78
 * the stack pointer (sp=x2), where the immediate is scaled to represent
79
 * multiples of 16 in the range (-512,496). C.ADDI16SP is used to adjust the
80
 * stack pointer in procedure prologues and epilogues. It expands into
81
 * addi x2, x2, nzimm[9:4].
82
 */
83
class C_ADDI16SP : public RiscvInstruction16 {
84
public:
85
    C_ADDI16SP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
86
        "C_ADDI16SP", "????????????????011?00010?????01") {}
87
 
88
    virtual int exec(Reg64Type *payload) {
89
        ISA_CI_type u;
90
        u.value = payload->buf16[0];
91
 
92
        uint64_t imm = (u.spbits.imm8_7 << 3) | (u.spbits.imm6 << 2)
93
                    | (u.spbits.imm5 << 1) | u.spbits.imm4;
94
        if (u.spbits.imm9) {
95
            imm |= EXT_SIGN_6;
96
        }
97
        imm <<= 4;
98
        R[Reg_sp] = R[Reg_sp] + imm;
99
        return 2;
100
    }
101
};
102
 
103
/**
104
 * @brief Stack-relative Add wide immediate
105
 *
106
 * C.ADDI4SPN is a CIW-format RV32C/RV64C-only instruction that adds a
107
 * zero-extended non-zero immediate, scaled by 4, to the stack pointer, x2,
108
 * and writes the result to rd0. This instruction is used to generate
109
 * pointers to stack-allocated variables, and expands to
110
 * addi rd0, x2, zimm[9:2].
111
 */
112
class C_ADDI4SPN : public RiscvInstruction16 {
113
public:
114
    C_ADDI4SPN(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
115
        "C_ADDI4SPN", "????????????????000???????????00") {}
116
 
117
    virtual int exec(Reg64Type *payload) {
118
        ISA_CIW_type u;
119
        u.value = payload->buf16[0];
120
 
121
        uint64_t imm = (u.bits.imm9_6 << 4) | (u.bits.imm5_4 << 2)
122
                    | (u.bits.imm3 << 1) | u.bits.imm2;
123
        imm <<= 2;
124
        R[8 + u.bits.rd] = R[Reg_sp] + imm;
125
        return 2;
126
    }
127
};
128
 
129
/**
130
 * @brief Add immediate with sign extending
131
 *
132
 * C.ADDIW is an RV64C/RV128C-only instruction that performs the same
133
 * computation but produces a 32-bit result, then sign-extends result
134
 * to 64 bits. C.ADDIW expands into addiw rd, rd, imm[5:0]. The immediate
135
 * can be zero for C.ADDIW, where this corresponds to sext.w rd.
136
 */
137
class C_ADDIW : public RiscvInstruction16 {
138
public:
139
    C_ADDIW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
140
        "C_ADDIW", "????????????????001???????????01") {}
141
 
142
    virtual bool parse(uint32_t *payload) {
143
        ISA_CR_type u;
144
        u.value = static_cast<uint16_t>(payload[0]);
145
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
146
    }
147
 
148
    virtual int exec(Reg64Type *payload) {
149
        ISA_CI_type u;
150
        u.value = payload->buf16[0];
151
 
152
        uint64_t imm = u.bits.imm;
153
        if (u.bits.imm6) {
154
            imm |= EXT_SIGN_6;
155
        }
156
        R[u.bits.rdrs] = (R[u.bits.rdrs] + imm) & 0xFFFFFFFFLL;
157
        if (R[u.bits.rdrs] & (1LL << 31)) {
158
            R[u.bits.rdrs] |= EXT_SIGN_32;
159
        }
160
        return 2;
161
    }
162
};
163
 
164
/**
165
 * @brief C_ADDW
166
 *
167
 * C.ADDW is an RV64C/RV128C-only instruction that adds the values in registers
168
 * rd' and rs2', then sign-extends the lower 32 bits of the sum before writing
169
 * the result to register rd'. C.ADDW expands into addw rd', rd', rs2'.
170
 */
171
class C_ADDW : public RiscvInstruction16 {
172
public:
173
    C_ADDW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
174
        "C_ADDW", "????????????????100111???01???01") {}
175
 
176
    virtual int exec(Reg64Type *payload) {
177
        ISA_CS_type u;
178
        u.value = payload->buf16[0];
179
        R[8 + u.bits.rs1] += R[8 + u.bits.rs2];
180
        R[8 + u.bits.rs1] &= 0xFFFFFFFFLL;
181
 
182
        if (R[8 + u.bits.rs1] & (1LL << 31)) {
183
            R[8 + u.bits.rs1] |= EXT_SIGN_32;
184
        }
185
        return 2;
186
    }
187
};
188
 
189
 
190
/**
191
 * @brief C_AND
192
 *
193
 * C.AND computes the bitwise AND of the values in registers rd' and rs2', then
194
 * writes the result to register rd'. C.AND expands into and rd', rd', rs2'.
195
 */
196
class C_AND : public RiscvInstruction16 {
197
public:
198
    C_AND(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
199
        "C_AND", "????????????????100011???11???01") {}
200
 
201
    virtual int exec(Reg64Type *payload) {
202
        ISA_CS_type u;
203
        u.value = payload->buf16[0];
204
        R[8 + u.bits.rs1] &= R[8 + u.bits.rs2];
205
        return 2;
206
    }
207
};
208
 
209
/**
210
 * @brief AND with sign-extended immediate
211
 *
212
 * C.ANDI is a CB-format instruction that computes the bitwise AND of the
213
 * value in register rd' and the sign-extended 6-bit immediate, then writes
214
 * the result to rd'. C.ANDI expands to andi rd', rd', imm[5:0].
215
 */
216
class C_ANDI : public RiscvInstruction16 {
217
public:
218
    C_ANDI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
219
        "C_ANDI", "????????????????100?10????????01") {}
220
 
221
    virtual int exec(Reg64Type *payload) {
222
        ISA_CB_type u;
223
        u.value = payload->buf16[0];
224
 
225
        uint64_t imm = (u.bits.off7_6 << 3) | (u.bits.off2_1 << 1)  | u.bits.off5;
226
        if (u.bits.off8) {
227
            imm |= EXT_SIGN_5;
228
        }
229
        R[8 + u.bits.rs1] &= imm;
230
        return 2;
231
    }
232
};
233
 
234
/**
235
 * @brief Branch if registers zero
236
 *
237
 * C.BEQZ performs conditional control transfers. The offset is sign-extended
238
 * and added to the pc to form the branch target address. It can therefore
239
 * target a 256B range. C.BEQZ takes the branch if the value in register rs1'
240
 *  is zero. It expands to beq rs1', x0, offset[8:1].
241
 */
242
class C_BEQZ : public RiscvInstruction16 {
243
public:
244
    C_BEQZ(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
245
        "C_BEQZ", "????????????????110???????????01") {}
246
 
247
    virtual int exec(Reg64Type *payload) {
248
        ISA_CB_type u;
249
        u.value = payload->buf32[0];
250
 
251
        if (R[8 + u.bits.rs1] == 0) {
252
            uint64_t imm = (u.bits.off7_6 << 5) | (u.bits.off5 << 4)
253
                    | (u.bits.off4_3 << 2) | u.bits.off2_1;
254
            imm <<= 1;
255
            if (u.bits.off8) {
256
                imm |= EXT_SIGN_9;
257
            }
258
            icpu_->setBranch(icpu_->getPC() + imm);
259
        }
260
        return 2;
261
    }
262
};
263
 
264
 
265
/**
266
 * @brief Branch if registers not zero
267
 *
268
 * C.BNEZ is defined analogously, but it takes the branch if rs1' contains a
269
 * nonzero value. It expands to bne rs1', x0, offset[8:1].
270
 */
271
class C_BNEZ : public RiscvInstruction16 {
272
public:
273
    C_BNEZ(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
274
        "C_BNEZ", "????????????????111???????????01") {}
275
 
276
    virtual int exec(Reg64Type *payload) {
277
        ISA_CB_type u;
278
        u.value = payload->buf32[0];
279
 
280
        if (R[8 + u.bits.rs1]) {
281
            uint64_t imm = (u.bits.off7_6 << 5) | (u.bits.off5 << 4)
282
                    | (u.bits.off4_3 << 2) | u.bits.off2_1;
283
            imm <<= 1;
284
            if (u.bits.off8) {
285
                imm |= EXT_SIGN_9;
286
            }
287
            icpu_->setBranch(icpu_->getPC() + imm);
288
        }
289
        return 2;
290
    }
291
};
292
 
293
/**
294
 * @brief C.EBREAK (breakpoint instruction)
295
 *
296
 * The C.EBREAK instruction is used by debuggers to cause control to be
297
 * transferred back to a debug-ging environment.
298
 */
299
class C_EBREAK : public RiscvInstruction16 {
300
public:
301
    C_EBREAK(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
302
        "C_EBREAK", "????????????????1001000000000010") {}
303
 
304
    virtual int exec(Reg64Type *payload) {
305
        icpu_->raiseSignal(EXCEPTION_Breakpoint);
306
        return 2;
307
    }
308
};
309
 
310
 
311
/**
312
 * @brief Unconditional jump
313
 *
314
 * C.J performs an unconditional control transfer. The offset is sign-extended
315
 *  and added to the pc to form the jump target address. C.J can therefore
316
 * target a 2 KiB range. C.J expands to jal x0, offset[11:1].
317
 */
318
class C_J : public RiscvInstruction16 {
319
public:
320
    C_J(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
321
        "C_J", "????????????????101???????????01") {}
322
 
323
    virtual int exec(Reg64Type *payload) {
324
        ISA_CJ_type u;
325
        u.value = payload->buf16[0];
326
        uint64_t off = (u.bits.off10 << 9) | (u.bits.off9_8 << 7)
327
                     | (u.bits.off7 << 6) | (u.bits.off6 << 5)
328
                     | (u.bits.off5 << 4) | (u.bits.off4 << 3)
329
                     | u.bits.off3_1;
330
        off <<= 1;
331
        if (u.bits.off11) {
332
            off |= EXT_SIGN_11;
333
        }
334
        icpu_->setBranch(icpu_->getPC() + off);
335
        return 2;
336
    }
337
};
338
 
339
#ifdef RV32C_ONLY  // conflict with C_ADDIW
340
/**
341
 * @brief Unconditional jump with write to ra
342
 *
343
 * C.JAL is an RV32C-only instruction that performs the same operation as C.J,
344
 * but additionally writes the address of the instruction following the jump
345
 * (pc+2) to the link register, x1. C.JAL expands to jal x1, offset[11:1].
346
 */
347
class C_JAL : public RiscvInstruction16 {
348
public:
349
    C_JAL(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
350
        "C_JAL", "????????????????001???????????01") {}
351
 
352
    virtual int exec(Reg64Type *payload) {
353
        ISA_CJ_type u;
354
        u.value = payload->buf16[0];
355
        uint64_t off = (u.bits.off10 << 9) | (u.bits.off9_8 << 7)
356
                     | (u.bits.off7 << 6) | (u.bits.off6 << 5)
357
                     | (u.bits.off5 << 4) | (u.bits.off4 << 3)
358
                     | u.bits.off3_1;
359
        off <<= 1;
360
        if (u.bits.off11) {
361
            off |= EXT_SIGN_11;
362
        }
363
        R[Reg_ra] = icpu_->getPC() + 2;
364
        icpu_->setBranch(icpu_->getPC() + off);
365
        icpu_->pushStackTrace();
366
        return 2;
367
    }
368
};
369
#endif
370
 
371
/**
372
 * @brief Unconditional jump with write to ra
373
 *
374
 * C.JALR (jump and link register) performs the same operation as C.JR, but
375
 * additionally writes the address of the instruction following the jump (pc+2)
376
 * to the link register, x1. C.JALR expands to jalr x1, rs1, 0.
377
 */
378
class C_JALR : public RiscvInstruction16 {
379
public:
380
    C_JALR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
381
        "C_JALR", "????????????????1001?????0000010") {}
382
 
383
    virtual bool parse(uint32_t *payload) {
384
        ISA_CR_type u;
385
        u.value = static_cast<uint16_t>(payload[0]);
386
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
387
    }
388
 
389
    virtual int exec(Reg64Type *payload) {
390
        ISA_CR_type u;
391
        u.value = payload->buf16[0];
392
        R[Reg_ra] = icpu_->getPC() + 2;
393
        icpu_->setBranch(R[u.bits.rdrs1]);
394
        icpu_->pushStackTrace();
395
        return 2;
396
    }
397
};
398
 
399
/**
400
 * @brief Unconditional jump
401
 *
402
 * C.JR (jump register) performs an unconditional control transfer to the
403
 * address in register rs1. C.JR expands to jalr x0, rs1, 0.
404
 */
405
class C_JR : public RiscvInstruction16 {
406
public:
407
    C_JR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
408
        "C_JR", "????????????????1000?????0000010") {}
409
 
410
    virtual bool parse(uint32_t *payload) {
411
        ISA_CR_type u;
412
        u.value = static_cast<uint16_t>(payload[0]);
413
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
414
    }
415
 
416
    virtual int exec(Reg64Type *payload) {
417
        ISA_CR_type u;
418
        u.value = payload->buf16[0];
419
        icpu_->setBranch(R[u.bits.rdrs1]);
420
        if (u.bits.rdrs1 == Reg_ra) {
421
            icpu_->popStackTrace();
422
        }
423
        return 2;
424
    }
425
};
426
 
427
/**
428
 * @brief LOAD instructions with sign extending.
429
 *
430
 * C.LD is an RV64C/RV128C-only instruction that loads a 64-bit value from
431
 * memory into register rd0. It computes an eective address by adding the
432
 * zero-extended oset, scaled by 8, to the base address in register rs10.
433
 * It expands to ld rd0, offset[7:3](rs10).
434
 */
435
class C_LD : public RiscvInstruction16 {
436
public:
437
    C_LD(CpuRiver_Functional *icpu) :
438
        RiscvInstruction16(icpu, "C_LD", "????????????????011???????????00") {}
439
 
440
    virtual int exec(Reg64Type *payload) {
441
        Axi4TransactionType trans;
442
        ISA_CL_type u;
443
        u.value = payload->buf16[0];
444
        uint64_t off = (u.bits.imm27 << 4) | (u.bits.imm6 << 3)
445
                     | u.bits.imm5_3;
446
        off <<= 3;
447
        trans.action = MemAction_Read;
448
        trans.addr = R[8 + u.bits.rs1] + off;
449
        trans.xsize = 8;
450
        if (trans.addr & 0x7) {
451
            trans.rpayload.b64[0] = 0;
452
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
453
        } else {
454
            icpu_->dma_memop(&trans);
455
        }
456
        R[8 + u.bits.rd] = trans.rpayload.b64[0];
457
        return 2;
458
    }
459
};
460
 
461
/**
462
 * @brief LOAD stack-relative dword.
463
 *
464
 * C.LDSP is an RV64C/RV128C-only instruction that loads a 64-bit value from
465
 * memory into register rd. It computes its eective address by adding the
466
 * zero-extended oset, scaled by 8, to the stack pointer, x2.
467
 * It expands to ld rd, offset[8:3](x2).
468
 */
469
class C_LDSP : public RiscvInstruction16 {
470
public:
471
    C_LDSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
472
        "C_LDSP", "????????????????011???????????10") {}
473
 
474
    virtual bool parse(uint32_t *payload) {
475
        ISA_CR_type u;
476
        u.value = static_cast<uint16_t>(payload[0]);
477
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
478
    }
479
 
480
    virtual int exec(Reg64Type *payload) {
481
        Axi4TransactionType trans;
482
        ISA_CI_type u;
483
        u.value = payload->buf16[0];
484
        uint64_t off = (u.ldspbits.off8_6 << 3) | (u.ldspbits.off5 << 2)
485
                     | u.ldspbits.off4_3;
486
        off <<= 3;
487
        trans.action = MemAction_Read;
488
        trans.addr = R[Reg_sp] + off;
489
        trans.xsize = 8;
490
        if (trans.addr & 0x7) {
491
            trans.rpayload.b64[0] = 0;
492
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
493
        } else {
494
            icpu_->dma_memop(&trans);
495
        }
496
        R[u.ldspbits.rd] = trans.rpayload.b64[0];
497
        return 2;
498
    }
499
};
500
 
501
/**
502
 * @brief Constant generation
503
 *
504
 * C.LI loads the sign-extended 6-bit immediate, imm, into register rd. C.LI is
505
 * only valid when rd /= x0. C.LI expands into addi rd, x0, imm[5:0].
506
 */
507
class C_LI : public RiscvInstruction16 {
508
public:
509
    C_LI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
510
        "C_LI", "????????????????010???????????01") {}
511
 
512
    virtual bool parse(uint32_t *payload) {
513
        ISA_CR_type u;
514
        u.value = static_cast<uint16_t>(payload[0]);
515
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
516
    }
517
 
518
    virtual int exec(Reg64Type *payload) {
519
        ISA_CI_type u;
520
        u.value = payload->buf16[0];
521
 
522
        uint64_t imm = u.bits.imm;
523
        if (u.bits.imm6) {
524
            imm |= EXT_SIGN_6;
525
        }
526
        R[u.bits.rdrs] = imm;
527
        return 2;
528
    }
529
};
530
 
531
/**
532
 * @brief LOAD instructions with sign extending.
533
 *
534
 * C.LW loads a 32-bit value from memory into register rd0. It computes an
535
 * effective address by adding the zero-extended offset, scaled by 4, to the
536
 * base address in register rs10. It expands to lw rd0, offset[6:2](rs10).
537
 */
538
class C_LW : public RiscvInstruction16 {
539
public:
540
    C_LW(CpuRiver_Functional *icpu) :
541
        RiscvInstruction16(icpu, "C_LW", "????????????????010???????????00") {}
542
 
543
    virtual int exec(Reg64Type *payload) {
544
        Axi4TransactionType trans;
545
        ISA_CL_type u;
546
        u.value = payload->buf16[0];
547
        uint64_t off = (u.bits.imm6 << 4) | (u.bits.imm5_3 << 1) | u.bits.imm27;
548
        off <<= 2;
549
        trans.action = MemAction_Read;
550
        trans.addr = R[8 + u.bits.rs1] + off;
551
        trans.xsize = 4;
552
        trans.rpayload.b64[0] = 0;
553
        if (trans.addr & 0x3) {
554
            trans.rpayload.b64[0] = 0;
555
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
556
        } else {
557
            icpu_->dma_memop(&trans);
558
        }
559
        R[8 + u.bits.rd] = trans.rpayload.b32[0];
560
        if (R[8 + u.bits.rd] & (1LL << 31)) {
561
            R[8 + u.bits.rd] |= EXT_SIGN_32;
562
        }
563
        return 2;
564
    }
565
};
566
 
567
/**
568
 * @brief LOAD stack-relative word.
569
 *
570
 * C.LWSP loads a 32-bit value from memory into register rd. It computes
571
 * an eective address by adding the zero-extended oset, scaled by 4, to the
572
 * stack pointer, x2. It expands to lw rd, offset[7:2](x2).
573
 */
574
class C_LWSP : public RiscvInstruction16 {
575
public:
576
    C_LWSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
577
        "C_LWSP", "????????????????010???????????10") {}
578
 
579
    virtual bool parse(uint32_t *payload) {
580
        ISA_CR_type u;
581
        u.value = static_cast<uint16_t>(payload[0]);
582
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
583
    }
584
 
585
    virtual int exec(Reg64Type *payload) {
586
        Axi4TransactionType trans;
587
        ISA_CI_type u;
588
        u.value = payload->buf16[0];
589
        uint64_t off = (u.lwspbits.off7_6 << 4) | (u.lwspbits.off5 << 3)
590
                     | u.lwspbits.off4_2;
591
        off <<= 2;
592
        trans.action = MemAction_Read;
593
        trans.addr = R[Reg_sp] + off;
594
        trans.xsize = 4;
595
        if (trans.addr & 0x3) {
596
            trans.rpayload.b64[0] = 0;
597
            icpu_->raiseSignal(EXCEPTION_LoadMisalign);
598
        } else {
599
            icpu_->dma_memop(&trans);
600
        }
601
        R[u.lwspbits.rd] = trans.rpayload.b32[0];
602
        if (R[u.lwspbits.rd] & (1LL << 31)) {
603
            R[u.lwspbits.rd] |= EXT_SIGN_32;
604
        }
605
        return 2;
606
    }
607
};
608
 
609
/**
610
 * @brief Constant generation
611
 *
612
 * C.LUI loads the non-zero 6-bit immediate eld into bits 17-12 of the
613
 * destination register, clears the bottom 12 bits, and sign-extends
614
 * bit 17 into all higher bits of the destination. C.LUI is only
615
 * valid when rd /= {x0; x2}, and when the immediate is not equal to zero.
616
 * C.LUI expands into lui rd, nzuimm[17:12].
617
 */
618
class C_LUI : public RiscvInstruction16 {
619
public:
620
    C_LUI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
621
        "C_LUI", "????????????????011???????????01") {}
622
 
623
    virtual bool parse(uint32_t *payload) {
624
        ISA_CR_type u;
625
        u.value = static_cast<uint16_t>(payload[0]);
626
        return RiscvInstruction::parse(payload) && u.bits.rdrs1
627
            && u.bits.rdrs1 != Reg_sp;
628
    }
629
 
630
    virtual int exec(Reg64Type *payload) {
631
        ISA_CI_type u;
632
        u.value = payload->buf16[0];
633
 
634
        uint64_t imm = u.bits.imm;
635
        if (u.bits.imm6) {
636
            imm |= EXT_SIGN_6;
637
        }
638
        imm <<= 12;
639
        R[u.bits.rdrs] = imm;
640
        return 2;
641
    }
642
};
643
 
644
/**
645
 * @brief Move register to register
646
 *
647
 * C.MV copies the value in register rs2 into register rd. C.MV expands
648
 * into add rd, x0, rs2.
649
 */
650
class C_MV : public RiscvInstruction16 {
651
public:
652
    C_MV(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
653
        "C_MV", "????????????????1000??????????10") {}
654
 
655
    virtual bool parse(uint32_t *payload) {
656
        ISA_CR_type u;
657
        u.value = static_cast<uint16_t>(payload[0]);
658
        return RiscvInstruction::parse(payload)
659
            && u.bits.rs2 && u.bits.rdrs1;
660
    }
661
 
662
    virtual int exec(Reg64Type *payload) {
663
        ISA_CR_type u;
664
        u.value = payload->buf16[0];
665
        R[u.bits.rdrs1] = R[u.bits.rs2];
666
        return 2;
667
    }
668
};
669
 
670
/**
671
 * @brief empty cycle
672
 */
673
class C_NOP : public RiscvInstruction16 {
674
public:
675
    C_NOP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
676
        "C_NOP", "????????????????0000000000000001") {}
677
 
678
    virtual bool parse(uint32_t *payload) {
679
        return RiscvInstruction::parse(payload);
680
    }
681
 
682
    virtual int exec(Reg64Type *payload) {
683
        return 2;
684
    }
685
};
686
 
687
 
688
/**
689
 * @brief C_OR
690
 *
691
 * C.OR computes the bitwise OR of the values in registers rd' and rs2', then
692
 * writes the result to register rd'. C.OR expands into or rd', rd', rs2'.
693
 */
694
class C_OR : public RiscvInstruction16 {
695
public:
696
    C_OR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
697
        "C_OR", "????????????????100011???10???01") {}
698
 
699
    virtual int exec(Reg64Type *payload) {
700
        ISA_CS_type u;
701
        u.value = payload->buf16[0];
702
        R[8 + u.bits.rs1] |= R[8 + u.bits.rs2];
703
        return 2;
704
    }
705
};
706
 
707
/**
708
 * @brief Store 64-bits data
709
 *
710
 * C.SD is an RV64C/RV128C-only instruction that stores a 64-bit value in
711
 * register rs20 to memory. It computes an eective address by adding the
712
 * zero-extended oset, scaled by 8, to the base address in register rs10. It
713
 * expands to sd rs20, offset[7:3](rs10).
714
 */
715
class C_SD : public RiscvInstruction16 {
716
public:
717
    C_SD(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
718
        "C_SD", "????????????????111???????????00") {}
719
 
720
    virtual int exec(Reg64Type *payload) {
721
        Axi4TransactionType trans;
722
        ISA_CS_type u;
723
        u.value = payload->buf16[0];
724
        uint64_t off = (u.bits.imm27 << 4) | (u.bits.imm6 << 3) | u.bits.imm5_3;
725
        off <<= 3;
726
        trans.action = MemAction_Write;
727
        trans.xsize = 8;
728
        trans.wstrb = (1 << trans.xsize) - 1;
729
        trans.addr = R[8 + u.bits.rs1] + off;
730
        trans.wpayload.b64[0] = R[8 + u.bits.rs2];
731
        if (trans.addr & 0x7) {
732
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
733
        } else {
734
            icpu_->dma_memop(&trans);
735
        }
736
        return 2;
737
    }
738
};
739
 
740
/**
741
 * @brief Stack-relative Store 64-bits data
742
 *
743
 * C.SDSP is an RV64C/RV128C-only instruction that stores a 64-bit value
744
 * in register rs2 to memory. It computes an eective address by adding the
745
 * zero-extended oset, scaled by 8, to the stack pointer, x2. It expands
746
 * to sd rs2, offset[8:3](x2).
747
 */
748
class C_SDSP : public RiscvInstruction16 {
749
public:
750
    C_SDSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
751
        "C_SDSP", "????????????????111???????????10") {}
752
 
753
    virtual int exec(Reg64Type *payload) {
754
        Axi4TransactionType trans;
755
        ISA_CSS_type u;
756
        u.value = payload->buf16[0];
757
        uint64_t off = (u.dbits.imm8_6 << 3) | u.dbits.imm5_3;
758
        off <<= 3;
759
        trans.action = MemAction_Write;
760
        trans.xsize = 8;
761
        trans.wstrb = (1 << trans.xsize) - 1;
762
        trans.addr = R[Reg_sp] + off;
763
        trans.wpayload.b64[0] = R[u.dbits.rs2];
764
        if (trans.addr & 0x7) {
765
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
766
        } else {
767
            icpu_->dma_memop(&trans);
768
        }
769
        return 2;
770
    }
771
};
772
 
773
/**
774
 * @brief Logical shift left
775
 *
776
 * C.SLLI is a CI-format instruction that performs a logical left shift
777
 * of the value in register rd then writes the result to rd. The shift amount
778
 * is encoded in the shamt eld, where shamt[5] must be zero for RV32C.
779
 * For RV32C and RV64C, the shift amount must be non-zero. For RV128C, a shift
780
 * amount of zero is used to encode a shift of 64. C.SLLI expands into
781
 * slli rd, rd, shamt[5:0], except for RV128C with shamt=0, which expands
782
 * to slli rd, rd, 64.
783
 */
784
class C_SLLI : public RiscvInstruction16 {
785
public:
786
    C_SLLI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
787
        "C_SLLI", "????????????????000???????????10") {}
788
 
789
    virtual bool parse(uint32_t *payload) {
790
        ISA_CR_type u;
791
        u.value = static_cast<uint16_t>(payload[0]);
792
        return RiscvInstruction::parse(payload) && u.bits.rdrs1;
793
    }
794
 
795
    virtual int exec(Reg64Type *payload) {
796
        ISA_CB_type u;
797
        u.value = payload->buf16[0];
798
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
799
        uint32_t idx = (u.shbits.funct2 << 3) | u.shbits.rd;
800
        R[idx] = R[idx] << shamt;
801
        return 2;
802
    }
803
};
804
 
805
/**
806
 * @brief Arith shift right
807
 *
808
 * C.SRAI is defined analogously to C.SRLI, but instead performs an arithmetic
809
 * right shift. C.SRAI expands to srai rd', rd', shamt[5:0].
810
 */
811
class C_SRAI : public RiscvInstruction16 {
812
public:
813
    C_SRAI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
814
        "C_SRAI", "????????????????100?01????????01") {}
815
 
816
    virtual int exec(Reg64Type *payload) {
817
        ISA_CB_type u;
818
        u.value = payload->buf16[0];
819
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
820
        R[8 + u.shbits.rd] = static_cast<int64_t>(R[8 + u.shbits.rd]) >> shamt;
821
        return 2;
822
    }
823
};
824
 
825
/**
826
 * @brief Logical shift right
827
 *
828
 * C.SRLI is a CB-format instruction that performs a logical right shift of
829
 * the value in register rd' then writes the result to rd'. The shift amount
830
 * is encoded in the shamt field, where shamt[5] must be zero for RV32C.
831
 * For RV32C and RV64C, the shift amount must be non-zero. For RV128C, a shift
832
 * amount of zero is used to encode a shift of 64. Furthermore, the shift
833
 * amount is sign-extended for RV128C, and so the legal shift amounts are
834
 * 1-31, 64, and 96-127. C.SRLI expands into srli rd0, rd0, shamt[5:0],
835
 * except for RV128C with shamt=0, which expands to srli rd0, rd0, 64.
836
 */
837
class C_SRLI : public RiscvInstruction16 {
838
public:
839
    C_SRLI(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
840
        "C_SRLI", "????????????????100?00????????01") {}
841
 
842
    virtual int exec(Reg64Type *payload) {
843
        ISA_CB_type u;
844
        u.value = payload->buf16[0];
845
        uint32_t shamt = (u.shbits.shamt5 << 5) | u.shbits.shamt;
846
        R[8 + u.shbits.rd] = R[8 + u.shbits.rd] >> shamt;
847
        return 2;
848
    }
849
};
850
 
851
/**
852
 * @brief C_SUB
853
 *
854
 * C.SUB subtracts the value in register rs2' from the value in register rd',
855
 * then writes the result to register rd'. C.SUB expands into
856
 * sub rd', rd', rs2'.
857
 */
858
class C_SUB : public RiscvInstruction16 {
859
public:
860
    C_SUB(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
861
        "C_SUB", "????????????????100011???00???01") {}
862
 
863
    virtual int exec(Reg64Type *payload) {
864
        ISA_CS_type u;
865
        u.value = payload->buf16[0];
866
        R[8 + u.bits.rs1] -= R[8 + u.bits.rs2];
867
        return 2;
868
    }
869
};
870
 
871
/**
872
 * @brief C_SUBW
873
 *
874
 * C.SUBW is an RV64C/RV128C-only instruction that subtracts the value in
875
 * register rs2' from the value in register rd', then sign-extends the lower
876
 * 32 bits of the difference before writing the result to register rd'.
877
 * C.SUBW expands into subw rd', rd', rs2'.
878
 */
879
class C_SUBW : public RiscvInstruction16 {
880
public:
881
    C_SUBW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
882
        "C_SUBW", "????????????????100111???00???01") {}
883
 
884
    virtual int exec(Reg64Type *payload) {
885
        ISA_CS_type u;
886
        u.value = payload->buf16[0];
887
        R[8 + u.bits.rs1] -= R[8 + u.bits.rs2];
888
        R[8 + u.bits.rs1] &= 0xFFFFFFFFLL;
889
 
890
        if (R[8 + u.bits.rs1] & (1LL << 31)) {
891
            R[8 + u.bits.rs1] |= EXT_SIGN_32;
892
        }
893
        return 2;
894
    }
895
};
896
 
897
/**
898
 * @brief Store word
899
 *
900
 * C.SW stores a 32-bit value in register rs20 to memory. It computes an
901
 * effective address by adding the zero-extended oset, scaled by 4, to the
902
 * base address in register rs10. It expands to sw rs20, offset[6:2](rs10).
903
 */
904
class C_SW : public RiscvInstruction16 {
905
public:
906
    C_SW(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
907
        "C_SW", "????????????????110???????????00") {}
908
 
909
    virtual int exec(Reg64Type *payload) {
910
        Axi4TransactionType trans;
911
        ISA_CS_type u;
912
        u.value = payload->buf16[0];
913
        uint64_t off = (u.bits.imm6 << 4) | (u.bits.imm5_3 << 1) | u.bits.imm27;
914
        off <<= 2;
915
        trans.action = MemAction_Write;
916
        trans.xsize = 4;
917
        trans.wstrb = (1 << trans.xsize) - 1;
918
        trans.addr = R[8 + u.bits.rs1] + off;
919
        trans.wpayload.b64[0] = R[8 + u.bits.rs2];
920
        if (trans.addr & 0x3) {
921
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
922
        } else {
923
            icpu_->dma_memop(&trans);
924
        }
925
        return 2;
926
    }
927
};
928
 
929
/**
930
 * @brief Stack-relative Store word
931
 *
932
 * C.SWSP stores a 32-bit value in register rs2 to memory. It computes an
933
 * effective address by adding the zero-extended oset, scaled by 4, to the
934
 * stack pointer, x2. It expands to sw rs2, offset[7:2](x2).
935
 */
936
class C_SWSP : public RiscvInstruction16 {
937
public:
938
    C_SWSP(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
939
        "C_SWSP", "????????????????110???????????10") {}
940
 
941
    virtual int exec(Reg64Type *payload) {
942
        Axi4TransactionType trans;
943
        ISA_CSS_type u;
944
        u.value = payload->buf16[0];
945
        uint64_t off = (u.wbits.imm7_6 << 4) | u.wbits.imm5_2;
946
        off <<= 2;
947
        trans.action = MemAction_Write;
948
        trans.xsize = 4;
949
        trans.wstrb = (1 << trans.xsize) - 1;
950
        trans.addr = R[Reg_sp] + off;
951
        trans.wpayload.b64[0] = R[u.wbits.rs2];
952
        if (trans.addr & 0x3) {
953
            icpu_->raiseSignal(EXCEPTION_StoreMisalign);
954
        } else {
955
            icpu_->dma_memop(&trans);
956
        }
957
        return 2;
958
    }
959
};
960
 
961
/**
962
 * @brief C_XOR
963
 *
964
 * C.XOR computes the bitwise XOR of the values in registers rd' and rs2', then
965
 * writes the result to register rd'. C.XOR expands into xor rd', rd', rs2'.
966
 */
967
class C_XOR : public RiscvInstruction16 {
968
public:
969
    C_XOR(CpuRiver_Functional *icpu) : RiscvInstruction16(icpu,
970
        "C_XOR", "????????????????100011???01???01") {}
971
 
972
    virtual int exec(Reg64Type *payload) {
973
        ISA_CS_type u;
974
        u.value = payload->buf16[0];
975
        R[8 + u.bits.rs1] ^= R[8 + u.bits.rs2];
976
        return 2;
977
    }
978
};
979
 
980
 
981
void CpuRiver_Functional::addIsaExtensionC() {
982
    addSupportedInstruction(new C_ADD(this));
983
    addSupportedInstruction(new C_ADDI(this));
984
    addSupportedInstruction(new C_ADDI16SP(this));
985
    addSupportedInstruction(new C_ADDI4SPN(this));
986
    addSupportedInstruction(new C_ADDIW(this));
987
    addSupportedInstruction(new C_ADDW(this));
988
    addSupportedInstruction(new C_AND(this));
989
    addSupportedInstruction(new C_ANDI(this));
990
    addSupportedInstruction(new C_BEQZ(this));
991
    addSupportedInstruction(new C_BNEZ(this));
992
    addSupportedInstruction(new C_EBREAK(this));
993
    addSupportedInstruction(new C_J(this));
994
#ifdef RV32C_ONLY
995
    addSupportedInstruction(new C_JAL(this));
996
#endif
997
    addSupportedInstruction(new C_JALR(this));
998
    addSupportedInstruction(new C_JR(this));
999
    addSupportedInstruction(new C_LD(this));
1000
    addSupportedInstruction(new C_LDSP(this));
1001
    addSupportedInstruction(new C_LWSP(this));
1002
    addSupportedInstruction(new C_LI(this));
1003
    addSupportedInstruction(new C_LUI(this));
1004
    addSupportedInstruction(new C_LW(this));
1005
    addSupportedInstruction(new C_MV(this));
1006
    addSupportedInstruction(new C_NOP(this));
1007
    addSupportedInstruction(new C_OR(this));
1008
    addSupportedInstruction(new C_SD(this));
1009
    addSupportedInstruction(new C_SDSP(this));
1010
    addSupportedInstruction(new C_SLLI(this));
1011
    addSupportedInstruction(new C_SRAI(this));
1012
    addSupportedInstruction(new C_SRLI(this));
1013
    addSupportedInstruction(new C_SUB(this));
1014
    addSupportedInstruction(new C_SUBW(this));
1015
    addSupportedInstruction(new C_SW(this));
1016
    addSupportedInstruction(new C_SWSP(this));
1017
    addSupportedInstruction(new C_XOR(this));
1018
 
1019
    uint64_t isa = portCSR_.read(CSR_misa).val;
1020
    portCSR_.write(CSR_misa, isa | (1LL << ('C' - 'C')));
1021
}
1022
 
1023
}  // namespace debugger

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.