memory class
シミュレーションをするためのクラスを再度作成。address, data の幅を可変にするためにテンプレートを使用する。その他外部との配線の prefix をかえたり、 protected メンバにする。
template <typename datarange, typename addressrange> class SimROM : public sc_module { protected: datarange *const m_data; const uint32_t m_size; sc_in<bool> w_reset, w_clock; sc_in<addressrange> w_a; sc_out<datarange> w_q; void qout(void) { uint32_t a = w_a.read(); assert(a < m_size); w_q.write(m_data[a]); } virtual void thread() { while(true){ wait(w_clock.posedge_event()); qout(); } } public: SC_HAS_PROCESS(SimROM); void Connect(sc_signal<bool> reset, sc_signal<bool> clock, sc_signal<addressrange> a, sc_signal<datarange> q) { w_reset(reset); w_clock(clock); w_a(a); w_q(q); } SimROM(sc_module_name n, int size) : sc_module(n), m_data(new datarange [size]), m_size(size), w_reset("p_reset"), w_clock("m_clock"), w_a("a"), w_q("q") { SC_THREAD(thread); } virtual ~SimROM() { delete [] m_data; } };
RAM クラスは ROM に書き込み端子が付いたものとして、 SimROM class を継承する。RAM も address と data の幅を可変にしないといけないので基底クラスへのテンプレートもテンプレートして渡さないといけない。
template <typename D, typename A> class SimRAM : public SimROM <D, A> { protected: sc_in<D> w_d; sc_in<bool> w_we; void thread(void) { while(true){ wait(SimROM<D, A>::w_clock.posedge_event()); SimROM<D, A>::qout(); if(w_we.read() == 1){ SimROM<D, A>::m_data[SimROM<D, A>::w_a.read()] = w_d.read(); } } } public: SC_HAS_PROCESS(SimRAM); SimRAM(sc_module_name n, int size) : SimROM<D, A>::SimROM(n, size), w_d("d"), w_we("we") { } };
エラーのでない形に持っていくのが大変で解決方法が検索してもよくわからず、 gcc の出すエラーを元に組み合わせたらこの形になった。テンプレート->テンプレートの場合は継承した protected メンバにアクセスするにしろ、基底クラスと使うテンプレートを明示しないといけないらしい。
理由はよくわからなくて、記述が冗長になるのでめんどい。
次に RAM 読み込み初期化クラスを作る。現状ではただの ROM になっていたので ROM として継承する。(近いうちに RAM にしないとダメ)
class ColorRAM : public SimROM <uint16_t, uint8_t> { private: //LE.16 bit4:0 void load(const char *name, uint16_t *d, size_t length) { load_le16(name, d, length); while(length != 0){ *d++ &= 0x1f; length--; } } public: ColorRAM(sc_module_name n, const char *filename) : SimROM(n, 0x100) { size_t l = 0x100; uint16_t *const dd = new uint16_t [l * 3]; uint16_t *d = dd; uint16_t *rom = m_data; load(filename, d, l * 3); while(l != 0){ *rom = d[0]; *rom |= d[0x100] << 5; *rom |= d[0x200] << 10; rom += 1; l--; } delete [] dd; } };
bus の幅はこの時点で決定しているので RAM のようなベースの記述はいらなくなる。ここまで来るとようやく簡潔な記述にすることが出来る。この段階で RAM イメージのバイトオーダーとか data bus の幅を意識した変換コードに注力できる。