新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Spoc CPU軟核 Part 3-軟件(即程序員)模型

Spoc CPU軟核 Part 3-軟件(即程序員)模型

作者: 時(shí)間:2024-01-22 來源:EEPW編譯 收藏

有一個(gè)小指令集和一些尋址模式。
這使得 程序員的模型易于學(xué)習(xí)。

本文引用地址:http://2s4d.com/article/202401/454998.htm
指令集

目前支持 8 條指令:

1705888178193292.png

例子:

 inc RA2      // increments register RA2 
 dec A       // decrements accumulator 
 sel WA10     // selects WA10 
 do #0xBA00 + WA22 > A // adds value 0xBA00 to register WA22, and writes the result to the accumulator 
 do A and #0x5555 -> @ // logical AND between accumulator and value goes to memory 
 do A xnor #0x5555 > RA0     // logical XNOR between accumulator and value goes to register RA0, selects RA0 
 not RA1     // inverts all the bits in register RA1, selects RA1 
 jsr A+RA10   // calculates A+RA10, and jumps to this address (subroutine, returns with RET)
 jmp #loop   // jmp to label "loop"
尋址模式

Spoc 支持 3 種尋址模式:

1705888324903172.png

例子:

 do #1234 -> A    // Immediate addressing: moves value 1234 to accumulator 
 do A -> RA4    // Direct addressing: writes accumulator value to register RA4 
 do @ -> A    // Indirect addressing: reads memory to accumulator 
 do A -> @    // Indirect addressing: writes accumulator to memory

可以對(duì)源操作數(shù)和目標(biāo)操作數(shù)使用間接尋址。

 do @ -> @ 
 do @ + #0x22 -> @ 
 do A or @ -> @

間接尋址與“選定的寄存器”有關(guān)(參見下面的“存儲(chǔ)器和寄存器文件”段落)。

DO指令

DO 指令是最強(qiáng)大的,因?yàn)樗梢允褂枚噙_(dá) 2 個(gè)源執(zhí)行操作,并將結(jié)果寫入多達(dá) 2 個(gè)目的地。

要寫入 2 個(gè)目標(biāo),請(qǐng)用逗號(hào)分隔它們。
示例:寫入 2 個(gè)目標(biāo)時(shí),一個(gè)始終是累加器,另一個(gè)是寄存器 (RAxx/WAxx) 或存儲(chǔ)器 (@)。

 do #22 -> A, RA0 
 do A + #22 -> A, WA1 
 do A - @ -> A, WA1 
 do A or RA3 -> WA4, A 
 do @ and #22 -> A, @ 
 do WA6 xor #22 -> A, @
累加器和數(shù)據(jù)大小

每個(gè) spoc 指令都從可能的大小列表中指定一個(gè)數(shù)據(jù)大小。
Spoc0 具有 4 種有效數(shù)據(jù)大?。?、8、16 和 32 位。 默認(rèn)值為 16 位(未指定數(shù)據(jù)大小時(shí))。
數(shù)據(jù)大小是通過后綴指令(.bit、.byte、.word 和 .dw)來指定的。

Spoc 還為每個(gè)有效數(shù)據(jù)大小提供了一個(gè)累加器。使用 Spoc0,這為我們提供了 4 個(gè)累加器。
累加器是獨(dú)立的(寫入一個(gè)不會(huì)影響其他累加器)。

例子:

 do.bit #1 -> A      // writes 1 to the 1-bit accumulator inc.byte A      // increments the 8-bits accumulator 
 do.word A + #0x1000-> A      // adds 0x1000 to the 16-bits accumulator 
 do.dw #0x12DECF80 -> A      // writes 0x12DECF80 to the 32-bits accumulator
分支

指令 JMP 用于分支到新的程序位置。
指令 JSR 用于分支到新的程序位置,最終使用指令 RET 從該位置返回。
這些指令可以有條件地執(zhí)行(借助 C 和 Z 標(biāo)志,請(qǐng)參閱下一段)。

例子:

 jmp #gothere      // jumps unconditionally 
 jsr #gotosubroutine    // jumps unconditionally to subroutine 
 jmp.Z=0 #gothere    // jumps conditionally (if flag Z is 0)

分支指令可以使用計(jì)算地址進(jìn)行分支。 例如,可以有子例程表。
注意:在任何分支指令之后,將取消選擇當(dāng)前寄存器(有關(guān)“選定”寄存器的討論,請(qǐng)參閱后面的內(nèi)容)。

在使用 JSR 指令之前,請(qǐng)確保初始化 SP(堆棧指針)寄存器。

例:

  do #0x0C00 > SP // stack from 0x0C00 to 0x0FFF,enough for a depth of 64 subroutine calls
  jsr #mysubroutine

堆棧用于存儲(chǔ)子例程返回地址。 堆棧使用內(nèi)存并向上增長(zhǎng)(在 Spoc0 中,SP 指針對(duì)于每個(gè) JSR 指令遞增 16,對(duì)于每個(gè) RET 遞減 16)。

標(biāo)志和條件執(zhí)行

標(biāo)志用于有條件地執(zhí)行其他指令。
Spoc0 使用 2 個(gè)標(biāo)志:

  • Z(零)標(biāo)志。用于檢測(cè)零值或“相等”比較。

  • C(攜帶)標(biāo)志。對(duì)于無符號(hào)數(shù)字的“大于”比較很有用(還可以檢測(cè)無符號(hào)添加/子操作的溢出)。

如果上一個(gè)操作的結(jié)果為 0,則 Z 標(biāo)志為 0。
如果上一個(gè)操作的結(jié)果不是 1,則 Z 標(biāo)志為 0(注意:許多 CPU 采用相反的約定......
標(biāo)志由所有執(zhí)行的指令設(shè)置。

例子:

 do #3 > A dec A   // A becomes 0x0002, C is 0, Z is 1 
 dec A   // A becomes 0x0001, C is 0, Z is 1 
 dec A   // A becomes 0x0000, C is 0, Z is 0 
 dec A   // A becomes 0xFFFF, C is 1, Z is 1 
 dec A   // A becomes 0xFFFE, C is 0, Z is 1 
 dec A   // A becomes 0xFFFD, C is 0, Z is 1

您可以執(zhí)行沒有目標(biāo)的 DO 操作。 在這種情況下,將執(zhí)行操作,結(jié)果將丟失,但標(biāo)志仍會(huì)更新。

例子:

 do #3 -> WA0     // writes 3 to register WA0

 // now we are going to do 3 subtractions, without saving the results. But the flags are still updated. 
 do WA0-#2    // WA0>2, so we get C=0, Z=1 
 do WA0-#3    // WA0=3, so we get C=0, Z=0 
 do WA0-#4    // WA0<4, so we get C=1, Z=1

 // now run some conditional instructions 
 jmp.c=0 #mylabel1     // conditional jump, not executed since C=1 
 add.z=0 WA0 + A > RA2       // conditional addition, not executed since Z=1 
 jmp.z=1 #mylabel2     // conditional jump, executed since Z=1

最后,如果未執(zhí)行條件指令,則標(biāo)志也不會(huì)更新。

例:

 do #1 > A    // A is 0x0001, C is 0, Z is 1 
 dec.z=0 A      // not executed, and flags not changed
將標(biāo)志作為操作數(shù)

進(jìn)位標(biāo)志也可以在源操作數(shù)中使用(在源操作數(shù)中,進(jìn)位標(biāo)志可以命名為“C”或“CY”或“carry”)。

例:

 do CY -> A 
 do A + #22 + C -> A 
 do A xor CARRY -> RA0

對(duì)于算術(shù)運(yùn)算,進(jìn)位標(biāo)志值不是有符號(hào)擴(kuò)展的,但對(duì)于邏輯運(yùn)算,它是有符號(hào)擴(kuò)展的(換句話說,對(duì)于算術(shù)運(yùn)算,進(jìn)位值為 0 或 1,對(duì)于邏輯運(yùn)算,進(jìn)位值為 0 和 0xFFFF)。

例:

 do #0 -> A dec A        // A=0xFFFF, C=1 
 do CY + #22 -> A       // arithmetic operation, so A=23 
 do #0 -> A dec A        // A=0xFFFF, C=1 
 do CY xor #0x1111 -> A       // logical operation, so A=0xEEEE
存儲(chǔ)器和寄存器文件

符號(hào)“@”用于表示內(nèi)存訪問。
它與名為“RAxx”和“WAxx”的寄存器結(jié)合使用。

內(nèi)存讀取示例(從地址0x200讀取):

 do #0x0200 -> RA0 do @ -> A      
 // reads memory 0x200, and puts the value in accumulator

內(nèi)存寫入(寫入地址0x200)示例:

 do #0x0200 -> WA17 
 do RA3 -> @       // writes content of RA3 to memory 0x200

讀取存儲(chǔ)器訪問的地址由“RAxx”寄存器給出。
寫存儲(chǔ)器訪問的地址由“WAxx”寄存器給出。
寄存器是寄存器文件的一部分,因此您可以使用其中的許多寄存器。
Spoc0 有 32 個(gè) RA 寄存器,命名為 RA0 到 RA31,以及 32 個(gè) WA 寄存器,命名為 WA0 到 WA31。
每個(gè)文件的一個(gè)寄存器在給定的執(zhí)行時(shí)間被“選擇”。 要選擇寄存器,您可以使用“sel”指令,也可以寫入寄存器。
當(dāng)指令進(jìn)行內(nèi)存訪問時(shí),所選寄存器的值用作內(nèi)存地址。
在每次內(nèi)存訪問期間,寄存器都會(huì)自動(dòng)遞增。

例:

 do #0x0200 -> RA5    // writes 0x200 to RA5, and selects it 
 do #0x0300 -> WA7    // writes 0x300 to WA7, and selects it

 // RA5 and WA7 are both selected 
 do @ -> @    // copies the value from memory location 0x200 to memory location 0x300

 // now RA5=0x210 and WA7=0x310 
 do WA7 + #0x20 -> RA6     // RA6 is now selected with the value 0x330 
 do @ -> A       
 // memory location 0x330 is read and copied to the accumulator 
 sel RA5    
 // re-select RA5. Since it was non-persistent, its value is back to 0x0200 (see later for explanation on persistent registers)

寄存器 RAxx/WAxx 還可用于存儲(chǔ)器訪問以外的其他目的。 它們具有與累加器幾乎相同的功能,因此可以遞增、添加、異或編輯......
它們還可用于子例程參數(shù)傳遞。

內(nèi)存空間

使用 Spoc0 時(shí),每個(gè)寄存器 WAxx 和 RAxx 的寬度為 16 位 (.word),因此它可以尋址 64K。
數(shù)據(jù)空間是“位可尋址”的。 因此,您可以在沒有任何對(duì)齊限制的情況下訪問它的任何部分。 例如,可以將一個(gè) 32 位值寫入尋址0xABCD,然后在地址0xABC3寫入另一個(gè)值,最后從地址0xABC7讀?。ㄗx取兩個(gè)值的一部分)。
代碼空間通常無法直接訪問。 它用于保存要執(zhí)行的指令。 但是有一個(gè)鉤子可以訪問代碼空間,這樣你就可以存儲(chǔ)表、數(shù)據(jù)、字符串......
Spoc0 使用寄存器 CS 訪問代碼空間。

例:

  do #GreetingString -> CS      // CS points to a string, and selects CS  do.byte @ -> A     // read the "H" into the accumulator
  ...

GreetingString:  data.byte "Hello world!", 13

另一個(gè)保留值是“$”。 它代表實(shí)際的PC(程序代碼位置,當(dāng)前執(zhí)行指令的位置)。 這是一個(gè)只讀值。

例:

  jmp $     // forever loop (if you want spoc to "die")

當(dāng)您使用 blockram 時(shí)(如在 Spoc0 中),代碼空間是位可尋址的,如果使用串行閃存,則代碼空間是字節(jié)可尋址的。 這為 Spoc64 提供了 0Kbits 的空間,而使用串行閃存時(shí)則為 64KB 的空間。

預(yù)留空間

Spoc0 使用一個(gè)塊 (4Kbits) 作為數(shù)據(jù)空間,它填充0x0000到0x0FFF的地址。
在此之上,0x1000 0xFFFF的空間是“外部存儲(chǔ)器”。它應(yīng)該用于連接外部外圍設(shè)備。

此外,保留 blockram 數(shù)據(jù)空間的前 1Kbit(地址 0x0000 到 0x03FF)來保存寄存器 RAxx/WAxx 的值。 如果你知道自己在做什么,你仍然可以使用它......


保留寄存器

寄存器 WA30/31 和 RA30/31 是保留的。 不要使用它們。

例如,在 Spoc0 中,寄存器 WA31 用作 PC...所以如果你要使用 WA31,你實(shí)際上會(huì)跳到某個(gè)地方......

持久寄存器

當(dāng)一個(gè)寄存器被取消選擇,然后在以后重新選擇時(shí),它的值可以是“持久的”(它在最后一次自動(dòng)遞增之后恢復(fù)該值),也可以是“非持久的”(它恢復(fù)最初受影響的值,即在任何內(nèi)存訪問/自動(dòng)遞增之前)。

您可以選擇是否希望在選擇寄存器時(shí)將其持久化(通過使用或不使用“.p”后綴)。

例:

do #0x0200 -> RA5    // RA5 is selected (not persistent) 
do @ -> A    // copies the value from memory location 0x200 to accumulator
                  // RA5 value is now 0x210 do #0x0300 -> RA6.p    // RA6 is selected (persistent) 
do @ -> A    // copies the value from memory location 0x300 to accumulator
                  // RA6 value is now 0x310 
sel RA5.p    // re-selects RA5. Since it was non-persistent, its value is back to 0x0200
                   // note that it is now persistent! 
do @ -> A    // copies the value from memory location 0x200 to accumulator
                  // RA5 value is now 0x210 
sel RA6    // re-selects RA6. Since it was persistent, its value is 0x0310 
do @ -> A    // copies the value from memory location 0x310 to accumulator
                  // RA6 value is now 0x320 
sel RA5    // re-selects RA5 (not persistent). But since it was persistent, its value is 0x0210 
do @ -> A    // copies the value from memory location 0x210 to accumulator
                  // RA5 value is now 0x220

上一篇:Spoc CPU軟核 Part 2-主要特征

下一篇:Spoc CPU軟核 Part 4-硬件接口



關(guān)鍵詞: FPGA Spoc

評(píng)論


相關(guān)推薦

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

關(guān)閉