SRAMコントローラ

コネクタのピンが足りないので、データバス16bitとアドレスバス16bitを1つの線で共有する方式にした。これは元から CPU がその方式だったことが大きい。

declare ohram_controller{
	input cpu_a[21]; input cpu_select, cpu_rw; 
	input cpu_d[16]; output cpu_q_t[16]; output cpu_dtack_t;
	output ohram_a20; inout ohram_a[4]; inout ohram_adq[16];
	output ohram1_ce_t, ohram2_ce_t, ohram_oe_t, ohram_we_t, 
		ohram_ahe, ohram_ale_t;
}
module ohram_controller{
	reg cpu_select_history;
	cpu_select_history := cpu_select;
	
	
	ohram_ahe = 1;
	ohram_a20 = cpu_a[19];
	ohram_a = /*if(ohram_ahe == 0) 4'hz else*/ cpu_a[18:15];
	{
		reg cpu_q[16];
		reg cpu_dtack;
		reg ohram_d[16];
		reg ohram_ale, ohram1_ce = 1, ohram2_ce = 1;
		reg ohram_we = 1, ohram_oe = 1;
		reg access_wait[2];

		state_name IDLE, ADDRESS_LATCH, WRITE_L, READ_L, WRITE_READ_H;
		state IDLE{
			if(cpu_select_history == 1'b1 && cpu_select == 1'b0){
				ohram_d := {cpu_a[14:0], 1'b0};
				ohram_ale := 0;
				cpu_dtack := 1'b1;
				goto ADDRESS_LATCH;
			}else{
				ohram1_ce := 1;
				ohram2_ce := 1;
			}
		}
		state ADDRESS_LATCH{
			ohram_ale := 1;
			ohram1_ce := cpu_a[20];
			ohram2_ce := ~cpu_a[20];
			if(cpu_rw == 0){
				goto WRITE_L;
			}else{
				goto READ_L;
			}
		}
		state WRITE_L{ //wait 35ns
			ohram_d := cpu_d;
			ohram_we := 0;
			access_wait := 2;
			goto WRITE_READ_H;
		}
		state READ_L{ //after 22ns, data valid
			ohram_oe := 0;
			access_wait := 2;
			goto WRITE_READ_H;
		}
		state WRITE_READ_H{
			if(access_wait == 0){
				cpu_q := ohram_adq;
				ohram_we := 1;
				ohram_oe := 1;
				cpu_dtack := 1'b0;
				goto IDLE;
			}else{
				access_wait--;
			}
		}
	}
	cpu_q_t = cpu_q;
	cpu_dtack_t = cpu_dtack;
	ohram_adq = if(ohram_oe == 1'b1 && cpu_select == 1'b0) 
		ohram_d else 16'hzzzz;
	ohram1_ce_t = ohram1_ce;
	ohram2_ce_t = ohram2_ce;
	ohram_ale_t = ohram_ale;
	ohram_we_t = ohram_we;
	ohram_oe_t = ohram_oe;
}

verilog ソースに変換してシミュレータを動かしてみると write は問題ないのだが、 read でバスが衝突するみたいだ。変換したソースをみたところ下記のようになっててちゃんと動かない。(長い行は勝手に改行を入れた)

   assign  _net_23 = ( (ohram_oe)==(1'b1) )&( (cpu_select)==(1'b0) );
   assign  _net_24 = {
   _net_23,_net_23,_net_23,_net_23,_net_23,_net_23,_net_23,_net_23,
   _net_23,_net_23,_net_23,_net_23,_net_23,_net_23,_net_23,_net_23};
   assign  ohram_adq = (1'b1)?
    (_net_24&ohram_d)|((~_net_24)&16'bZZZZZZZZZZZZZZZZ):16'bZ;

3state の切り替えがうまくいっていないので手作業で直してちゃんと動いた。

   assign  ohram_adq = _net_23 ? ohram_d : 16'hzzzz

実機に持っていてもちゃんと動いたのでいいのだが、現状では nsl のよろしくない点は下記である。

  • output reg が定義できないので似た配線命名が必要 (以前も書いた)
  • 分周処理がやりづらい (以前も書いた)
  • バスの LSB が 0 固定なので、 68000 の様に A0 を使わないアドレスバス設定のソースが分かりづらい。実際にそれでバグを見つけるのに手間取った。
  • 桁数の出力が変なときがある。上記の 16'bZ がそう。
  • 3 state は現状ではちゃんと生成されない
  • 遅延定義がないので、シミュレーションコードは結局 verilog で書く

state machine なんかは verilog よりもタイプ数が少ないのでいけると思うので、分周も 3state もない、 tilemap renderer でも使ってみるかな。