{"id":571,"date":"2020-11-12T12:29:29","date_gmt":"2020-11-12T12:29:29","guid":{"rendered":"http:\/\/dsd.webs.upv.es\/?page_id=571"},"modified":"2025-08-06T16:51:47","modified_gmt":"2025-08-06T16:51:47","slug":"memorias-ram","status":"publish","type":"page","link":"https:\/\/dsd.webs.upv.es\/?page_id=571","title":{"rendered":"Memorias RAM"},"content":{"rendered":"\n\n\n<h2 class=\"wp-block-heading\"><span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>RAM&nbsp; de lectura as\u00edncrona<\/strong><\/span> <\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As\u00ed se las denomina a las que cambian el puerto de salida cuando cambia la direcci\u00f3n de lectura sin la necesidad de ning\u00fan flanco de reloj adicional <\/li>\n\n\n\n<li>No suele ser posible en la mayor\u00eda de las memorias embebidas de la mayor\u00eda de los fabricantes (XILINX, IntelFPGA, etc)\u200f\n<ul class=\"wp-block-list\">\n<li>Sin embargo es posible en las memoras distribuidas de XILINX que implementan esta memoria con las CLB o slices y no utilizan los bloques embebidos de memoria <\/li>\n\n\n\n<li>Tambi\u00e9n es posible en las nuevas familias Cyclone 10, ARRIA 10 y STRATIX 10 de INtelFPGA mediante los MLAB <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>RAM \u201csingle port\u201d<\/strong><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Entendidas como aquellas memorias que solo disponen de una entrada de direcciones (un solo posible acceso en cada instante) que sirve indistintamente a la escritura como a la lectura<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Ejemplo. Modelo de la memoria as\u00edncrona \u201csingle port\u201d<\/h4>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"toolbar-overlay:false lang:verilog decode:true \">module ram_synch_in (data_in,\naddress, wren, inclock,\nSPO);\nparameter d_width = 16;\nparameter a_width = 6;\ninput [d_width-1:0] data;\ninput [a_width-1:0] address;\ninput wren, inclock;\noutput [d_width-1:0] SPO;\nlogic  [d_width-1:0] mem[(1&lt;&lt;a_width)-1:0];\nalways_ff @(posedge inclock)\u200f\n\tif (wr_en)\u200f\n\t\tmem[address] &lt;=data_in;\n\t\nassign SPO = mem[address];\nendmodule<\/pre><\/div>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nmodule ram_synch_in (data_in,\naddress, wren, inclock,\nSPO);\nparameter d_width = 16;\nparameter a_width = 6;\ninput &#x5B;d_width-1:0] data;\ninput &#x5B;a_width-1:0] address;\ninput wren, inclock;\noutput &#x5B;d_width-1:0] SPO;\nlogic  &#x5B;d_width-1:0] mem&#x5B;(1&amp;lt;&amp;lt;a_width)-1:0];\nalways_ff @(posedge inclock)\u200f\n\tif (wr_en)\u200f\n\t\tmem&#x5B;address] &amp;lt;=data_in;\n\t\nassign SPO = mem&#x5B;address];\nendmodule\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"479\" height=\"268\" src=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-3.png\" alt=\"\" class=\"wp-image-572\" srcset=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-3.png 479w, https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-3-300x168.png 300w\" sizes=\"auto, (max-width: 479px) 100vw, 479px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong><span class=\"has-inline-color has-vivid-cyan-blue-color\">RAM s\u00edncrona<\/span><\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Cambian el puerto de salida cuando cambia la direcci\u00f3n de lectura con la necesidad de un flanco de reloj adicional <\/li>\n\n\n\n<li>Las memorias embebidas de la mayor\u00eda de los fabricantes son de este tipo (XILINX, IntelFPGA, etc)\u200f <\/li>\n\n\n\n<li>La tendencia es que estas memorias sean \u201cTrue Dual port\u201d y que permitan trabajar con relojes independientes en cada uno de los puertos<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">RAM \u00abDUAL port\u00bb<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Disponen de dos entrada de direcciones (dos accesos simult\u00e1neos) si bien en su versi\u00f3n \u201csimple\u201d necesariamente una direcci\u00f3n servir\u00e1 para una acceso de lectura y la otra direcci\u00f3n para un acceso de escritura. <\/li>\n\n\n\n<li>Si estos accesos pueden ser configurados como lectura o escritura independientemente de c\u00f3mo trabaje el otro acceso estaremos hablando de \u201cTrue Dual Port\u201d<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">RAM s\u00edncrona \u00abSimple Dual Port\u00bb<\/h4>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"479\" height=\"276\" src=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-4.png\" alt=\"\" class=\"wp-image-575\" srcset=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-4.png 479w, https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-4-300x173.png 300w\" sizes=\"auto, (max-width: 479px) 100vw, 479px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Existen dos estilos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Registrar el puerto de salida\n<ul class=\"wp-block-list\">\n<li>Hist\u00f3ricamente era m\u00e1s natural para XILINX que para IntelFPGA cuando se utiliza un sintetizador generalista: Leonardo, Synplify. Lo cual obliga a utilizar muchas veces pragmas para ayudar a la inferencia sobre IntelFPGA.<\/li>\n\n\n\n<li>Con el sintetizador de Quartus no hace falta pragmas y no infiere autom\u00e1ticamente \u201dglue logic\u201d para evitar desavenencias pre-post s\u00edntesis en el caso de lectura y escritura simult\u00e1nea sobre la misma direcci\u00f3n, de lo cual eres advertido.<\/li>\n\n\n\n<li>Da una idea de que si utilizamos el mismo reloj para ambos puertos y escribimos y leemos de la misma direcci\u00f3n, el dato extra\u00eddo por el puerto de salida ser\u00eda el antiguo.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nmodule ram_dp #(parameter mem_depth=32, parameter size=8)\n(\ninput &#x5B;size-1:0] data,\ninput wren,clock1,clock2,rden,\ninput &#x5B;$clog2(mem_depth-1)-1:0] wraddress, \ninput &#x5B;$clog2(mem_depth-1)-1:0] rdaddress,\noutput logic &#x5B;size-1:0] DPO\n);\nlogic &#x5B;size-1:0] mem &#x5B;mem_depth-1 :0];\nalways_ff @(posedge clock1)\n  if (wren==1&#039;b1)\n        mem&#x5B;wraddress]&amp;lt;=data_in;\nalways_ff @(posedge clock2)\n  if (rden==1&#039;b1)\n        DPO&amp;lt;=mem&#x5B;rdaddress];   \n   \nendmodule \n<\/pre><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>Registrar la direcci\u00f3n de lectura\n<ul class=\"wp-block-list\">\n<li>Hist\u00f3ricamente era m\u00e1s natural\u00a0 para IntelFPGA cuando se utiliza un sintetizador generalista: Leonardo, Synplify.<\/li>\n\n\n\n<li>En el caso del sintetizador de Quartus . Si a\u00f1ade l\u00f3gica adicional para evitar desavenencias para el caso simult\u00e1neo de lectura y escritura sobre la misma direcci\u00f3n<\/li>\n\n\n\n<li>Da una idea de que si utilizamos el mismo reloj para ambos puertos y escribimos y leemos de la misma direcci\u00f3n, el dato extra\u00eddo por el puerto de salida ser\u00eda el nuevo.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: systemverilog; title: ; notranslate\" title=\"\">\nmodule ram_dp #(parameter mem_depth=32, parameter size=8)\n(\ninput &#x5B;size-1:0] data,\ninput wren,clock1,clock2,rden,\ninput &#x5B;$clog2(mem_depth-1)-1:0] wraddress, \ninput &#x5B;$clog2(mem_depth-1)-1:0] rdaddress,\noutput logic &#x5B;size-1:0] DPO\n);\nlogic &#x5B;size-1:0] mem &#x5B;mem_depth-1 :0];\nlogic &#x5B;$clog2(mem_depth-1)-1:0] rdaddress_reg,\t\t\t\nalways_ff @(posedge clock1)\n  if (wren==1&#039;b1)\n        mem&#x5B;wraddress]&amp;lt;=data_in;\nalways_ff @(posedge clock2)\n  if (rden==1&#039;b1)\n\trdaddress_reg&amp;lt;=rdaddress;          \n   \nassign DPO&amp;lt;=mem&#x5B;rdaddress_reg]; \nendmodule\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\"><span class=\"has-inline-color has-vivid-cyan-blue-color\">Inferencia de memorias RAM<\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Todos los c\u00f3digos expuestos intentan que tu SystemVerilog infiera autom\u00e1ticamente la RAM de las caracter\u00edsticas deseadas. Sin embargo hay que reconocer que a veces hay que leerse la letra peque\u00f1a del sintetizador que tienes entre manos para conseguir exactamente lo que deseas y muy posiblemente tengas que recurrir a pragmas y atributos espec\u00edficos de la herramienta<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por ejemplo es posible que desees que el sintetizador utilice una alternativa espec\u00edfica de implementaci\u00f3n (si memorias embebidas o utilizaci\u00f3n de logic cells) y que no introduzca l\u00f3gica adicional para evitar desavenencias pre-post s\u00edntesis. En Quartus deber\u00edamos emplear el siguiente atributo que se colocar\u00eda antes de la declaraci\u00f3n del array bidimensional:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li> (* ramstyle = \u00abMLAB, no_rw_check\u00bb *)\u00a0 logic [d_width-1:0] mem[1&lt;&lt;a_width:0]\/ ;<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>RAM&nbsp; de lectura as\u00edncrona RAM \u201csingle port\u201d Entendidas como aquellas memorias que solo disponen de una entrada de direcciones (un solo posible acceso en cada instante) que sirve indistintamente a la escritura como a la lectura Ejemplo. Modelo de la memoria as\u00edncrona \u201csingle port\u201d module ram_synch_in (data_in, address, wren, inclock, SPO); parameter d_width = 16; parameter a_width = 6; input [d_width-1:0] data; input [a_width-1:0] address; input wren, inclock; output [d_width-1:0] SPO; logic [d_width-1:0] mem[(1&lt;&lt;a_width)-1:0]; always_ff @(posedge inclock)\u200f if (wr_en)\u200f mem[address] &lt;=data_in; assign SPO = mem[address]; endmodule RAM s\u00edncrona RAM \u00abDUAL port\u00bb RAM s\u00edncrona \u00abSimple Dual Port\u00bb Existen dos estilos: Inferencia de memorias RAM Todos los c\u00f3digos expuestos intentan que tu SystemVerilog infiera autom\u00e1ticamente la RAM de las caracter\u00edsticas deseadas. Sin embargo hay que reconocer que a veces hay que leerse la letra peque\u00f1a del sintetizador que tienes entre manos para conseguir exactamente lo que deseas y muy posiblemente tengas que recurrir a pragmas y atributos espec\u00edficos de la herramienta Por ejemplo es posible que desees que el sintetizador utilice una alternativa espec\u00edfica de implementaci\u00f3n (si memorias embebidas o utilizaci\u00f3n de logic cells) y que no introduzca l\u00f3gica adicional para evitar desavenencias pre-post s\u00edntesis. En Quartus deber\u00edamos emplear el siguiente atributo que se colocar\u00eda antes de la declaraci\u00f3n del array bidimensional:<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":568,"menu_order":1,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ub_ctt_via":"","footnotes":""},"class_list":["post-571","page","type-page","status-publish","hentry"],"featured_image_src":null,"_links":{"self":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/571","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=571"}],"version-history":[{"count":14,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/571\/revisions"}],"predecessor-version":[{"id":1860,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/571\/revisions\/1860"}],"up":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/pages\/568"}],"wp:attachment":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=571"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}