iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0

昨天完成了R-Type的ALU,今天要來實作I-type。

I-type ALU

I-type跟R-type的區別在於說R-type一個是以兩個暫存器內的值做運算,而I-type則是以暫存器的值加上一個立即值來做運算,但整體來說是相當接近的,decode上在func3的欄位也相同,可以重複利用昨天的code。

不過要注意,由於[31:20]被immediate值使用,因此像sub等指令是沒有I-type的,
總之今天也來實作吧。

我們可以重複利用昨天的test,只要少掉一個暫存內的值即可,同樣以addi作為範例。

/*ISA Test*/

TEST(ISATESTSuite, ADDI0)
{
    ALISS::reg[11] = 3;
    //ALISS::reg[12] = 7;
    uint32_t insn = 0x00758513; // addi a0 a1 7
    ALISS::ID_EX_WB(insn);
    EXPECT_EQ(ALISS::reg[10], 0xa); //3 + 7 = 10;
}

TEST(ISATESTSuite, ADDI1)
{
    ALISS::reg[10] = 0xffffffffffffffff;
    //ALISS::reg[12] = 0x1;
    uint32_t insn = 0x00150593; // addi a1 a0 1
    ALISS::ID_EX_WB(insn);
    EXPECT_EQ(ALISS::reg[11], 0); //1 + -1 = 0;
}

而I-type的最後7bit是0x13,我們可以重複利用昨天的code。

比較要注意的是因為imm只有12bit,但有些指令的imm是有號的,因此要做sign extension,我們簡單實作sign extension程式如下,將輸入結果左移到64bit再右移回原本的位元數。


uint64_t sext(uint64_t input, int len) { return int64_t(input) << (64 - len) >> (64 - len); }

完成 sign extension後,我們實作ADDI如下,將R-type取rs2的地方改為取imm,

            case 0x13:
            {
                uint64_t rd = ((insn >> 7) & 0x1f);
                uint64_t rs1 = ((insn  >> 15) & 0x1f);
                uint64_t imm = ((insn >> 20) & 0xfff);
                switch ((insn >> 12) & 7)
                {
                    case 0x0: //ADDI
                    {
                        reg[rd] =  reg[rs1] +  sext(imm, 12);
                        break;
                    }
                    ...
                    ..
                    .
                }
                break;
             }
            ...
            ..
            .

另外還有shift相關指令如SLLI,SRAI,SRLI等,並不會將完整的[31:20]當成immediate (shift超過64bit是沒必要的),相反的是以[24:20]作為shift amount,因此要特別處理


uint64_t shamt = imm & 0x1f; //[24:20]

case 0x1: //SLLI
{
     uint64_t shamt = imm & 0x1f; //[24:20]
     reg[rd] = reg[rs1] << shamt;
     break;
}

之後就可以直接仿照昨天實作的R-type的decode,將I-type的指令全部實現啦~

                    case 0x0: //ADDI
                    {
                        reg[rd] =  reg[rs1] +  sext(imm, 12);
                        break;
                    }
                    case 0x1: //SLLI
                    {
                        uint64_t shamt = imm & 0x1f; //[24:20]
                        reg[rd] = reg[rs1] << shamt;
                        break;
                    }
                    case 0x2: //SLTI
                    {
                        reg[rd] = ((int64_t)reg[rs1] < sext(imm, 12));
                        break;
                    }
                    case 0x3: //SLTUI
                    {
                        reg[rd] = (reg[rs1] < imm);
                        break;
                    }
                    case 0x4: //XORI
                    {
                        reg[rd] = (reg[rs1] ^ sext(imm, 12));
                        break;
                    }
                    case 0x5: //SRLI & SRAI
                    {
                        uint64_t shamt = imm & 0x1f; //[24:20]
                        switch ((insn >> 25) & 0x7f)
                        {
                            case 0x0 : //SRLI
                            {
                                reg[rd] =  reg[rs1] >> shamt;
                                break;
                            }
                            case 0x20 : //SRAI
                            {
                                reg[rd] =  (int64_t)reg[rs1] >> shamt;
                                break;
                            }
                           default:
                           {
                                printf("Illegal instruction");
                                printf("%x\n",insn);
                                break;
                           }
                        }
                        break;
                    }
                    case 0x6: //ORI
                    {
                        reg[rd] = (reg[rs1] | sext(imm, 12));
                        break;
                    }
                    case 0x7: //ANDI
                    {
                        reg[rd] = (reg[rs1] & sext(imm, 12));
                        break;
                    }

https://ithelp.ithome.com.tw/upload/images/20231003/20162436BICh8ZP0WZ.png

並同樣確認test都通過,送出。


碎碎念:以為有R-type的經驗I-type做起來會輕鬆很多,結果踩到sext的坑,明天來實作CTRL指令


上一篇
Day 17 RISC-V R-type ALU implement
下一篇
Day-19 RISC-V CTRL Instruction implement
系列文
從零開始的RISC-V ISA Simulator (Another Little RISC-V ISA Simulator)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言