Thanks, I did not mean to use vendors IP cores, every body knows that they should use them, I meant that how we can model or code a piece of Dual port ram with different data widths for example to be implemented in an ASIC or to know how it's internals should work out of curiosity!
Look at any vendor's block RAM simulation model that supports different aspect ratios for the memory access. Be warned: some of those models are written in ancient dialects of the languages.
That said, it's not all that difficult. (I use VHDL, so the points here are made for that language. I'm sure SystemVerilog has similar.)
For a single-port memory, or a dual-port with only one write side, you use a signal to model the memory. The trick is that each side of a true dual port memory has its own clock, and each clock domain means separate processes, one for each. And remember how HDL processes (or always blocks) work: the process creates a driver for each signal assigned within. If you have more than one process assigning to a signal, you get more than one driver for that signal. And generally that's bad. You'll get a complier complaint.
So the usual way to manage multiple processes assigning to a signal is to use a shared variable. Remember in VHDL, a variable normally exists only within a process. That means it can only be assigned in the process in which it is declared, and it can only be read in that process. A shared variable removes that process-only restriction: it can be accessed anywhere in the architecture of the entity in which it is declared.
Old vendor models use that. There are processes for each domain which can assign to the shared variable memory array and read from it. But there's an obvious danger. What happens when both sides attempt to write to the memory simultaneously? (This is a problem in the real memory, which is where there is a distinction about "read first," "write first," and so on.)
This was recognized by the maintainers of VHDL, so in modern VHDL-2008, the idea of a "protected type" was introduced. And you model the memory as a protected type. The cool thing about protected types is that they are like a C++ class. You use setters and getters (procedures) to access the memory.
The gotcha is that with VHDL-2008 and later, all shared variables must be a protected type, and if you analyze old code with 2008, the compile will complain.
For a dual-port memory model, you create a protected type that includes the data and the accessor methods, and then you declare a shared variable of that type. Then all accesses to that variable's data are done with the accessor methods, and those methods can be called from anywhere within the architecture.
This is actually a very cool feature. Don't expect much of it to be synthesizable, but for modeling and verification it's great.