I wanted to make a class-based memory model (to be later integrated into UVM testbench). It had to be highly configurable through multiple parameters. The first approach was to make it through a parameterized class:
class memory_model #(
parameter int DATA= 32,
parameter int ADDR = 32,
...
) extends uvm_object;
bit [bit [DATA-1 :0]] mem [bit [ADDR-1 :0]];
....
Now, being lazy as I am I found it a bit tedious to have to write bit [ADDR-1 :0], bit [DATA-1 :0], etc., every time in the same class. So I changed the class to this:
class memory_model #(
parameter int DATA= 32,
parameter int ADDR = 32,
...
) extends uvm_object;
typedef bit [DATA-1 :0] mem_data_t;
typedef bit [ADDR-1 :0] mem_addr_t;
bit [mem_data_t] mem [mem_addr_t];
....
I then realized that I would need to use these types later across other related classes, Now the final form of my class is as follows:
class memory_config#(
parameter int DATA= 32,
parameter int ADDR = 32,
...
) extends config_base; // config_base extends uvm_object
typedef bit [DATA-1 :0] mem_data_t;
typedef bit [ADDR-1 :0] mem_addr_t;
....
class memory_model extends uvm_object;
config_base mem_cfg;
bit [mem_cfg::mem_data_t] mem [mem_cfg::mem_addr_t];
....
My question is this the best way to go, or is there a better pattern to follow? And how can I improve this model?