キャラクタROMの容量減らし

lineview から出している画は、エミュレータから VRAM をダンプしてそれを作成中の互換回路に読み込ませて同じ画が出るか確認する。座標とか色を管理する VRAM のサイズはたいしたことがないのだが、キャラクタ ROM のサイズはそれと比較すると大きくて 1MB 以上ということもざらにある。

回路規模(→メモリサイズ)が大きくなると、シミュレータの処理が露骨に遅くなり、1画面(16.6ms)出すのに10分かかるということもある。それはやってられないので、パンクショットでは同じビデオ回路を使っていてキャラクタROMのサイズが小さいクォースでテストをしていた。

これでもおそいし、毎回キャラクタROMの容量が少ない場合もあるわけではないということで、 VRAM イメージを verilog ソースに変換するついでに中身を解析し、VRAM が指定しているキャラクタ ROM だけ出力すればいいのではと思いついた。*1

というわけで RAM データを verilog ソースに変換するソース。

class Memory
	def address_width_get(size)
		size -= 1
		width = 0
		while size != 0
			width += 1
			size >>= 1
		end
		return width
	end
	
	def width_to_syntax(width)
		keta = width / 4
		if(width % 4 != 0)
			keta += 1
		end
		
		return sprintf("%d'h%%0%dx", width, keta)
	end
	
	def initialize(buf, datawidth, q = 'q', op = '<=')
		@buf = buf
		datawidth
		a = width_to_syntax(address_width_get(buf.size))
		d = width_to_syntax(datawidth)
		#18'h01234: q <= 16'h89ab;
		@syntax = sprintf("%s: %s %s %s;", a, q, op, d)
		@default = sprintf("default: %s %s %d'hx;", q, op, datawidth)
		
		@datamask = 0
		datawidth.times{
			@datamask <<= 1
			@datamask |= 1
		}
	end
	
	def Dump(f = $stdout)
		linepardata = 0
		str = ''
		adddress = 0
		
		@buf.each{|t|
			str += sprintf(@syntax, adddress, t & @datamask)
			adddress += 1
			linepardata += 1
			if(linepardata < 2)
				str += ' '
			else
				linepardata = 0
				f.puts str
				str = ''
			end
		}
		if str != ''
			f.puts str
		end
	end
end

Memory クラスは初期化時に渡した配列を全てダンプするクラス。場合によって always でつかうか function でつかうか別れるので代入先と演算子も替えられるようにしてある。

class MemoryList < Memory
	def Dump(list, f = $stdout)
		linepardata = 0
		str = ''

		list.uniq.sort.each{|a|
			str += sprintf(@syntax, a, @buf[a] & @datamask)
			linepardata += 1
			if(linepardata < 2)
				str += ' '
			else
				linepardata = 0
				f.puts str
				str = ''
			end
		}
		if str != ''
			f.puts str
		end
		f.puts @default
	end
end

継承する必要性はあまりない気がするが、Dump メソッドを変更。list に使用するアドレスを配列につっこんで吐かせる。重複は削除、見た目も直すと言うことで、 uniq.sort.each の順におこなう。これであっさりとデータが出せる Ruby は素敵だ。

とりあえずこれをやってみて様子をみてみたら、1発で絵が出るようになった。処理時間は1分かかるので満足ではないが時間の短縮はできるし、パズルゲームを必死に探さなくても済むのは大きい。

昨日のちょっと崩れた絵は未定義のアドレスをアクセスした場合で不定値を出しているんだが、場合によっては warning を出すなり、シミュレートを中断した方がいいかもと思った。

*1:普通なら先に思いつくかもしれないが、それはおいておいて。