Changes between Initial Version and Version 1 of Ex05 レジスタファイルとメモリ2017


Ignore:
Timestamp:
May 15, 2017 3:11:50 PM (9 years ago)
Author:
nakasato
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Ex05 レジスタファイルとメモリ2017

    v1 v1  
     1トップ:http://galaxy.u-aizu.ac.jp/note/wiki/CAEX2017 
     2 
     3= レジスタファイルについて =  
     4 
     5MIPSプロセッサにおいて、プログラマから見える汎用レジスタには $0 から $31 までの32個があります。 
     6このうち $0 は値が常にゼロである仮想的なレジスタなので、実際のハードウェアでは31個のレジスタからなるレジスタファイルが使われます。 
     7各レジスタの入出力データのビット幅は32ビットです。 
     8 
     9レジスタファイルに対する書き込み口や読み出し口のことをポートと呼びます。 
     10今回利用するレジスタファイルは2つの読み出しポートと1つの書き込みポートを備えています。 
     11このことは、2つの異なるレジスタの読み出しと、さらに異なる1つのレジスタへの書き込みを、 
     121つのクロックサイクルの中で同時に行えるということを意味します。 
     13 
     14== レジスタファイルの記述例:Registers.v == 
     15{{{ 
     16module Registers(ReadRegster1, ReadRegster2, WriteData, RegWrite, WriteRegster, CK, CLR, ReadData1, ReadData2); 
     17 
     18input[4:0]      ReadRegster1, ReadRegster2, WriteRegster; 
     19input[31:0]     WriteData; 
     20input           RegWrite, CK, CLR; 
     21output[31:0]    ReadData1, ReadData2; 
     22 
     23reg[31:0]       regfile[1:31]; 
     24integer i; 
     25 
     26always  @(posedge CK) begin 
     27      if (CLR == 1'b1) 
     28            for( i = 1; i < 31; i = i + 1) 
     29                  regfile[i] <= 32'h00000000; 
     30      else if ( RegWrite == 1'b1 && WriteRegster != 5'b00000) 
     31                  regfile[WriteRegster] <= WriteData; 
     32      end 
     33  
     34 
     35assign #5 ReadData1 = (ReadRegster1 == 5'b00000) ? 32'h00000000 : regfile[ReadRegster1]; 
     36assign #5 ReadData2 = (ReadRegster2 == 5'b00000) ? 32'h00000000 : regfile[ReadRegster2]; 
     37 
     38endmodule 
     39}}} 
     40 
     41=== 入出力信号の説明 === 
     42* ReadRegster1 と ReadData1 は1つ目の読み出しポートのための信号です。ReadRegster1 にレジスタ番号を (0~31) を入力すると該当するレジスタの値が ReadData1 から出力されます(レジスタ番号が 0 のときは常に 0 が出力される)。 
     43* ReadRegster2 と ReadData2 は2つ目の読み出しポートのための信号です。動作は1つ目の読み出しポートと同じです。 
     44* !WriteData、!RegWrite、および!WriteRegsterは書き込みポートを形成します。WriteRegsterにレジスタ番号を入力し、WriteDataには書き込むデータをセットして、!RegWrite を 1 にすると、次のクロックの立ち上がりでデータが該当レジスタに書き込まれます。WriteEN が 0 のときは、クロックの立ち上がりがあってもデータは書き込まれません。また、レジスタ番号が 0 のときは、レジスタへの書き込みは行われません。 
     45* CK はクロック信号、CLR はクリア信号です。 CLR が 1 になると全てのレジスタが 0 に初期化されます。 
     46 
     47 
     48= メモリについて =  
     49メモリ(Memory.v)は、データを格納しておくために利用し、読み出しおよび書き込みの両方ができるメモリです。 
     50 
     51{{{ 
     52module Memory(Address, WriteData, ReadData, MemWrite, MemRead, CK); 
     53 
     54input[31:0]     Address, WriteData; 
     55input           MemWrite, MemRead, CK; 
     56output[31:0]    ReadData; 
     57 
     58always @(posedge CK) 
     59 begin  
     60   if (( MemWrite == 1'b1 ) && (32'h00000000 <= Address) && ( Address <= 32'h0000ffff) ) 
     61     begin 
     62       Mem.cell[Address] = WriteData; 
     63     end 
     64 end 
     65 
     66assign #5 ReadData = (MemRead == 1'b1) && (32'h00000000 <= Address) && ( Address <= 32'h0000ffff) ? Mem.cell[Address] : 32'bx; 
     67 
     68endmodule 
     69 
     70 
     71module Mem (); 
     72  reg [31:0]  cell [0:65535]; 
     73endmodule 
     74}}} 
     75 
     76=== メモリMemoryの入出力信号の説明 ===  
     77* 制御入力Memwriteが1のときデータの書き込みが、MemReadが1のときデータの読み込みが行われます。 
     78* データを書き込むときは、Memwriteを1にすると、次のクロックの立ち上がりで、アドレスAddressにデータWriteDataが書き込まれます。アドレスは32'h00000000から32'h0000ffffが 有効です。これ以外の範囲の場合は書き込みは行われません。 
     79* データを読み出すときは、MemReadを1にすると、ReadDataにそのアドレスに格納されたデータが出力されます。有効なアドレスは、書き込みの場合と同じです。 
     80 
     81== メモリ初期化について == 
     82メモリの初期設定はテストベンチ記述で行います。 
     83今後の演習ではメモリの初期化は、xspimが出力するテストベンチ用のVerilogHDL記述を利用します。  
     84 
     85xspimのdumpコマンドを用いて出力されるVerilogHDL記述は以下のような形式になっています。 
     86{{{ 
     87// text segment         
     88Mem.cell['h00000000] = 32'h08000400; // j 0x1000       
     89Mem.cell['h00001000] = 32'h********;      以下プログラムに対するコードが続く  
     90     ...      
     91         
     92// data segment         
     93Mem.cell['h00005000] = 32'h********;        以下データに対するコードが続く  
     94     ...     
     95}}}  
     96 
     97この記述をテストベンチにコピーして、プログラムおよびデータ領域の初期化を行います。 
     98 
     99{{{ 
     100Mem.cell['h00000000] = 32'h08000400; 
     101}}} 
     102という記述で、テストベンチからモジュールMemのレジスタcellに 直接アクセスしています。 
     103 
     104= 課題を行う前の注意 = 
     105上で説明したレジスタファイルmoduleとメモリmoduleをそれぞれ"Registers.v"と"Memory.v"としてファイルに保存すること。 
     106 
     107= 課題1 レジスタの利用方法 = 
     108以下のテストベンチは、レジスタファイルをインスタンス化して、$a0レジスタに"0xffffffff"を書き込んでいる。 
     109{{{ 
     110`timescale 1ns/1ps 
     111`include "Registers.v" 
     112 
     113module  RegTest; 
     114   reg [4:0]  read_adr1,  read_adr2,  write_adr; 
     115   reg [31:0] write_data; 
     116   reg        write_enable; 
     117   reg        ck,clear; 
     118   wire [31:0] read_data1, read_data2; 
     119 
     120   Registers regs(read_adr1, read_adr2, write_data, write_enable, write_adr, ck, clear, read_data1, read_data2); 
     121 
     122   initial 
     123     begin 
     124        $dumpfile("RegTest.vcd"); 
     125        $dumpvars(0, RegTest); 
     126 
     127 
     128        #0 
     129        ck = 1'b1; 
     130        clear = 1'b1; 
     131 
     132        #110 
     133        clear = 1'b0; 
     134 
     135        #190 
     136        read_adr1 = 5'b00100; 
     137 
     138        #100 
     139        write_enable = 1'b1; 
     140        write_adr  = 5'b00100; 
     141        write_data = 32'hffffffff; 
     142        $display("%x %x",read_adr1, read_data1); 
     143 
     144        #100 
     145        write_enable = 1'b0; 
     146        $display("%x %x",read_adr1, read_data1); 
     147 
     148        #900 
     149 
     150        $finish; 
     151     end // initial begin 
     152 
     153   always #50 ck = ~ck; 
     154endmodule 
     155}}} 
     156 
     157これを参考にして、以下のテーブルに示すように、レジスタに値の値を書き込んで、読み出すテストベンチを作成し実行したうえで、クロック信号(ck)、読み出しているレジスタのアドレス(read_adr1)と読み出し結果(read_data1)の波形を確認しなさい。波形には、この三つの信号のみを表示すること。表示する順番は、小さいアドレスから大きいアドレスになるようにすること。なお、表示している信号名がわかるようにすること。 
     158 
     159||レジスタ|| 値|| 
     160|| $sp ||  0xfffff     || 
     161|| $v0 ||  0xfafa      || 
     162|| $v1 ||  0x1010      || 
     163|| $t0 ||  0xffffffff  || 
     164|| $t1 ||  0xaaaaaaaa  || 
     165|| $ra ||  0x98765432  || 
     166|| $t2 ||  0x98765432  || 
     167|| $t3 ||  0x12121     || 
     168 
     169== 波形の例 ==               
     170以下のように各レジスタにデータを書き込んだ場合: 
     171 
     172|| $at ||  0xf      || 
     173|| $v0 ||  0xff     || 
     174|| $v1 ||  0xfff    || 
     175|| $a0 ||  0xffff   || 
     176 
     177実行結果の波形の例: 
     178 
     179[[Image(http://galaxy.u-aizu.ac.jp/note/raw-attachment/wiki/Ex06%E8%AA%B2%E9%A1%8C2015/comparch_ex6_reg.png)]] 
     180 
     181 
     182'''動作確認をするので、波形が表示できたらTAのチェックをうけること''' 
     183 
     184= 課題2 メモリの利用方法 = 
     185以下のテストベンチファイルでは、レジスタファイルとメモリとALUをインスタンス化し、テストするためのテンプレートである。 
     186{{{ 
     187`timescale 1ns/1ps 
     188`include "Registers.v" 
     189`include "Memory.v" 
     190`include "ALU.v" 
     191 
     192module  MemTest; 
     193   // for Memory 
     194   reg [31:0] address; 
     195   reg [31:0] write_data; 
     196   reg        write_enable, read_enable; 
     197   reg        ck; 
     198   wire [31:0] read_data; 
     199 
     200   // for Registers 
     201   reg [4:0]  read_adr1_reg, read_adr2_reg, write_adr_reg; 
     202   reg [31:0] write_data_reg; 
     203   reg        write_enable_reg; 
     204   reg        clear_reg; 
     205   wire [31:0] read_data1_reg, read_data2_reg; 
     206 
     207   // for ALU 
     208   reg [31:0]  A, B; 
     209   reg [3:0]   ALUop; 
     210   wire        Zero; 
     211   wire [31:0] Result; 
     212       
     213   Memory    mem(address, write_data, read_data, write_enable, read_enable, ck); 
     214 
     215   Registers regs(read_adr1_reg, read_adr2_reg, write_data_reg, write_enable_reg, write_adr_reg, 
     216                  ck, clear_reg, 
     217                  read_data1_reg, read_data2_reg); 
     218 
     219   ALU       alu(A, B, ALUop, Result, Zero); 
     220       
     221   initial 
     222     begin 
     223        $dumpfile("MemTest.vcd"); 
     224        $dumpvars(0, MemTest); 
     225         
     226        // data segment 
     227        Mem.cell['h00005000] = 32'h0000000a; 
     228        Mem.cell['h00005004] = 32'h0000000b; 
     229        Mem.cell['h00005008] = 32'h00000000; 
     230        Mem.cell['h00005010] = 32'h00000000; 
     231        Mem.cell['h00005014] = 32'h00000000; 
     232        Mem.cell['h00005018] = 32'h00000000; 
     233 
     234        #0 
     235        ck = 1'b1; 
     236        clear_reg = 1'b1; 
     237         
     238        read_enable = 1'b0; 
     239        address = 32'h00000000; 
     240        write_enable_reg = 1'b0;         
     241        write_adr_reg    = 5'b00000;     
     242        write_data_reg   = 32'h00000000; 
     243         
     244        #110 
     245        clear_reg = 1'b0; 
     246 
     247        #190 // read memory at 0x5000 
     248        read_enable = 1'b1; 
     249        address = 32'h00005000; 
     250 
     251        #100 // write data to $v0 and read memory at 0x5004 
     252        write_enable_reg = 1'b1; 
     253        write_adr_reg    = 5'b00010; 
     254        write_data_reg   = read_data; 
     255 
     256        #100 
     257        read_enable = 1'b0; 
     258        write_enable_reg = 1'b0; 
     259 
     260        #100 
     261        read_adr1_reg = 5'b00010; 
     262 
     263        #100 
     264        $display("$v0 = %x",read_data1_reg);       
     265 
     266        #2000 
     267         
     268        $finish; 
     269     end // initial begin 
     270    
     271   always #50 ck = ~ck; 
     272endmodule 
     273}}} 
     274 
     275実行結果は以下のようになるはずである。 
     276{{{ 
     277% ncverilog test_mem.v 
     278 
     279....省略 
     280 
     281ncsim> run 
     282$v0 = 0000000a 
     283 
     284....省略 
     285}}} 
     286 
     287以下の部分でメモリからデータを読み出し、レジスタファイル($v0)に書き込んでいる。 
     288{{{ 
     289        #190 // read memory at 0x5000 
     290        read_enable = 1'b1; 
     291        address = 32'h00005000; 
     292 
     293        #100 // write data to $v0 
     294        write_enable_reg = 1'b1; 
     295        write_adr_reg    = 5'b00010; 
     296        write_data_reg   = read_data; 
     297 
     298        #100 
     299        read_enable = 1'b0; 
     300        write_enable_reg = 1'b0; 
     301}}} 
     302 
     303実行結果の波形の例: 
     304 
     305[[Image(http://galaxy.u-aizu.ac.jp/note/raw-attachment/wiki/Ex06%E8%AA%B2%E9%A1%8C2015/comparch_ex6_mem.png)]] 
     306 
     307このテンプレートを元にして、アドレス0x5000と0x5004にあるデータを演算した結果を、再びメモリに書き込むテストベンチを作成せよ。格納アドレスと演算結果の対応は以下の通りとする。特に、レジスタへの読み書き、演算をして結果をメモリに書き込む部分の波形を確認すること。 
     308 
     309|| 0x5008 || 加算      || 
     310|| 0x500c || 減算      || 
     311|| 0x5010 || AND演算   || 
     312|| 0x5014 || 3*"0x5000のデータ"+"0x5004のデータ" ||