NET "a<24>" LOC = "S:PIN18"; NET "a<25>" LOC = "S:PIN40"; NET "a<26>" LOC = "S:PIN6"; NET "a<27>" LOC = "S:PIN41"; NET "a<28>" LOC = "S:PIN71"; NET "a<29>" LOC = "S:PIN56"; NET "a<30>" LOC = "S:PIN65"; NET "a<31>" LOC = "S:PIN81"; NET "as_b" LOC = "S:PIN69"; NET "ba<23>" LOC = "S:PIN54"; NET "ba<24>" LOC = "S:PIN43"; NET "cpurw" LOC = "S:PIN50"; NET "ds_b" LOC = "S:PIN3"; NET "fc<0>" LOC = "S:PIN46"; NET "fc<1>" LOC = "S:PIN20"; NET "fc<2>" LOC = "S:PIN35"; NET "irq_n<1>" LOC = "S:PIN70"; NET "irq_n<2>" LOC = "S:PIN33"; NET "irq_n<3>" LOC = "S:PIN26"; NET "irq_n<4>" LOC = "S:PIN83"; NET "irq_n<5>" LOC = "S:PIN44"; NET "irq_n<6>" LOC = "S:PIN37"; NET "irq_n<7>" LOC = "S:PIN48"; NET "refclk" LOC = "S:PIN36"; NET "reset_b" LOC = "S:PIN74"; NET "sa<0>" LOC = "S:PIN15"; NET "sa<1>" LOC = "S:PIN21"; NET "sa<2>" LOC = "S:PIN67"; NET "siz<0>" LOC = "S:PIN34"; NET "siz<1>" LOC = "S:PIN11"; NET "sysclk" LOC = "S:PIN9"; NET "avec_n" LOC = "S:PIN25"; NET "berr_n" LOC = "S:PIN31"; NET "cas0_n" LOC = "S:PIN72"; NET "cas1_n" LOC = "S:PIN75"; NET "cas2_n" LOC = "S:PIN80"; NET "cas3_n" LOC = "S:PIN82"; NET "cf_ce1_n" LOC = "S:PIN47"; NET "cf_ce2_n" LOC = "S:PIN51"; NET "cf_iocs16_n" LOC = "S:PIN53"; NET "cf_iord_n" LOC = "S:PIN14"; NET "cf_iowr_n" LOC = "S:PIN84"; NET "ciin_n" LOC = "S:PIN61"; NET "cpuclk" LOC = "S:PIN63"; NET "cs16550_n" LOC = "S:PIN1"; NET "ft245rd_n" LOC = "S:PIN4"; NET "ft245wr" LOC = "S:PIN5"; NET "iord_n" LOC = "S:PIN66"; NET "iowr_n" LOC = "S:PIN68"; NET "ipl_n<0>" LOC = "S:PIN32"; NET "ipl_n<1>" LOC = "S:PIN39"; NET "ipl_n<2>" LOC = "S:PIN57"; NET "lan_n" LOC = "S:PIN7"; NET "n_dsack<0>" LOC = "S:PIN45"; NET "n_dsack<1>" LOC = "S:PIN55"; NET "psd_n" LOC = "S:PIN13"; NET "ras0_n" LOC = "S:PIN17"; NET "ras1_n" LOC = "S:PIN19"; NET "ras2_n" LOC = "S:PIN23"; NET "ras3_n" LOC = "S:PIN24"; NET "rtc_n" LOC = "S:PIN2"; #PINLOCK_END
module dramc_tp ; reg sysclk ; //system clock reg reset_b ; //system reset reg [31:24] a ; // cpu address reg [24:23] ba ; // dram bank address (4x8MB) reg [2:0] sa ; // cpu a2-a0 reg [1:0] siz ; // cpu bus size reg as_b ; // cpu address strobe reg ds_b ; // cpu data strobe reg cpurw ; // cpu read/~write reg refclk ; //refresh clock reg [7:1] irq_n ; // interrupt request reg [2:0] fc ; // cpu function code
ポートサイズを32bit→8bit→16bit→8bitと変化させてDynamic bus sizing風の動作をシミュレーションしている(つもり)。M68020,68030はDynamic bus sizingをCPU側でサポートしてたので回路が簡単になって助かった記憶がある。今回はDRAMは32ビット、psd含むioポートは8ビット、CF等のPC104系は16ビットポートとして返す様に設計している。まあBus sizingはCPUが勝手にやってくれるのでデバイス側が自分のポートサイズを[1:0]dsack_n にエンコードして返せば良いだけなのだが。
4.合成結果
cpldfit: version P.20131013 Xilinx Inc. Fitter Report Design Name: dramc Date: 11-28-2021, 10:54AM Device Used: XC95108-20-PC84 Fitting Status: Successful
バスエラーは/ASがnegateされず(=dsack_nが所定時間以内にアサートされず)busがlockされるのを防ぐCPU側の仕掛けで具体的には/ASがアサートされてから所定時間内にネゲートされなければ/BERRをアサートする時間監視回路を構成すれば良い。この所定時間は適時適当で良く9〜12μS程度にする場合が多い(と思われる)。根拠はと言えばDRAMのリフレッシュサイクル(2ms/128cyc=15.6us)より短めの値でそのくらいなのでは?と勝手に考えているが極端に長い(数百usとか)で無ければ良い。Normal not ready系のバスアーキテクチャではbus errorの概念は有る(PCIとか)ので一般的と思われる。x86系は伝統的にNormal ready系が多いと思っているのでこの回路は実装されない(のでは?)。
parameter S0=3'b000,S1=3'b001,S2=3'b011,S3=3'b111,S4=3'b110,S5=3'b100 ; // dram state 0-5 parameter R0=4'b0000,R1=4'b0001,R2=4'b0011,R3=4'b0111,R4=4'b1111,R5=4'b1110,R6=4'b1100,R7=4'b1000 ; // rfsh state 0-7 parameter dram=8'h80,dram80=8'h80,dram81=8'h81,psd=8'h00,rtc=8'hf0,cs16550=8'hf1,ft245=8'hf2,pc104=8'hff ; parameter IRQ7=7'b0111111,IRQ6=7'b1011111,IRQ5=7'b1101111,IRQ4=7'b1110111,IRQ3=7'b1111011,IRQ2=7'b1111101,IRQ1=7'b1111110 ; parameter LVL7=3'b000,LVL6=3'b001,LVL5=3'b010,LVL4=3'b011,LVL3=3'b100,LVL2=3'b101,LVL1=3'b110 ;
// cpuclock always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) cpuclk <= 1'b0 ; else cpuclk <= ~cpuclk ; end
// state register always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) begin drsq <= S0 ; rfsq <= R0 ; end else begin drsq <= ndrsq ; rfsq <= nrfsq ; end end
// dram state sequencer always @( drsq or as_b or a or cpuclk or rfshcyc ) begin case ( drsq ) // S0 : if ( as_b == 0 && {a[31:25],1'b0} == dram && cpuclk && rfshcyc == 0 ) S0 : if ( as_b == 0 && *1 && cpuclk && rfshcyc == 0 ) ndrsq <= S1 ; else ndrsq <= S0 ; S1 : ndrsq <= S2 ; S2 : if ( cpuclk ) ndrsq <= S3 ; else ndrsq <= S2 ; S3 : ndrsq <= S4 ; S4 : ndrsq <= S5 ; S5 : if ( as_b ) ndrsq <= S0 ; else ndrsq <= S5 ; endcase end
reg [2:0] drsq,ndrsq ; // dram sequencer reg [3:0] rfsq,nrfsq ; // dram refresh sequencer reg cpuclk ; // sysclk/2
parameter S0=3'b000,S1=3'b001,S2=3'b011,S3=3'b111,S4=3'b110,S5=3'b100 ; // dram state 0-5 parameter R0=4'b0000,R1=4'b0001,R2=4'b0011,R3=4'b0111,R4=4'b1111,R5=4'b1110,R6=4'b1100,R7=4'b1000 ; // rfsh state 0-7
parameter dram=8'h80,dram80=8'h80,dram81=8'h81,psd=8'h00,rtc=8'hf0,cs16550=8'hf1,ft245=8'hf2,pc104=8'hff ; // cpuclock always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) cpuclk <= 1'b0 ; else cpuclk <= ~cpuclk ; end
// state register always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) begin drsq <= S0 ; rfsq <= R0 ; end else begin drsq <= ndrsq ; rfsq <= nrfsq ; end end
// dram state sequencer always @( drsq or as_b or a or cpuclk or rfshcyc ) begin case ( drsq ) // S0 : if ( as_b == 0 && {a[31:25],1'b0} == dram && cpuclk && rfshcyc == 0 ) S0 : if ( as_b == 0 && *1 && cpuclk && rfshcyc == 0 ) ndrsq <= S1 ; else ndrsq <= S0 ; S1 : ndrsq <= S2 ; S2 : if ( cpuclk ) ndrsq <= S3 ; else ndrsq <= S2 ; S3 : ndrsq <= S4 ; S4 : ndrsq <= S5 ; S5 : if ( as_b ) ndrsq <= S0 ; else ndrsq <= S5 ; endcase end
reg [2:0] drsq,ndrsq ; // dram sequencer reg [3:0] rfsq,nrfsq ; // dram refresh sequencer reg cpuclk ; // sysclk/2
parameter S0=3'b000,S1=3'b001,S2=3'b011,S3=3'b111,S4=3'b110,S5=3'b100 ; // dram state 0-5 parameter R0=4'b0000,R1=4'b0001,R2=4'b0011,R3=4'b0111,R4=4'b1111,R5=4'b1110,R6=4'b1100,R7=4'b1000 ; // rfsh state 0-7
parameter dram=8'h80,dram80=8'h80,dram81=8'h81,psd=8'h00,rtc=8'hf0,cs16550=8'hf1,ft245=8'hf2,pc104=8'hff ; // cpuclock always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) cpuclk <= 1'b0 ; else cpuclk <= ~cpuclk ; end
// state register always @( posedge sysclk or negedge reset_b ) begin if ( ~reset_b ) begin drsq <= S0 ; rfsq <= R0 ; end else begin drsq <= ndrsq ; rfsq <= nrfsq ; end end
// dram state sequencer always @( drsq or as_b or a or cpuclk or rfshcyc ) begin case ( drsq ) // S0 : if ( as_b == 0 && {a[31:25],1'b0} == dram && cpuclk && rfshcyc == 0 ) S0 : if ( as_b == 0 && ((a == dram80)|(a == dram81