跳轉到內容

超級任天堂程式設計/SPC700 參考資料

來自華夏公益教科書

系統概述

[編輯 | 編輯原始碼]
SPC700

SPC700 是索尼的協處理器,用於協調超級任天堂音訊。一旦它被超級任天堂 CPU 傳送的資料和程式碼初始化,它就會操作其附帶的數字訊號處理器 (DSP) 的狀態,該處理器會產生輸出音訊。

SPC700 概述

[編輯 | 編輯原始碼]

SPC700 擁有 64KB 的記憶體,用於儲存程式碼和資料。在這個記憶體空間中,還包含記憶體對映暫存器,用於與超級任天堂 CPU、DSP 和三個可用的定時器進行通訊。

SPC700 有 6 個暫存器:

  • A - 一個 8 位累加器
  • X & Y - 8 位索引暫存器
  • SP - 8 位堆疊指標
  • PC - 16 位程式計數器
  • PSW - 8 位“程式狀態字”,用於儲存狀態標誌

Y 和 A 暫存器可以組合成一個 16 位暫存器,其中 Y 是高位元組,用於某些操作。

DSP 概述

[編輯 | 編輯原始碼]

DSP 有 8 個通道,每個通道可以播放 16 位聲音。所有 8 個通道都具有獨立的左右立體聲音量,可以在不同的音高下播放,並且可以應用攻擊-衰減-持續-釋放 (ADSR) 包絡。可以將一個白噪聲源設定為替換任何 8 個通道上的取樣資料。此外,DSP 可以對音訊應用回聲。16 位音訊樣本從 SPC700 的 64KB 記憶體空間中讀取,它們以壓縮的 4 位有損格式儲存。

SPC700 記憶體對映

[編輯 | 編輯原始碼]
  • $0000 - $00EF - 直接頁 0
  • $00F0 - $00FF - 記憶體對映硬體暫存器
  • $0100 - $01FF - 直接頁 1
  • $0100 - $01FF - 潛在的堆疊記憶體
  • $FFC0 - $FFFF - IPL ROM

直接頁定址

[編輯 | 編輯原始碼]

許多指令提供一種定址模式,用於訪問“直接頁”中的 1 位元組記憶體地址。這種定址模式會生成更短的位元組碼,這可能導致執行速度更快。直接頁的高位元組是 $00$01,對應於 PSW 暫存器中的 P 位。

堆疊指標的低位元組由 SP 暫存器指定;高位元組始終是 $01。堆疊指標在 IPL ROM 重啟時設定為 $01EF,並向下增長。

重啟時,64KB RAM 末尾的 64 位元組記憶體塊被初始化為 IPL ROM 的內容,這是執行開始的地方。IPL ROM 中的程式碼將堆疊指標設定為 $01EF,將記憶體從 $0000 清零到 $00EF,然後等待來自超級任天堂的透過輸入埠的資料。

SPC700 暫存器

[編輯 | 編輯原始碼]
地址 描述 讀/寫
$00F0 未知 ?
$00F1 控制
$00F2 DSP 讀/寫地址 讀/寫
$00F3 DSP 讀/寫資料 讀/寫
$00F4 埠 0 讀/寫
$00F5 埠 1 讀/寫
$00F6 埠 2 讀/寫
$00F7 埠 3 讀/寫
$00FA 定時器設定 0
$00FB 定時器設定 1
$00FC 定時器設定 2
$00FA 定時器計數器 0
$00FB 定時器計數器 1
$00FC 定時器計數器 2

$00F0 未知

[編輯 | 編輯原始碼]

Anomie 對此暫存器進行了一些測試。romhacking.net 上的一份文件對此進行了描述。

$00F1 控制

[編輯 | 編輯原始碼]
7 6 5 4 3 2 1 0
X X PC32 PC10 X ST2 ST1 ST0
  • PC32 - 在此位寫入 1 將使埠 2 和 3 的輸入歸零
  • PC10 - 在此位寫入 1 將使埠 1 和 0 的輸入歸零
  • ST0-2 - 這些用於啟動定時器。
 Warning: Writing to this register will always restart/stop all of the timers.

$00F2/$00F3 DSP 暫存器

[編輯 | 編輯原始碼]

寫入 $00F2 會設定要訪問的 DSP 暫存器的地址。寫入 $00F3 會更改指向的暫存器的值。從 $00F3 讀取將返回指向的暫存器的值。允許向 $00F2 寫入一個字,它可以用於同時設定地址和向暫存器寫入一個值。

$00F4-$00F7

[編輯 | 編輯原始碼]

從這些埠讀取將為您提供超級任天堂在 $2140-$2143 設定的值。寫入這些暫存器的值可以透過超級任天堂使用相同的 $2140-$2143 檢視。可以使用控制暫存器清除這些埠的輸入。

$00FA-$00FF 定時器設定

[編輯 | 編輯原始碼]

暫存器 $00FA-$00FC 用於設定定時器速率。定時器 0 和 1 的解析度為 125 微秒。定時器 2 的解析度更精細,約為 15.6 微秒。$00FD-$00FF 是包含定時器溢位計數的 4 位暫存器。以下是定時器的工作方式。

每個定時器都有一個內部計數器,它在每個時鐘輸入時遞增。如果它等於 $00FA-$00FC 中的數字(取決於您使用的是哪個定時器),相應的計數器暫存器將遞增,內部計數器將復位。計數器暫存器 ($00FD-$00FF) 是 4 位暫存器,只能讀取。從它們讀取會導致它們復位為零。如果您沒有在有限的時間範圍內讀取計數器,它們也會溢位並被清除為零。必須在設定 $00FA-$00FC 暫存器之前停止定時器。要啟動定時器,請寫入控制暫存器位 0-2。要停止定時器,請復位這些位。請注意,寫入控制暫存器將重新啟動現有的定時器。

DSP 壓縮格式

[編輯 | 編輯原始碼]

DSP 使用一種特殊的 ADPCM 編碼聲音格式。樣本由一系列 9 位元組的壓縮塊組成。每個塊包含 16 個 4 位樣本和一個 1 位元組的頭部。16 位樣本將獲得 9/32 的壓縮比,但 8 位樣本必須在壓縮之前膨脹為 16 位(使其僅獲得 9/16 的壓縮比)。每個塊的第一個位元組包含頭部。

7 6 5 4 3 2 1 0
範圍 濾波器 迴圈 結束
  • 範圍 - 這是資料的移位值。它可以是 0-12。
  • 濾波器 - 這選擇解碼過程中使用的濾波器係數。(見下表)
  • 迴圈 - 此位將塊標記為迴圈內的塊。此位的確切功能未知,但我檢查過的某些商業 SPC 樣本將此位設定為樣本中的所有塊。
  • 結束 - 此位將塊標記為樣本中的最後一個塊。如果 DSP 通道到達此塊,它將終止或跳轉到迴圈點。

每個塊包含 8 位元組的樣本資料(16 個帶符號的 4 位樣本)。每個位元組中的較高 nibble 包含在較低 nibble 中解碼的樣本之前要解碼的樣本。

解碼過程

[編輯 | 編輯原始碼]

以下公式用於估計 DSP 的 16 位輸出。設 y 和 z 為最後兩個先前解碼的樣本。'a' 和 'b' 是由頭部位元組的第 2-3 位選擇的濾波器係數。

 sample = S + ay + bz
 S is the shifted data:
 S = (4-bit sample) << Range

DSP 使用最少的移位操作執行此過程;輸出精度不會很完美。它還將高斯插值應用於輸出。

濾波器係數

[編輯 | 編輯原始碼]
濾波器# a b
0 0 0
1 15/16 0
2 61/32 -15/16
3 115/64 -13/16

進一步閱讀

[編輯 | 編輯原始碼]
華夏公益教科書