存储器的设计 寻址存储器(RAM和ROM) ROM和RAM属于通用大规模器件,一般不需要自行设 计,特别是采用PLD器件进行设计时 但是在数字系统中,有时也需要设计一些小型的存储器 件,用于特定的用途:临时存放数据,构成查表运算等。 此类器件的特点为地址与存储内容直接对应,设计时将 输入地址作为给出输出内容的条件; RAM随机存储器 RAM的用途是存储数据,其指标为存储容量和字长; RAM的内部可以分为地址译码和存储单元两部分 外部端口为:wr写读控制cs片选 d数据端口adr地址端口 例16x8位RAM的设计 设计思想 将每个8位数组作为一个字(word);总共存储16个字; 将ram作为由16个字构成的数组,以地址为下标 通过读写控制模式实现对特定地址上字的读出或写入; library ieee Ise ieee std logic 1164. all; use ieee std logic unsigned. all
存储器的设计 寻址存储器(RAM 和 ROM) ROM 和 RAM 属于通用大规模器件,一般不需要自行设 计,特别是采用 PLD 器件进行设计时; 但是在数字系统中,有时也需要设计一些小型的存储器 件,用于特定的用途:临时存放数据,构成查表运算等。 此类器件的特点为地址与存储内容直接对应,设计时将 输入地址作为给出输出内容的条件; RAM 随机存储器 RAM 的用途是存储数据,其指标为存储容量和字长; RAM 的内部可以分为地址译码和存储单元两部分; 外部端口为: wr 写读控制 cs 片选 d 数据端口 adr 地址端口 例 16x8 位 RAM 的设计 设计思想: 将每个 8 位数组作为一个字(word);总共存储 16 个字; 将 ram 作为由 16 个字构成的数组,以地址为下标; 通过读写控制模式实现对特定地址上字的读出或写入; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all;
entity kram is port( clk, wr, cs: in std logic; d inout std log 0); adr in std logic vector(3 downto O)) end kram architecture beh of kram i subtype word is std logic vector(7 downto 0) type memory is array(0 to 15)of word signal adr in integer range0 to 15 gnal sram memory dr in<=conv integer(adr) process(clk) if(clk'event and clk='I)then if(cs=I'and wr=")then sram(adr in)<=d end if if(cs=I'and wr0')then end if nd if end process, RAM的数据端口通常为 Inout模式,设置仿真输入时只 能在写入时将信号加到该输入端口上,在其他时候输入应设 置为高阻态 RAM设计时需要注意器件的大小,一个16x8位的RAM 大约占用200个门,而256x16的RAM则需要6200门以上
entity kram is port ( clk,wr,cs: in std_logic; d: inout std_logic_vector(7 downto 0); adr: in std_logic_vector(3 downto 0)); end kram; architecture beh of kram is subtype word is std_logic_vector(7 downto 0); type memory is array (0 to 15) of word; signal adr_in:integer range 0 to 15; signal sram:memory; begin adr_in<=conv_integer (adr); process(clk) begin if(clk'event and clk='1') then if (cs='1'and wr='1') then sram (adr_in)<=d; end if; if (cs='1'and wr='0' ) then d<=sram (adr_in); end if; end if; end process; end beh; RAM 的数据端口通常为 inout 模式,设置仿真输入时只 能在写入时将信号加到该输入端口上,在其他时候输入应设 置为高阻态; RAM 设计时需要注意器件的大小,一个 16x8 位的 RAM 大约占用 200 个门,而 256x16 的 RAM 则需要 6200 门以上
因此大规模RAM不适合于采用PLD设计,最好采用通用器 ROM只读存储器 ROM的内容是初始设计电路时就写入到内部的,通常采 用电路的固定结构来实现存储;ROM只需设置数据输出端口 和地址输入端口 例1简单ROM的设计(16x8位ROM) 设计思想:采用二进制译码器的设计方式,但将每个输入组 态对应的输出与一组存储数据对应起来; library ieee use ieee std logic 1164. all entity rom Is port(dataout: out std logic vector( 7 downto 0) addr: in std logic vector(3 downto o) ce: in std logic) end rom architecture d of rom is dataout <=00001111 when addr=0000 "and ce=o else 11110000 "when addr =0001"and ce=o' else 11001100" when addr=0010" and ce=o' else 00110011" when addr=0011"and ce=o' else 10101010 when addr=0100"and ce=o' else 01010101 when addr=0101"and ce=o' else 1001 1001"when addr =0110" and ce=o' else
因此大规模 RAM 不适合于采用 PLD 设计,最好采用通用器 件; ROM 只读存储器 ROM 的内容是初始设计电路时就写入到内部的,通常采 用电路的固定结构来实现存储;ROM 只需设置数据输出端口 和地址输入端口; 例 1 简单 ROM 的设计(16x8 位 ROM) 设计思想:采用二进制译码器的设计方式,但将每个输入组 态对应的输出与一组存储数据对应起来; library ieee; use ieee.std_logic_1164.all; entity rom is port(dataout: out std_logic_vector(7 downto 0); addr: in std_logic_vector(3 downto 0); ce: in std_logic); end rom; architecture d of rom is begin dataout <= "00001111" when addr ="0000" and ce='0' else "11110000" when addr ="0001" and ce='0' else "11001100" when addr ="0010" and ce='0' else "00110011" when addr ="0011" and ce='0' else "10101010" when addr ="0100" and ce='0' else "01010101" when addr ="0101" and ce='0' else "10011001" when addr ="0110" and ce='0' else
" 01100110" when addr=0111" and ce= o' else 00000000"when addr="1000"and ce=o' else 11111111"when addr=1001" and ce=o' else "00010001"when addr=1010"and ce=o' else 10001000"when addr=1011"and ce=0 else 10011001"when addr ="1100"and ce=o' else 01100110" when addr=1101"and ce=o' else 10100110"when addr=1110" and ce=o' else 01100111" when addr="1111"and ce=o else XXXXXXXX 对于较大的ROM,可以采用结构设计的方法,直接调用 参数化模块进行设计 例ROM的LPM设计(256x8位ROM library ieee, use ieee std logic 1164. all library lpm use lpm Ipm components.all; port(address in std logic vector(7 downto 0); clock in std logic. g: out std logic vector(7 downto O)); d ron architecture str of romlpm is signal sub wireD: std logic vector(7 downto 0) q8 m w
"01100110" when addr ="0111" and ce='0' else "00000000" when addr ="1000" and ce='0' else "11111111" when addr ="1001" and ce='0' else "00010001" when addr ="1010" and ce='0' else "10001000" when addr ="1011" and ce='0' else "10011001" when addr ="1100" and ce='0' else "01100110" when addr ="1101" and ce='0' else "10100110" when addr ="1110" and ce='0' else "01100111" when addr ="1111" and ce='0' else "XXXXXXXX"; end d; 对于较大的 ROM,可以采用结构设计的方法,直接调用 参数化模块进行设计; 例 ROM 的 LPM 设计 (256x8 位 ROM) library ieee; use ieee.std_logic_1164.all; library lpm; use lpm.lpm_components.all; entity romlpm is port(address: in std_logic_vector(7 downto 0); inclock: in std_logic; q: out std_logic_vector(7 downto 0)); end romlpm; architecture str of romlpm is signal sub_wire0:std_logic_vector(7 downto 0); begin q8, lpm_widthad =>8
Ipm address control=>"registered Ipm outdata=>"unregistered pm file→>"krom2mif") port map( address=>address inclock->inclock q=>sub wire) end str: ROM的初始化 在ROM的设计中,必须要预先设置好数据存储文件,这 是一种以mf为后缀的文本文件,在任何文本编辑器中,按如 下文件格式写入: DEPTH=16;字线数量 WIDT 位线数量 ADDRESS RADIX=HEX;地址与数据的表达类型 DATA RADIX=HEX;可以选择: HEX OCT DEC BIN CONTENT 存储内容地址:数据 BEGIN [0.F] 4567; FE5 END 文件写完后,保存为mif即可。 例:4位查表式乘法器设计 功能:将两个4位二进制数A和B相乘,输出乘积结果 C(8位二进制数) 设计方案:采用256x8位ROM实现,8位地址输入(高 4位为A,低4位为B),256个存储字;8位数据输出 数据存储文件(krom2.mif):填写相应的乘法表即可 depth=256; width=8
lpm_address_control=>"registered", lpm_outdata => "unregistered", lpm_file=> "krom2.mif") port map( address=>address, inclock=>inclock, q =>sub_wire0); end str; ROM 的初始化 在 ROM 的设计中,必须要预先设置好数据存储文件,这 是一种以.mif 为后缀的文本文件,在任何文本编辑器中,按如 下文件格式写入: DEPTH = 16; 字线数量 WIDTH = 4; 位线数量 ADDRESS_RADIX = HEX; 地址与数据的表达类型 DATA_RADIX = HEX; 可以选择:HEX OCT DEC BIN CONTENT 存储内容 地址 :数据; BEGIN [0..F] : 3; 2 : 4 5 6 7; 8 : F E 5; END ; 文件写完后,保存为.mif 即可。 例:4 位查表式乘法器设计 功能:将两个 4 位二进制数 A 和 B 相乘,输出乘积结果 C(8 位二进制数); 设计方案:采用 256x8 位 ROM 实现,8 位地址输入(高 4 位为 A,低 4 位为 B),256 个存储字;8 位数据输出; 数据存储文件(krom2.mif): 填写相应的乘法表即可 depth = 256; width = 8;
address radix= hex data radix hex content [00.0f]:00; 10:000102030405060708090a0b0c0doe0f, 20:00020406080a0c0e1012141618 la lc le; 30:000306090c0f121518ble2124272a2d 40:0004080c101418lc2024282c3034383c 50:00050aof1419ld23282d32373c41464b 60:00060c1218le242a30363c42484e545a 70:00070e15lc232a31383f464d545b6269 80:00081018202830384048505860687078; 90:009121b242d363f48515a636c757e87; a0:000a14le28323c46505a646e78828c96; b0:000b16212c37424d58636e79848f9aa5 c0:000c1824303c4854606c7884909ca8b4 d0:000dla27344l4e5b6875828f9ca9b6c3; e0:000elc2a38465462707e8c9aa8b6c4d2 f0: 00 Of le 2d 3c 4b 5a 66788796 a5 b4 c3 d2 el end 该乘法器ROM设计完毕后,将其设置为符号文件,将来 就可以在VHDL程序中用 component语句调用了。 在 maxplus2的仿真器窗口内,也可以直接生成ROM的 初始化文件,其步骤如下 选择 Initialize/ nitialize Memory 按ROM地址输入数据 存盘即可生成指定的mif文件(文件名已经在结构体内 指明)
address_radix = hex; data_radix = hex; content begin [00..0f] : 00 ; 10 : 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f; 20 : 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e; 30 : 00 03 06 09 0c 0f 12 15 18 1b 1e 21 24 27 2a 2d; 40 : 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c; 50 : 00 05 0a 0f 14 19 1d 23 28 2d 32 37 3c 41 46 4b; 60 : 00 06 0c 12 18 1e 24 2a 30 36 3c 42 48 4e 54 5a; 70 : 00 07 0e 15 1c 23 2a 31 38 3f 46 4d 54 5b 62 69; 80 : 00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78; 90 : 00 09 12 1b 24 2d 36 3f 48 51 5a 63 6c 75 7e 87; a0 : 00 0a 14 1e 28 32 3c 46 50 5a 64 6e 78 82 8c 96; b0 : 00 0b 16 21 2c 37 42 4d 58 63 6e 79 84 8f 9a a5; c0 : 00 0c 18 24 30 3c 48 54 60 6c 78 84 90 9c a8 b4; d0 : 00 0d 1a 27 34 41 4e 5b 68 75 82 8f 9c a9 b6 c3; e0 : 00 0e 1c 2a 38 46 54 62 70 7e 8c 9a a8 b6 c4 d2; f0 : 00 0f 1e 2d 3c 4b 5a 66 78 87 96 a5 b4 c3 d2 e1; end; 该乘法器 ROM 设计完毕后,将其设置为符号文件,将来 就可以在 VHDL 程序中用 component 语句调用了。 在 maxplus2 的仿真器窗口内,也可以直接生成 ROM 的 初始化文件,其步骤如下: 选择 Initialize/Initialize Memory…; 按 ROM 地址输入数据; 存盘即可生成指定的 mif 文件(文件名已经在结构体内 指明);
顺序存储器(堆栈和FIFO) 顺序存储器的特点是不设置地址,所有数据的写入和读 出都按顺序进行;数据写入或读出时通常会进行移位操作; 在设计时必须考虑各存储单元的存储状态: 堆栈(后进先出存储器) 要求:存入数据按顺序排放,存储器全满时给出信号并拒绝 继续存入;读出时按后进先出原则;存储数据一旦读出就从 存储器中消失; 设计思想: 将每个存储单元设置为字(word):存储器整体作为由字 构成的数组;为每个字设置一个标记(fag),用以表达该存 储单元是否已经存放了数据;每写入或读出一个数据时,字 的数组内容进行相应的移动,标记也做相应的变化 程序示例: use ieee std logic 1164. all use ieee std logic arith. all port(datain: in std logic vector(7 downto O); push, pop, reset, clk in std logic stackfull: out std logic, dataout: buffer std logic vector(7 downto O)) end stack
顺序存储器(堆栈和 FIFO) 顺序存储器的特点是不设置地址,所有数据的写入和读 出都按顺序进行;数据写入或读出时通常会进行移位操作; 在设计时必须考虑各存储单元的存储状态; 堆栈(后进先出存储器) 要求:存入数据按顺序排放,存储器全满时给出信号并拒绝 继续存入;读出时按后进先出原则;存储数据一旦读出就从 存储器中消失; 设计思想: 将每个存储单元设置为字(word);存储器整体作为由字 构成的数组;为每个字设置一个标记(flag),用以表达该存 储单元是否已经存放了数据;每写入或读出一个数据时,字 的数组内容进行相应的移动,标记也做相应的变化; 程序示例: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_signed.all; entity stack is port(datain: in std_logic_vector(7 downto 0); push,pop,reset,clk:in std_logic; stackfull:out std_logic; dataout: buffer std_logic_vector(7 downto 0)); end stack;
architecture b of stack is type arraylogic is array (15 downto 0) of std logic vector(7 signal stackflag: std logic vector(15 downto O) stackfull0); dataout0) for i in 0 to 15 loop data(1) if stackflag(00 then data(15)=datain stackflagnull end case
architecture b of stack is type arraylogic is array(15 downto 0) of std_logic_vector(7 downto 0); signal data :arraylogic; signal stackflag:std_logic_vector(15 downto 0); begin stackfull'0'); dataout'0'); for i in 0 to 15 loop data(i) if stackflag(0)=’0’ then data(15) dataoutnull; end case;
end if end process 以上程序是基于移位寄存器的设计思想;若基于存储器 的设计思想,则可以设置一个指针( point),表示出当前写入 或读出单元的地址,使这种地址进行顺序变化,就可以实现 数据的顺序读出或写入 程序示例 library说明和entt设计与上面程序完全相同 chitecture b of stack type arraylogic is array(15 downto 0) of std logic vector(7 downto 0) signal data arraylogic process(clk, reset, pop, push) variable p natural range 0 to 15 variable selfunction: std logic vector( I downto 0) variable s std logic beg selfunction: =push& pop; if reset='l' then for i in 0 to 15 loop data()<="0000000 nd lo elsif clk'event and clk=l' then if p<15 and selfunction="10"then data(p)=datain; p: =p+ if p=15 and selfunction="10"and s=o' then
end if; end process; end b; 以上程序是基于移位寄存器的设计思想;若基于存储器 的设计思想,则可以设置一个指针(point),表示出当前写入 或读出单元的地址,使这种地址进行顺序变化,就可以实现 数据的顺序读出或写入; 程序示例 library 说明和 entity 设计与上面程序完全相同; architecture b of stack is type arraylogic is array(15 downto 0) of std_logic_vector(7 downto 0); signal data :arraylogic; begin process(clk,reset,pop,push) variable p:natural range 0 to 15; variable selfunction: std_logic_vector(1 downto 0); variable s:std_logic; begin stackfull'0');s:='0'; for i in 0 to 15 loop data(i)<="00000000"; end loop; elsif clk'event and clk='1' then if p<15 and selfunction="10" then data(p)<=datain; p:=p+1; end if; if p=15 and selfunction="10" and s='0' then
data(p)=datain; S:=l if p>0 and selfunction="01"and s=0 then p:=p-1; dataout<=data(p) end if if p=15 and selfunction="Ol"and s=lthen dataout<=data(p); S:=0 end if end if end b: FIFO(先进先出存储器 要求:存入数据按顺序排放,存储器全满时给出信号并拒绝 继续存入,全空时也给出信号并拒绝读出;读出时按先进先 出原则:存储数据一旦读出就从存储器中消失 设计思想: 结合堆栈指针的设计思想,采用环行寄存器方式进行设 计:分别设置写入指针wp和读出指针rp,标记下一个写入地 址和读出地址;地址随写入或读出过程顺序变动;设置全空 标记和全满标记以避免读出或写入的错误 设计时需要注意处理好从地址最高位到地址最地位的变 化 程序示例 use ieee std logic 1164 al se ieee std logic arith. all use ieee std logic signed. all
data(p)0 and selfunction="01" and s='0' then p:=p-1; dataout<=data(p); end if; if p=15 and selfunction="01" and s='1' then dataout<=data(p); s:='0'; end if; end if; end process; end b; FIFO(先进先出存储器) 要求:存入数据按顺序排放,存储器全满时给出信号并拒绝 继续存入,全空时也给出信号并拒绝读出;读出时按先进先 出原则;存储数据一旦读出就从存储器中消失; 设计思想: 结合堆栈指针的设计思想,采用环行寄存器方式进行设 计;分别设置写入指针 wp 和读出指针 rp,标记下一个写入地 址和读出地址;地址随写入或读出过程顺序变动;设置全空 标记和全满标记以避免读出或写入的错误; 设计时需要注意处理好从地址最高位到地址最地位的变 化; 程序示例 library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_signed.all;