ROM の設定その2

前からある case の中身を吐くだけのクラスはほぼよいので、ちょっと手直ししてラッピングするものを作った。printf がちょろちょろ混ざってるんで、ヒアドキュメントにできればもうちょっときれいになるものの、わからず。(perl みたく $ を付けるわけではないので #{} かな?)

prefix, assignment, safix に別けたのは同期ROM や SDRAM もどきを継承して作ってしまうため。

class AsyncROM
	def initialize(data_width, be)
		@bin = Binary.new(data_width, be, '=')
	end
	def Open(file)
		return @bin.Open(file)
	end
	def prefix(f, name)
		f << '//autogenerated by incdump'
		f << "\n"
		f.printf("module %s #(\n", name)
		f << "\tparameter WAITTIME = 'x\n"
		f << ")(\n"
		f.printf("\tinput [%d:0] a, output [%d:0] d, ", 
			@bin.AddressWidth - 1, @bin.DataWidth - 1)
		f << "input ce, output Wait\n);\n"
	end
	def assignment(f, list)
		f.printf("\tfunction [%d:0] q;\n", @bin.DataWidth - 1)
		f.printf("\t\tinput [%d:0] a;\n", @bin.AddressWidth - 1)
		f << "\t\tcase(a)\n"
		f.printf("default: q = {%d{1'b1}};\n", @bin.DataWidth)
		i = 0
		list.each{|t|
			@bin.Print(f, t)
			if(i < 4)
				i += 1
				f << ' '
			else
				i = 0
				f << "\n"
			end
		}
		if(i != 0)
			f << "\n"
		end
		f << "\t\tendcase\n\tendfunction\n"
	end
	def safix(f)
		f.printf("\tassign #WAITTIME d = ce == 1'b1 ? {%d{1'bz}} : q(a);\n", 
			@bin.DataWidth)
		f << "\tassign #WAITTIME Wait = ~ce;\n"
		f << "endmodule\n"
	end
	
	def Dump(f, modulename, list = nil)
		prefix(f, modulename)
		if(list == nil)
			list = []
			@bin.Size.times{|i|
				list << i
			}
		end
		assignment(f, list)
		safix(f)
	end
end

これを別途生成アプリから呼ぶことにする。今回は単純にこんな感じ。 list が対象アドレスなんだが、ちょっと微妙かもしれない。VRAM 解析してキャラクタアドレスを算出すると重複しまくるから uniq は必須であろう。

require 'd:/work/verilog/incdump.rb'
begin
	f = File.open(ARGV.shift, "w")
	f << '`include "timescale.h"'
	f << "\n"
	rom = AsyncROM.new(8, false)
	romlist = ['a10.bin', '11a.bin', '11b.bin']
	romlist.each{|romimage|
		if(rom.Open(romimage) == false)
			puts romimage + " open error"
			return
		end
	}
	list = [0, 1, 0x10000]
	
	rom.Dump(f, "pcmrom", list)
	f.close
end

こうするとこういう ROM が生成される。

`include "timescale.h"
//autogenerated by incdump
module pcmrom #(
	parameter WAITTIME = 'x
)(
	input [18:0] a, output [7:0] d, input ce, output Wait
);
	function [7:0] q;
		input [18:0] a;
		case(a)
default: q = {8{1'b1}};
19'h00000: q = 8'h40; 19'h00001: q = 8'h3d; 19'h10000: q = 8'h40; 
		endcase
	endfunction
	assign #WAITTIME d = ce == 1'b1 ? {8{1'bz}} : q(a);
	assign #WAITTIME Wait = ~ce;
endmodule

試しにテストベンチに通してみたところいい感じだ。