68020 とメモリのつなぎ方
Twitter で Ki さんが 68000 と PCM 音源を使った CPU ボードを設計するとのことで冗談で 68000 より小さいから 68EC020 にしろといったところ本当に EC020 を検討し始めた。ちゃんと読んでなかった 68020 のつなぎ方の記事を読んでたら自分もおもしろくなってきたという件。
ここは資料整理とメモ代わりなので、正しいデータは freescale にあるデータシートを元に設計してください。(いま設計する人は限られてるのでないと思います)
Dynamic Sizing
data bus が 32bit となったと同時に、接続するメモリの幅を 8/16/32 bit から選べる仕組み。これのおかげで奇数アドレスへの word/longword アクセスでアドレスエラーが発生しなくなった(と思う)。
以下 8bit の SRAM を data bus の幅別につなぐ方式を記載する。
8bit SRAM
//RAM A[nn:0] = CPU_A[nn:0]; DQ[7:0] = CPU_D[31:24]; CS = CPU_A[amax:nn + 1] == xxxx && CPU_AS == 1'b0 ? 1'b0 : 1'b1; OE = CPU_RW == 1'b1 && CPU_DS == 1'b0 ? 1'b0 : 1'b1; WE = CPU_RW == 1'b0 && CPU_DS == 1'b0 ? 1'b0 : 1'b1; //CPU CPU_8BIT_DSACK[1:0] = WAIT ? 2'b11 : 2'b10;
16bit SRAM (8x2)
size |A0|UD LD|part
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- UD = UDS(D31:24), LD = LDS(D23:16), part = 想定される転送バイト数
- part の 条件で()内の値は担当外の転送
- [*] 32 bus の offset が 2'b01 でその次が 16 bit bus
- 3byte で offset 1'b1 はないと思うんだが....
//data strobe CPU_UDS = DS | CPU_A[0]; CPU_LDS = CPU_A[0] == 1'b0 ? DS | (CPU_SIZ[1:0] == 2'b01 ? 1'b1 : 1'b0) : DS; //RAM A[nn-1:0] = CPU_A[nn:1]; U_DQ[7:0] = CPU_D[31:24]; L_DQ[7:0] = CPU_D[23:16]; CS = CPU_A[amax:nn + 1] == xxxx && CPU_AS == 1'b0 ? 1'b0 : 1'b1; U_OE = CPU_RW == 1'b1 && CPU_UDS == 1'b0 ? 1'b0 : 1'b1; L_OE = CPU_RW == 1'b1 && CPU_LDS == 1'b0 ? 1'b0 : 1'b1; //CPU CPU_16BIT_DSACK[1:0] = WAIT ? 2'b11 : 2'b01;
- LDS: A0 == 0 のとき byte アクセスの場合には active にはならない。 A0 == 1 のときはどのサイズでも OK
- A: 68000 同様 A1 からシフトして接続
- DQ: 31 から 16.
- CS: 68000 と同じ.
- OE, WE: UDS, LDS を周辺回路で作る以外は 68000 と同じ. WE は略した。
- DSTACK: 16bit bus cycle end は 2'b10
32bit SRAM (8x4)
size |OF|UU UM LM LL|part
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- OF = offset, A[1:0]. 表示値としては prefix として 2'h。
- UU = UUDS, D31:24
- UM = UMDS, D23:16
- LM = LMDS, D15:8
- LL = LLDS, D7:0
- 3byte がいまいち理解できず。
//data strobe CPU_UUDS = DS | (CPU_A[1:0] == 2'00 ? 1'b0 : 1'b1); //D31:24 CPU_UMDS = DS == 1'b1 ? 1'b1 : umds(CPU_A, CPU_SIZ); CPU_LMDS = DS == 1'b1 ? 1'b1 : lmds(CPU_A, CPU_SIZ); CPU_LLDS = DS == 1'b1 ? 1'b1 : llds(CPU_A, CPU_SIZ); function umds; input [1:0] cpu_a; input [1:0] size; case(cpu_a) 2'h0: umds = (size == 2'b01 ? 1'b0 : 1'b1); 2'h1: umds = 1'b0; 2'h2, 2'h3: umds = 1'b1; endcase endfunction function lmds; input [1:0] cpu_a; input [1:0] size; case(cpu_a) 2'h0: case(size) 2'b01, 2'b10: lmds = 1'b1; 2'b11, 2'b00: lmds = 1'b0; endcase 2'h1: case(size) 2'b01: lmds = 1'b1; 2'b10, 2'b11, 2'b00: 1'b0; endcase 2'h2: lmds = 1'b0; 2'h3: lmds = 1'b1; endcase endfunction function llds; (略) endfunction //RAM A[nn-2:0] = CPU_A[nn:2]; UU_DQ[7:0] = CPU_D[31:24]; UM_DQ[7:0] = CPU_D[23:16]; LM_DQ[7:0] = CPU_D[15:8]; LL_DQ[7:0] = CPU_D[7:0]; CS = CPU_A[amax:nn + 1] == xxxx && CPU_AS == 1'b0 ? 1'b0 : 1'b1; UU_OE = CPU_RW == 1'b1 && CPU_UUDS == 1'b0 ? 1'b0 : 1'b1; UM_OE = CPU_RW == 1'b1 && CPU_UMDS == 1'b0 ? 1'b0 : 1'b1; LM_OE = CPU_RW == 1'b1 && CPU_LMDS == 1'b0 ? 1'b0 : 1'b1; LL_OE = CPU_RW == 1'b1 && CPU_LLDS == 1'b0 ? 1'b0 : 1'b1; //CPU CPU_32BIT_DSACK[1:0] = WAIT ? 2'b11 : 2'b00;
- UUDS, UMDS, LMDS, LLDS はここまでくると面倒なので表をそのまま読めるように function で case を組みまくった方がよいと思われる
- A: A2 からシフトして接続
- DQ: 31 から 0 の全てを使う.
- CS: 68000 と同じ
- OE, WE: WE は略。 CPU_WR == 1'b0 && (OEとおなじ)
- DSTACK: 32bit bus cycle end は 2'b00
総評
32bitの data strobe を作るのが大変で、奇数アドレスへの word/long のアクセスはアドレスエラーをだしてもいいのではと思った。アドレスエラーでなくもののバスエラーならだせるので、 A[0] == 1'b1 のときに SIZ が word/long のときは発生。そうすれば SIZE == 3byte も発生しない気がする。