일단 SDRAM이라는 것에 대해서 어느 정도는 알 것 같다고 하자. 사실 어느 정도 알아서는 Controller를 제대로 만들기 어렵다. 제대로 Controller를 만들려면 Spec.에 대해 정확한 지식이 필요하다. 그러려면 얼마나 큰 노력이 필요하겠는가? 아.. 역시 엔지니어는 삽질의 연속이 될 수 밖에 없나 보다.
자 그럼 이제 어느 정도 SDRAM의 동작에 대해서도 테스트를 했으니 실제로 내가 생각하는데로 동작하는 것이 맞는지 의문이다. 보통 controller를 설계하다보면 spec.만을 가지고 설계하는 경우가 있는데 이런 경우에라도 내가 설계하는 controller가 내가 생각하는 데로 동작하는 지, 또는 해당 device가 있는 경우 해당 device가 제대로 동작하는 지 확인이 필요할 수 있다.
일단 우리는 SDRAM device가 있는 상태로 controller를 설계하는 것이다. 그리고, 현재 해당 SDRAM의 경우 simulation model을 제공하므로 내가 생각하는대로 신호를 제어 해 보면서 내가 생각하는 것이 맞는지 확인해 볼 수 있다.
k4s643232h_0401.v - k4s643232h_0401.v
일단 SDRAM은 기본적으로 다음 단계들을 거쳐야 한다.
-
Power Up Sequence
- 기본적으로 SDRAM은 power가 들어오고 나서 Power Up Sequence를 거쳐야 한다.
-
MRS (Mode Register Set)
- Power Up Sequence 단계 끝 부분에서 이루어 지는 것으로 SDRAM이 어떻게 동작할 지를 설정하는 것이 필요하다.
-
Normal Operation
- Power Up Sequence 단계가 끝나면 일반적인 Read/Write가 가능한 normal operation state가 된다.
-
Refresh
- SDRAM은 기본적으로 capacitor를 이용한 memory 소자인 DRAM이므로 일정 시간마다 충전을 해 주어야 한다. 이것이 Refresh이다.
뭐 위의 설명은 이미 datasheet에 있다. 이러한 일련의 동작이 내가 생각하는대로 device를 제어하면 제대로 동작할 지를 simulation model로 작성해서 테스트 해 볼 수 있다.
sdram_test.v - sdram_test.v
Power Up Sequence 과정을 거치면서 Mode Register를 Set하고 일반적인 Write and Read를 해 본 testbench code이다.
자 뭐 어느 순간 verilog code들이 나오더지 simulation code라고 뭔가 짜여졌다. 아직 전자공학을 공부하고 있는 저학년의 경우 'verilog가 무엇인가?' 라는 질문부터 나올 것이다. 이렇게 다시 가지를 치고 의문의 증대되고 공부해야 할 양만 늘어난다.. -_-;;; 머리 싸잡아 매고 울고싶다. 일단 그런 사람들을 돕기 위한 곳이 이 곳이므로 이러한 부분들도 앞으로 보안해 나갈 계획이다.
일단 code를 보면서 설명을 하는 식으로 하자. verilog란 무엇인가? 라는 것은 일단은 좀 미루어 두자. 아니다. 짧게나마 언급하고 넘어가자.
역시 wikipedia가 필요하다. - http://en.wikipedia.org/wiki/Verilog
혹시 논리회로라는 것을 배웠는가? 전자적으로 1과 0의 값을 의미하는 일정한 전압 레벨을 가지는 회로를 이용하여 논리적으로 의미를 가지는 회로를 구성하는 것이라고 볼 수 있다. 논리회로의 정의는 또 인터넷을 한번 찾아보자.(니가 찾아봐라. 아님 찾아달라고 답글 달면 찾아서 문서 업데이트 하리다.) 이러한 논리회로와 관련하여 서적들은 Gate 그림을 그리거나 table 같은 걸로 열심히 참/거짓을 따지고 있다. 이래서는 아주아주 복잡한 논리회로를 설계하기란 어렵다. gate 그림의 schematic으로 집적회로라는 것을 언제 다 그리느냔 말이다. 그러므로, 컴퓨터에서 기계어를 사람이 바로 짤 수 없어 프로그래밍 언어라는 것이 생겼듯이 하드웨어도 어느정도 추상화 하여 개념적으로 기술 할 수 있는 언어가 나왔다. 그 중에 많이 쓰는 것이 verilog이다.
물로 컴퓨터 프로그래밍 언어에도 C만 있는 것이 아니듯이 HDL(Hardware Description Language)에도 verilog만 있는 것이 아니다. 자 나머지는 아래 사이트를 참고하라.
verilog에 대한 설명도 있고, VHDL에 대한 설명도 있고, SystemVerilog에 대한 설명도 있나?....
- /*
- * SDRAM testbench
- */
- `include "timescale.v"
- `define cas_n_default 1
- `define ras_n_default 1
- `define cke_default 1
- `define we_n_default 1
- `define cs_n_default 1
음 code가 뭐 색이 입혀지거나 하지는 않네..-_-;; 이를 어쩌나? 난 뭔가 color가 나타나서 잘 보일 줄 알았는데..(이것은 springnote에 대한 이야기)
일단 verilog에서 /*, */, //는 주석에 해당한다.
`include는 다른 verilog code를 include하게 된다. 이렇게 code를 분리하는 경우는 해당 code가 독립된 기능을 하거나 특정 정보를 담고 있거나 할 경우 분리해 두면 편리한 경우 분리하면 된다. 참고로 include 된 timescale.v는 simulation에서만 필요한 부분이다.
`define은 code 전체에서 paramter 또는 경우에 따라서 가변 될 수 있는 값들을 의미있는 text로 치환해서 단순히 숫자를 적어 두는 경우보다 무슨 값인지를 알려줄 수 있기 때문에 사용한다. 뿐만 아니라 data bit width와 같이 그 값이 나중에 변경될 가능 성이 있는 경우에도 이렇게 define 해 놓으면 나중에 변경하기 쉽다.
- module top;
- regCLK;
- initial CLK = 0;
- always #10 CLK = ~CLK;// 50MHz
- regRST_N;
- initial begin
- RST_N = 1;
- repeat (10) @(posedge CLK);
- RST_N = 0;
- repeat (10) @(posedge CLK);
- RST_N = 1;
- end
- `ifdef VCD
- initial begin
- $dumpfile("wave_sdram.vcd");
- $dumpvars(5, top);
- end
- `endif
- // SDRAM component
- // K4S643232H-70
- // K4S643232H - 512K x 32Bit x 4Banks
- wireSDC_CLK;
- wireSDC_CS_N;
- wireSDC_CKE;
- wire[1:0]SDC_BA;
- wire[10:0]SDC_A;
- wireSDC_RAS_N;
- wireSDC_CAS_N;
- wireSDC_WE_N;
- wire[3:0]SDC_DQM;
- wire[31:0]SDC_DQ;
- sdram_testtb(
- .CLKi(CLK),
- .RST_Ni(RST_N),
- .CLK(SDC_CLK),
- .CS_N(SDC_CS_N),
- .CKE(SDC_CKE),
- .BA(SDC_BA),
- .A(SDC_A),
- .RAS_N(SDC_RAS_N),
- .CAS_N(SDC_CAS_N),
- .WE_N(SDC_WE_N),
- .DQM(SDC_DQM),
- .DQ(SDC_DQ)
- );
- sdram sdram(
- .clk(SDC_CLK),
- .csb(SDC_CS_N),
- .cke(SDC_CKE),
- .ba(SDC_BA),
- .ad(SDC_A),
- .rasb(SDC_RAS_N),
- .casb(SDC_CAS_N),
- .web(SDC_WE_N),
- .dqm(SDC_DQM),
- .dqi(SDC_DQ)
- );
- endmodule
module top;
endmodule
module이 시작하고 끝나는 것을 나타낸다. simulation에서의 top block은 따로 input/output 신호가 없으므로 module top;과 같이 module 이름만 선언한다. 그 외의 module들은 모두 input/output 을 가지게 된다.
reg/wire
신호에 대해 wire 또는 register로 설정하는 것이다. wire는 신호와 신호를 연결하거나 combinational한 회로 구성에 사용되는 신호이다. register는 특정한 순간에만 값이 변하는 신호로서 clock신호 또는 선택된 입출력신호 값이 변하는 경우에만 register 출력이 변한다. <-- 이건 뭐 논리회로다.
initial
simulation의 제일 초기 값을 설정한다.
always
register 신호들에 대해 계속해서 반복되는 경우를 기술하기 위한 것이다.
initial begin
end
뭐 begin/end를 보면 알겠지만 초기 simulation initial 단계를 정의하는데 그 구문이 여러 줄인 경우 begin/end로 block을 정해 준다. simulation code를 작성할 때에는 초기 값만 설정하는 것이 아니라 이 안에서 순차적인 신호 변화 값을 기술할 수도 있다. 물론 simulation에나 가능한 부분으로 실제 하드웨어 설계 시 이런 거 쓰면 안된다. 이와 관련 있는 것으로 #1과 같은 단위시간 delay 구문도 쓰면 안된다. simulation에서 말고 실제 하드웨어 설계 시.
`ifdef VCD
`endif
만약에 VCD라는 변수(?)가 이미 선언되어 있으면 해당 block 내의 구문을 수행하라... 이다.
sdram_test tb( .CLKi(CLK), ... );
verilog는 module의 묶음으로 구성되는데 top module 내에 다른 sub module들을 instantiation해서 연결하게 된다. tb가 instant name이고 실제 sub module은 sdram_test가 된다. sdram_test module의 CLKi신호를 top module에서는 CLK라는 신호로 연결해서 다른 어딘가와 연결한다는 것이다.
-
- module sdram_test(
- CLKi,
- RST_Ni,
- CLK,
- CS_N,
- CKE,
- BA,
- A,
- RAS_N,
- CAS_N,
- WE_N,
- DQM,
- DQ
- );
- inputCLKi;
- inputRST_Ni;
- outputCLK;
- outputCS_N;
- outputCKE;
- output[1:0]BA;
- output[10:0]A;
- outputRAS_N;
- outputCAS_N;
- outputWE_N;
- output[3:0]DQM;
- inout[31:0]DQ;
- wireCLK;
- assign CLK = CLKi;
- regCS_N;
- regCKE;
- reg[1:0]BA;
- reg[10:0]A;
- regRAS_N;
- regCAS_N;
- regWE_N;
- reg[3:0]DQM;
- reg[31:0]DQ_O;
- wire[31:0]DQ_I;
- regDQ_T;
- reg[128:0]COMMAND;
- wire[31:0]DQ;
- assign DQ = DQ_T ? 32'bz : DQ_O;
- assign DQ_I = DQ;
- reg[31:0]WBUF[0:3];
- reg[31:0]RBUF[0:3];
- integer i;
- initial begin
- // set default value
- COMMAND = "NOP";
- CS_N = `cs_n_default;
- CKE = `cke_default;
- BA = 0;
- A = 0;
- RAS_N = `ras_n_default;
- CAS_N = `cas_n_default;
- WE_N = `we_n_default;
- DQM = {4{1'b1}};
- DQ_T = 1'b1;
- DQ_O = 32'b0;
- // wait until reset
- @(negedge RST_Ni);
- @(posedge RST_Ni);
- @(posedge CLKi);
- TaskPowerOnSequence;
- repeat (10) @(posedge CLKi);
- TaskSingleWrite(32'h0, 32'h5);
- repeat (10) @(posedge CLKi);
- TaskSingleRead(0);
- repeat (10) @(posedge CLKi);
- for(i=0; i<4; i=i+1)
- begin
- WBUF[i] = i;
- end
- Task4BurstWrite(32'h1000);
- repeat (10) @(posedge CLKi);
- Task4BurstRead(32'h1000);
- repeat (10) @(posedge CLKi);
- $finish;
- end
@(negedge RST_Ni);
RST_Ni라는 신호의 negative edge까지 기다리는 거다.
TaskPowerOnSequence;
task를 수행하는 명령이다. task 또는 function은 특정한 기능을 수행할 수 있는 부분을 분리할 때 사용한다. task와 function의 차이점은 개인이 공부를 하거나 나중에 내용을 업데이트 하도록 한다. 간단히 task는 여러 개의 입력을 받아 들일 수 있으나 return value가 없다. 뭐 function의 경우에는 return value를 가지지.
repeat (10) @(posedge CLKi);
CLKi신호의 positive edge가 10번 반복 될 때까지 수행.
나머지 code 부분들은 보면 이해가 될 것이라고 본다. 우리가 살펴 보아야 할 것은 뭐 code도 대충 이해 되는데 과연 이런 verilog code라는 것들은 어떻게 simulation을 하는 가 하는 것일테다.
Simulation
simulation을 하려면 simulator가 필요하다. 여기서는 특정 회사를 홍보하려는 것은 아니지만 윈도우에서 쓰기 쉬운 modelsim을 소개하려고 한다. 소개라기 보다는 modelsim을 구해서 simulation을 해보라는 거다. modelsim만 여러분이 구한다면 나머지는 내가 첨부해 주는 script를 돌리면 된다. script가 지저분 하기는 하지만 동작 하는 걸 확인했으니 돌려보시고, 안되면 질문하세요.
먼저 7zip이라는 것으로 압축을 푼다. sdram_test/sim/Sim_sdram.bat를 실행하면 vcd라는 file이 생길텐데 waveform viewer로 구경해서 보면 된다. 공짜 VCD viewer로는 GTKWave라는 것이 있다.
'[메모리]' 카테고리의 다른 글
6. SDRAM controller - 2 (0) | 2012.07.20 |
---|---|
5. SDRAM controller - 1 (0) | 2012.07.16 |
3. SDRAM 동작원리 (0) | 2012.07.16 |
2. SDRAM 선정 (0) | 2012.07.16 |
SDRAM 이란? (0) | 2012.07.16 |