新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > 16位CPU怎么做,DIY大神給你支支招兒

        16位CPU怎么做,DIY大神給你支支招兒

        作者: 時間:2019-03-19 來源:電子工程世界 收藏

          狀態(tài)機(jī)基本上與系統(tǒng)所有的組件都連接到一起了,因為上面所說的所有動作的執(zhí)行,都需要狀態(tài)機(jī)的控制,狀態(tài)機(jī)其實(shí)就是由一部分觸發(fā)器構(gòu)成的記憶電路和另外一部 分組合邏輯構(gòu)成的次態(tài)譯碼電路構(gòu)成,還有根據(jù)當(dāng)前狀態(tài)和輸入進(jìn)行譯碼的部分用于控制各個部件,下面是教科書上的典型FSM結(jié)構(gòu):

        本文引用地址:http://www.104case.com/article/201903/398604.htm
        16位CPU怎么做,DIY大神給你支支招兒

          而我們用的狀態(tài)機(jī)狀態(tài)轉(zhuǎn)移圖如下:

        16位CPU怎么做,DIY大神給你支支招兒

          因為這個處理器設(shè)計的很簡單,所以沒有出現(xiàn)很多狀態(tài),當(dāng)處理器經(jīng)歷完以上的狀態(tài)之后,處理器就執(zhí)行完了一條指令。

          有的CISC的處理器用微指令進(jìn)行控制,作用和狀態(tài)機(jī)相近,這種結(jié)構(gòu)出現(xiàn)在一些比較古老的處理器上,因為那個時候的設(shè)計工具和方法沒有現(xiàn)在的先進(jìn),所以往往 改動硬件是困難的和高成本的,所以用微指令的話,做好了硬件的結(jié)構(gòu),要是需要改動只要修改微指令就好了,而現(xiàn)在的電子技術(shù)很發(fā)達(dá),設(shè)計工具也很完備,所以 就有很多直接通過硬連線實(shí)現(xiàn)的處理器。

          好馬配好鞍,有了處理器,我們就得給它配上一個好的程序,下面我們就用自己設(shè)計的處理器進(jìn)行求和,從1加到100,因為我們沒有設(shè)計編譯器,也沒有設(shè)計匯編器,所以程序只能用機(jī)器碼寫出,示例程序如下:

          我們不妨先寫出程序的匯編代碼:

          mov [ADDR],r0;r0 = 0

          mov r1,100

          lop:add r2,r1

          sub r1,1

          cmp r1,0

          jz ext

          mov r4,4

          jmp r4(lop)

          ext:mov [ADDR],r2

          jmp $

          先將內(nèi)存中存放數(shù)據(jù)的地址清零,這樣才能存放等下送來的結(jié)果,然后將r1寄存器存入循環(huán)次數(shù)(也就是求和的上限)。然后再將r1的值加到r2中來,r2其實(shí)就是放求和的寄存器,最后我們會將r2中的值送到內(nèi)存中的某個地址存放的。

          然 后將r1減去1,看看是否為0?如果為0則說明求和結(jié)束了,如果不是0則說明還要繼續(xù),結(jié)束后程序就跳到ext部分將結(jié)果存放到內(nèi)存中某個地址(例子中給 的是49152也就是二進(jìn)制的1100000000000000b),最后jmp $是為了讓程序停在這一行,防止程序跑飛(跑飛的程序危害很大!有可能吧數(shù)據(jù)當(dāng)代碼或者把代碼當(dāng)數(shù)據(jù)!)

          轉(zhuǎn)換成VerilogHDL語言如下:

          module memory

          (

          input [15:0] addr,

          inout [15:0] data,

          input rw

          );

          reg [15:0] data_ram[0:16'b1111_1111_1111_1111];

          integer i;

          initial begin

          for (i = 0; i <= 16'b1111_1111_1111_1111; i = i + 1)

          data_ram[i] = $random();

          data_ram[0] = 16'b1000000100000000; //mov [ADDR],r0;r0 = 0

          data_ram[1] = 16'b1100000000000000; //ADDR

          data_ram[2] = 16'b1000000010001000; //mov r1,100

          data_ram[3] = 100; //100

          //data_ram[2] = 16'b1110011001000000;

          data_ram[4] = 16'b0010000100010001; //lop:add r2,r1

          data_ram[5] = 16'b1110000011001000; //sub r1,1

          data_ram[6] = 16'b0000000000000001; //1

          data_ram[7] = 16'b1110000000001000; //cmp r1,0

          data_ram[8] = 16'b0000000000000000; //0

          data_ram[9] = 16'b1110011010000000; //jz ext

          data_ram[10] = 16'b0000000000000011; //+3 offset(ext)

          data_ram[11] = 16'b1000000010100000;//mov r4,4

          data_ram[12] = 16'b0000000000000100;

          data_ram[13] = 16'b0110011001100000;//jmp r4(lop)

          data_ram[14] = 16'b1000000100000010;//ext:mov [ADDR],r2

          data_ram[15] = 16'b1100000000000000;//ADDR

          data_ram[16] = 16'b1110011001000000;//jmp $

          data_ram[17] = 16'b1111111111111110;//-2 offset($)

          /*data_ram[0] = 16'b1000000010000000; //mov r0,imm

          data_ram[1] = 16'b0011111111111111; //imm

          data_ram[2] = 16'b0000000001111000; //mov r7,r0

          data_ram[3] = 16'b1000000010011000; //mov r3,0

          data_ram[4] = 16'b0000000000000000;

          data_ram[5] = 16'b1000000010100000; //mov r4,code of jmp r5

          data_ram[6] = 16'b0110011001101000; //jmp r5

          data_ram[7] = 16'b0000000101011100; //mov [r3],r4

          data_ram[8] = 16'b1000000011110000; //mov r6,[0]

          data_ram[9] = 16'b0000000000000000; //[0]

          data_ram[10]= 16'b1000000100000110; //mov [255],r6

          data_ram[11]= 16'b0000000011111111;

          data_ram[12]= 16'b0110011001011000; //jmp r3

          */

          end

          always @ (addr or rw or data)

          if (rw)

          data_ram[addr] = data;

          assign data = rw ? 16'hzzzz : data_ram[addr];

          endmodule

          設(shè)計中外圍還需要一個內(nèi)存設(shè)備(Memory),我用HDL對其建模,初始化的時候每個內(nèi)存地址上對應(yīng)的數(shù)據(jù)都初始化為隨機(jī)的,然后只有從0開始的一系列地址被初始化為我寫的代碼,機(jī)器碼對應(yīng)的匯編指令在注釋中已經(jīng)給出。

          然后是結(jié)果,結(jié)果應(yīng)該是r2從0變化到5050(1+2+3+......+100=5050)

          而r1則從100變化到0,變化到0后程序?qū)⑦M(jìn)入死循環(huán),停止在jmp $那一條。這是仿真開始的時候:

        16位CPU怎么做,DIY大神給你支支招兒

          大家可以看到初始化后,d0~d7都變成了0,這是r0~r7寄存器的Q端,而state_current和state_next則是狀態(tài)機(jī)的現(xiàn)態(tài)和狀態(tài)機(jī) 的次態(tài),cpu的各個部件都通過這個狀態(tài)機(jī)受到控制。狀態(tài)名出現(xiàn)的順序和上面的FSM Viewer的連線順序是一樣的。

          而且大家可以看到,d2從0變化到了0x64也就是十進(jìn)制100,說明已經(jīng)執(zhí)行了第一次加法了。

          再來看看仿真結(jié)束:

        16位CPU怎么做,DIY大神給你支支招兒

          這時候d1變化到了0而d2變化到了0x13ba(十進(jìn)制的5050),說明程序已經(jīng)在我們設(shè)計的處理器里面運(yùn)行并且成功的得出了結(jié)果!

          最后給出一些我用到的指令(跟x86的很像):

          add dst,src 將src和dst相加并且送到dst寄存器中

          mov [addr],src 將src的值送到以addr位地址的內(nèi)存單元

          sub dst,src 將dst減去src并且送到dst中去

          cmp dst,src 將dst減去src 然后不送到dst中 只改變標(biāo)志位

          jz dst 當(dāng)zf=1時(即上次的算術(shù)操作結(jié)果為0)則跳轉(zhuǎn)到dst中去

          最后再提一下:

          我是用synplify綜合的電路,然后用debussy+modelsim仿真的。


        上一頁 1 2 3 下一頁

        關(guān)鍵詞: CPU RISC

        評論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 唐海县| 汕头市| 刚察县| 澜沧| 农安县| 南涧| 平原县| 张家口市| 天津市| 沈阳市| 开阳县| 洱源县| 巍山| 苏尼特右旗| 临漳县| 额尔古纳市| 昌宁县| 英山县| 灌云县| 苏尼特右旗| 耿马| 宜川县| 分宜县| 平谷区| 高台县| 台山市| 长治县| 元朗区| 石狮市| 红河县| 夏津县| 雅江县| 永春县| 江北区| 苗栗县| 德昌县| 南郑县| 南和县| 寿阳县| 宣城市| 桑植县|