레이블이 verilog인 게시물을 표시합니다. 모든 게시물 표시
레이블이 verilog인 게시물을 표시합니다. 모든 게시물 표시

2015년 1월 29일 목요일

[verilog] 논리 합성에 쓰이는 verilog HDL

verilogHDL을 사용하여 코딩하다보면 가장 애매한 부분이 내가 만든 코드가 실제 합성을 통해서 로직으로 변경이 되냐? 안되냐? 일 것이다.

포트 input, output, inout
파라미터 parameter
모듈 정의 module
신호와 변수 wire, reg, tri
인스턴스 module instances, primitive gate instances
함수와 태스크 function, task
순차(procedural) always, if, else, case, casex, casez
순차적 블록 begin, end, named blocks disable
데이터플로우 assign
루프 for, while, forever

위의 명령어들이 논리 합성에 사용되지만 이 중에서도 특히 많이 사용하는 것들만 따로 나열해 보면

input, output, parameter, module, wire, reg, always, if, else, case, begin, end, assign 정도 사용하는 것 같다.

먼가 한정된 자원으로 많은 것을 해야하는 것 같지만 추상적인 모델로 RTL 코딩을 할 수록 합성시간이 오래걸리고 생각했던 것과 다른 결과가 나올 수 있다. 따라서 기존에 코딩하던 C/C++ 같은 방식이 아니라 말 그대로 하드웨어를 설명하는 RTL 코딩을 해야 합성 속도도 빠르고 처음 설계한 대로 원하는 합성이 가장 비슷하게 이루어질 수 있다.

끝

2015년 1월 28일 수요일

[verilog] Task 와 Function

이번에 정리하고자 하는것은 행위수준 설계의 태스크(task)와 함수(function) 이다.

태스크와 함수는 마치 C언어의 함수 처럼 둘다 비슷한 것 같은데 확실한 차이가 있다. 이를 분류하면 아래와 같다.

태스크(task)
- 다른 태스크나 함수를 사용할 수 있다.
- non-zero 시뮬레이션 시간에 수행될 수 있다.
- 지연, 사건, 또는 타이밍 제어 문장을 포함할 수 있다.
- input, output 또는 inout를 하나도 가지지 않거나 다수를 가질 수 있다.
- 값을 되돌릴 수 없지만, output와 input을 통해서 여러 개의 값을 전달 할 수 있다.

함수
- 다른 함수를 사용할 수 있지만 다른 태스크는 사용 할 수 없다.
- 항상 시뮬레이션 시간 0에 수행된다.
- 어떤 지연, 사건, 또는 타이밍 제어 문장을 포함할 수 없다.
- 적어도 하나 이상의 input 인수를 가져야만 한다.
- 항상 하나의 값을 되돌린다. output 또는 input 인수를 가질 수 없다.

공통적으로 태스크와 함수는 행위 수준 문장만 포함 할 수 있다.

마치 비슷한 것 같지만 확연한 차이가 있는 것을 확인 할 수 있다.

필자도 많이 사용해보지 않아 가장 궁금했던 부분들이였다. 또한 C언어는 시간 순서대로 코드가 실행되기 때문에 함수를 여러곳에서 불러다 써도 겹치는 일이 발생하지 않는다. 그러나 verilog에서는 '병렬'처리가 있기 때문에 필자가 궁금했던 사항이 있었는데

하나의 태스크나 함수를 만들어 놓고 여러번 병렬로 불러서 사용할 수 있는가?

이다.

다른 모듈을 만들어 놓고 사용할 때는 여러개로 만들어 사용할 수 있는데 태스크와 함수도 가능한 것일까?

일단 결론부터 말하면 안된다.

동시에 두곳 이상에서 불러다 쓰면 같은 변수들을 공유하고 사용하기 때문에 안되는 것이다. 하지만 이를 위해서 사용되는 키워드가 있으니 바로 'automatic' 이다.

automatic은 task 키워드 앞 또는 function 앞에 사용된다.
예)
task automatic 블라블라

function automatic 블라블라

이렇게 automatic를 사용하게되면 여러곳에서 사용하더라도 다른 태스크나 함수가 불러지게 되는 것이다.

먼가 알듯 말듯한 기분인데 역시나 사용을 많이 해봐야 알 것 같다.


2015년 1월 21일 수요일

[verilog] blocking과 non-blocking

이번에는 verilog에서 이해하기 어려웠던 blocking과 non-blocking에 대해서 설명해보기로 한다.

우선 사용법부터 정리하면
initial 또는 always 구문 안에 작성해야하는데

blocking 은
y = x 와 같은 형식이고

non-blocking은
y <= x 와 같은 형식으로 표현한다.

먼가 같은것 처럼 보이지만 굉장히 다르다.

= 를 사용하는 blocking 같은 경우 말 그대로 이다. 신호의 흐름을 'blocking' 한다 라고 생각하면 된다. 따라서 코드 내에서 blocking 구문으로 사용할 경우 이는 C언어 처럼 순차 실행을 의미하게 된다.

initial begin
  #10 a = b;
  #5 c = a;
end

위와 같은 경우 처음 10 단위 시간 뒤에 b를 a에 넣고 다시 5 단위 시간 뒤에 a를 c에 넣으므로 두번째 라인은 15 단위 시간 뒤에 동작하게 되는 것이다.

(단위시간은 코드처음에 `timescale 1ns/1ps 라고 했을 때 1ns 를 말한다. 즉, 다음과 같이 timescale를 설정했을 경우 #10 단위시간은 10ns를 말하는 것임)

<= 를 사용하는 non-blocking 같은 경우 말 그대로 신호의 흐름을 'non-blocking' 막지 않는 것이다.

initial begin
   a <= #10 b;
   c <= #5 a;
end

위와 같은 경우 처음 5단위 시간에서 c에 a값이 들어가고 10단위 시간에서 a에 b 값이 들어가므로 순서와 상관없이 동신에 실행하게 된다.

그림으로 마무리 하자면


위와 같이 blocking과 non-blocking을 설명할 수 있는 것이다.

아마 여기까지는 기존에 있던 블로그나 설명들을 통해 어느정도 이해를 했을 것이다. 아마 대부분의 엔지니어들은 '아 그렇구나.. ' 할 것이다.

그러나 대부분의 선배들은 다음과 같이 얘기 한다.

" always 구문 안에서는 가능하면 non-blocking 구문으로 작성할 것"

그럼 여러분들은 질문할 것이다.

"왜요?"

단편적으로 여기서 대답을 해주냐 못해주냐에 따라 실력있는 선배, 실력 없는 선배로 나누는 것은 옳지 않지만

"그냥 원래 그런거니까 그렇게해~ "

라고 할지도 모른다. 왜냐하면 나도 이글을 작성하기 전까지는 몰랐으니까!(그냥 연구원임 ㅠ)

그럼 여러분들은 고민할 것이다. 'C언어 짜던대로 순차로 실행하는게 더 좋지 않나?' 라고 하고 아마 대부분의 학생들은 실제로 그렇게 짜는 것을 보기도 했다.

이것이 나쁘기만 한 것은 아니지만 왜 always 안에서 non-blocking 구문을 주로 써야 하냐면 바로 경쟁조건(race condition) 때문이다.

이게 먼소리인고 하니 엔지니어들이니 말보다 코드로 설명한다.

보기1.
always@(posedge clock)
  a = b;

always@(posedge clock)
  b = a;

보기2.
always@(posedge clock)
  a <= b;

always@(posedge clock)
  b <= a;

위의 보기1과 보기2를 보면 보기1 blocking 구문부터 보면 a = b 와 b = a의 구문이 clock 상승 에지에서 동시에 실행되게 되는데 이것을 경쟁 상태 라고 한다. 이것이 어느것이 먼저 실행되느냐는 실제 게이트 레벨에서 어떻게 합성되느냐에 따라 선의 길이가 누가 더 긴가(?)와 같은 애매한 관계에 따라 달라지게 된다. 한마디로 예측이 어려운 상태가 되는 것이다.  이것을 경쟁 조건(race condition) 이라 한다.

하지만 보기2 에서 보면 둘은 동시에 실행되기 때문에 클럭이 발생했을 때 a는 현재 b값을 가지고 b는 이전의 a값을 가지고 있게 된다. 한마디로 서로 부딧칠 일이 없다.

그래서!! 왜 always 구문 안에서는 가능하면 non-blocking으로 설계해야 하는가? 바로 경쟁 조건이 발생하지 않기 위해서 이다. 저런 동시에 실행되는 많은 always 문이 생기게 되면 자신도 모르게 어디선가 경쟁조건이 발생하게 되고 시뮬레이션 상에서는 알 수 없지만 나중에 칩으로 갔을 때 제대로 동작 되지 않는 상태가 되는 것이다!!!!

(참조 : 책에는 non-blocking으로 파이프라인과 상호 배타적인 데이터 전송을 하지만 단점으로 시뮬레이터의 성능 하락과 메모리 사용량을 늘리는 것의 원인이라고 나와 있음)

이제 어느정도 blocking과 non-blocking에 대해서 알겠는가?

끝!
P.S. 필자가 이해한대로 작성하여 오류가 있을 수도 있습니다. 잘못된 점은 리플 부탁드립니다!

2015년 1월 19일 월요일

[verilog] delay 지연

시스템 레벨에서 디지털의 저속 회로에서는 타이밍이나 딜레이에 대해서 딱히 신경쓸일이 없지만 고속회로에서는 타이밍과 딜레이를 맞추기 위해 통신 신호선의 길이를 같게 만드는 등의 일을 하게 된다. 특히 RF 에서는 선의 길이, 방향, 모양, 두께 에 따라서 달라지는 요소들이 많기 때문에 굉장히 어렵다.

그나마 다행인게 칩 레벨에서 verilog로 디지털 설계를 할 때는 타이밍 문제정도가 중요한 요소 중 하나 인데 이 중 딜레이 문제가 있다. 

사용되는 게이트 내부에서 소모하는 시간이 있고 선의 길에 따라 전기속도(매질에 따라 다름, 빛의 속도 아님)에 따라 발생하는 딜레이도 있는데 예전에는 전체속도가 느리기 때문에 이런 문제가 큰 이슈가 아니였지만 지금은 빛의 속도도 카운트하는 시대에 선로의 길이에 대한 딜레이도 펑션에 문제가 발생할 정도로 중요한 이슈가 된다.

흔히 이런 딜레이를 없다고 생각하고 설계를 해서 시뮬레이션을 돌리는 것을 제로지연(zero-delay)라고 한다. 

실제 회로에서는 게이트에 지연을 가지고 있고 시뮬레이션을 위해서 verilog에서도 지연을 지정해 줄 수 있다. 

지연은 3가지로 나눌 수 있다.
상승지연, 하강지연, 턴-오프 지연 이다.


하강 지연은 0,x or z 에서 1로 변화되는 것과 관계 되어 있다.

하강 지연은 1,x or z 에서 0으로 변화되는 것과 관계되어 있다.

턴오프 지연은 어떤값에서 임피던스 값(z)로 게이트 출력이 변화는 것과 관계되어 있다.
만약 게이트 출력이 x로 변했다면, 상승, 하강, 턴-오프 지연 중 가장 작은 값으로 간주한다. 

예)
and #(delay_time) a1(out, i1, i2);

and #(rise_val, fall_val) a1(out, i1, i2);

and #(rise_val, fall_val, turnoff_val) a1(out, i1, i2);

한단계 더 나아가서 지연에 대해 최소/평균/최대값을 지정할 수 있다. 합성 툴에 따라 다르지만 합성시 추가 명령어에 따라 +maxdelays, +typdelays, +mindelay 옵션에 의해 선택된다. (옵션 미지정시 기본값은 평균)

예)
and #(min:typ:max, min:typ:max, min:typ:max) a1(out, i1, i2);

이런 기능이 있다는 것은 시뮬레이션에서 딜레이로 발생할 수 있는 문제를 눈으로 확인하기 위해서 인데 이런 과정은 pre-sim 즉, 제로 딜레이에서 펑션적으로 문제가 되던 부분들이 주로 나타나게 된다. 하지만 post-sim 에서는 딜레이가 포함된 시뮬레이션이기 때문에 이런 문제들에 대해서 크게 생각하지 않아도 되고 pre-sim 에서도 SDF를 통해서 시뮬레이션 하게 되면 라인딜레이를 제외한 게이트 딜레이까지는 체크가 가능하다. 라인 딜레이에 대한 부분도 어느정도 경험을 통해서 예측(사실 한클럭 여유면 대부분 충분함)가능하기 때문에 딱히 문제될게 없다? 정도랄까...(경험이 없어서 다른 문제에 대해서는 잘 모르겠음 ㅠ)

아날로그나 어떤 모델링을 만들면서 사용되면 모를까 일반적인 디지털 시뮬레이션에 딜레이를 자주쓰는 일은 없을 것 같다는 것이 내 결론이다. (만약 잘못된거면 사용되는 예를 한수 가르쳐 주시면 감사드립니다.ㅠㅠ)

사용 방법은 여러개가 있는데
assign #10 out = in1 & in2; // 10 지연 시간뒤 in1 in2 계산 결과 값이 out 적용
assign out = #10 in1 & in2; // in1 in2 계산 결과 값이 10 지연 시간뒤 out 적용

같은 말 처럼 보이지만 다르다.
인터넷에서 예문 퍼옴

begin // Equivalent to intra-assignment delay.
hold = y; // Sample and hold y immediately.
#1; // Delay.
x = hold; // Assignment to x. Overall same as x = #1 y.
end 
begin // Equivalent to delayed assignment.
#1; // Delay.
x = y; // Assign y to x. Overall same as #1 x = y.
end 

하나 더
wire #10 out; // 모든 out 사용된 곳에 10 지연 적용

선언에서 딜레이 적용할 경우 사용된 모든 곳에 동일하게 적용 시킬 수 있다.

끝!

2015년 1월 16일 금요일

[verilog] 계층적 이름(Hierarchical Names)

verilog는 계층적 설계방법을 지원한다. 이건 verilog에서만 중요한 것이 아니다. 필자는 무엇을 하던간에 제일먼저 숲이 보이지 않으면 움직이지 않는다. 그 숲이라함은 계층구조의 상위를 말한다. 목차를 잡을 때도 큰 그림이 보여야 잡기가 쉬우며 업무를 할 때도 큰 그림을 보고 움직여야 삽질을 줄일 수 있다. 그냥 그냥 노하우 인데 아무리 조사해도 숲이 안보이면 일단 가장 간단한걸로 부딧치면서 겪어보면 전체 프로세스를 한번 겪기 때문에 숲을 보는 '안목' 이 생긴다. verilog 해야하는데 쓸데 없는 말을... ㅡ.ㅡ;

verilog 계층적 이름을 지원한다. 이게 무슨소리냐 하면

                stimulus
                     |
       module1      module2
            |                 |
     and1 and2      or1 or2

다음과 같은 계층구조로 verilog를 작성했다고 할 때
최상위에 있는 stimulus를 root(루트)라고 부른다. 여기에 사용된 각 모듈들을 계층적 이름 참조(hierarchical name referncing)를 통해서 유일한 이름을 가지고 모든 모듈을 나타낼 수 있다.

계층적 이름은 각 계층 수준의 지시어 리스트를 도트(".")로 분리 한다.

위의 계층 모듈을 한번 분리해 보면
stimulus
stimulus.module1
stimulus.module2
stimulus.module1.and1
stimulus.module1.and2
stimulus.module2.or1
stimulus.module2.or2

와 같이 나타낼 수 있다. 심지어 각 모듈의 포트(신호선)까지도 나타낼 수 있다.

stimulus.module1.and1.clock
stimulus.module1.and1.reset
.
.
.

이전에 작성했던 system task 에서 $display나 $monitor 에서 %m 포멧을 통해서 계층적 수준을 확인할 수 있다.




2015년 1월 15일 목요일

[verilog] 자주쓰는 system task

verilog를 사용하다보면 시스템 태스크라는 것이 있다. 이것을 내맘대로 해석하면 verilog에서 디버깅이나 시뮬레이션에 편리하게 사용하라고 제공해주는 것 같다.

당연히 합성되지 않는다.

그 중에서 자주 사용하는 몇가지만 정리해 보려고 한다.

우선 verilog에서 시스템 태스크는 $<키워드> 형태로 나타낸다.

여기서 정리하고자 하는 시스템 태스크는 다음과 같다.
$display, $monitor, $time, $stop, $finish 이다.

1. $display 화면 출력 태스크
$display는 변수의 값 또는 문자열 또는 수식을 출력하기 위한 주요 시스템 태스크 이다.

사용법 : $display(p1, p2, ... pn);

p1, p2,... pn 은 문자열 또는 변수 또는 수식이 될 수 있다. 형식은 C언어의 printf와 매우 비슷하다.

(포맷과 출력은 구글 참조)

예문은 아래와 같다.
$display("Hello~");
-- Hello~

$display($time);
-- 230

$display("%b, %d, %h", a, b, c);
-- 00001010 (2진수)
-- 10 (10진수)
-- 0a (16진수)

$display("%m");
-- top.p1
(요건 모르던 기능! 계층이름을 출력 해줌)


2. $monitor 모니터링 태스크
$monitor는 신호의 값이 변할 때 마다 그 신호를 출력할 수 있다.

사용법 : $monitor(p1, p2, ... pn);

파라미터 p1, p2, ... pn 은 변수, 신호 이름, 문자열이 될 수 있다.
$monitor 태스크는 $display 태스크와 비슷한데 단 한번만 사용할 수 있다. 만약 $monitor 태스크가 사용되면 마지막 %monitor 문장이 수행 된다.

이 $monitor 태스크를 on/off 하기 위해서 $monitoron; 과 $monitoroff; 라는 태스크가 사용된다.

initial begin
  $monitor($time, "clock = %d, reset = %d", clock, reset);
end

-- 0 clock = 0 reset = 1
-- 5 clock = 1 reset = 1
-- 10 clock = 0 reset = 0

3. $time 시간 태스크
$time는 현재의 시뮬레이션 시간을 얻고자 할 때 쓰인다.

4. $stop 중단 태스크
$stop는 시뮬레이션 하는 동안 중단을 하기 위해서 사용한다.
사용법 : $stop;

4. $finsh 종료 태스크
$finsh는 시뮬레이션을 끝내기 위해 사용한다.
사용법 : $finsh;

($stop와 $finsh의 중단, 끝내기 라는건 알겠는데 구체적으로 어떤지는 잘 모르겠네...)

우선 이정도만 사용하면 디버깅하는데 어느정도 필요한 만큼 쓴다고 하겠다. 사실 C언어에서도 최고의 디버깅은 printf 이듯이 verilog도 눈으로 보는 디버깅은 monitor나 display인듯. (물론 시뮬레이션 파형으로 볼 때가 더 편할 때도.. 어떤게 더 좋은지는 나중에 경험하다 생각나면 다시 정리!)

나중에 이보다 더 많은 시스템 태스크에 대해서 알아보도록 하겠다.

끝!

2014년 11월 20일 목요일

[verilog] fixed point exp


This algorithm based on here -> http://www.quinapalus.com/efunc.html
I coded this algorithm using a verilogHDL and I designed a combinational logic. so you can change the design using a sequential logic and pipeline architecture.

This is 32bit fixed point exponential for verilogHDL.

/*
 * exp(k)
 * 5.5452 256
 * 2.7726 16
 * 1.3863 4
 * 0.6931 2
 * 0.4055 3/2
 * 0.2231 5/4
 * 0.1178 9/8
 * 0.0606 17/16
 * 0.0308 33/32
 * 0.0155 65/64
 * 0.0078 129/128
 *
 * 32bit
 * fix point
 * 16bit.16bit
 * */

module fxexp(
                x,

                y
               );

input [31:0] x;
output [31:0] y;

wire [31:0] tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,tmp10;
wire [31:0] tmp_x0, tmp_x1, tmp_x2, tmp_x3, tmp_x4,
tmp_x5, tmp_x6, tmp_x7, tmp_x8, tmp_x9, tmp_x10;
wire [31:0] tmp_y0, tmp_y1, tmp_y2, tmp_y3, tmp_y4, 
tmp_y5, tmp_y6, tmp_y7, tmp_y8, tmp_y9,
tmp_y10,tmp_y11,tmp_y12,tmp_y13,tmp_y14,
tmp_y15,tmp_y16,tmp_y17,tmp_y18,tmp_y19;

assign tmp0  = x      - 32'h00058b91;
assign tmp1  = tmp_x0 - 32'h0002c5c8;
assign tmp2  = tmp_x1 - 32'h000162e4;
assign tmp3  = tmp_x2 - 32'h0000b172;
assign tmp4  = tmp_x3 - 32'h000067cd;
assign tmp5  = tmp_x4 - 32'h00003920;
assign tmp6  = tmp_x5 - 32'h00001e27;
assign tmp7  = tmp_x6 - 32'h00000f85;
assign tmp8  = tmp_x7 - 32'h000007e1;
assign tmp9  = tmp_x8 - 32'h000003f8;
assign tmp10 = tmp_x9 - 32'h000001fe;

assign tmp_x0  = (tmp0[31]) ? x : tmp0;
assign tmp_x1  = (tmp1[31]) ? tmp_x0 : tmp1;
assign tmp_x2  = (tmp2[31]) ? tmp_x1 : tmp2;
assign tmp_x3  = (tmp3[31]) ? tmp_x2 : tmp3;
assign tmp_x4  = (tmp4[31]) ? tmp_x3 : tmp4;
assign tmp_x5  = (tmp5[31]) ? tmp_x4 : tmp5;
assign tmp_x6  = (tmp6[31]) ? tmp_x5 : tmp6;
assign tmp_x7  = (tmp7[31]) ? tmp_x6 : tmp7;
assign tmp_x8  = (tmp8[31]) ? tmp_x7 : tmp8;
assign tmp_x9  = (tmp9[31]) ? tmp_x8 : tmp9;
assign tmp_x10 = (tmp10[31]) ? tmp_x9 : tmp10;

assign tmp_y0  = 32'h00010000;  
assign tmp_y1  = (tmp0[31]) ? tmp_y0 : {tmp_y0[23:0],8'h00};
assign tmp_y2  = (tmp1[31]) ? tmp_y1 : {tmp_y1[27:0],4'h0};
assign tmp_y3  = (tmp2[31]) ? tmp_y2 : {tmp_y2[29:0],2'b00};
assign tmp_y4  = (tmp3[31]) ? tmp_y3 : {tmp_y3[30:0],1'b0};
assign tmp_y5  = (tmp4[31]) ? tmp_y4 : (tmp_y4+tmp_y4[31:1]);
assign tmp_y6  = (tmp5[31]) ? tmp_y5 : (tmp_y5+tmp_y5[31:2]);
assign tmp_y7  = (tmp6[31]) ? tmp_y6 : (tmp_y6+tmp_y6[31:3]);
assign tmp_y8  = (tmp7[31]) ? tmp_y7 : (tmp_y7+tmp_y7[31:4]);
assign tmp_y9  = (tmp8[31]) ? tmp_y8 : (tmp_y8+tmp_y8[31:5]);
assign tmp_y10 = (tmp9[31]) ? tmp_y9 : (tmp_y9+tmp_y9[31:6]);
assign tmp_y11 = (tmp10[31]) ? tmp_y10 : (tmp_y10+tmp_y10[31:7]);
assign tmp_y12 = (tmp_x10[8]) ? (tmp_y11+tmp_y11[31:8]) : tmp_y11;
assign tmp_y13 = (tmp_x10[7]) ? (tmp_y12+tmp_y12[31:9]) : tmp_y12;
assign tmp_y14 = (tmp_x10[6]) ? (tmp_y13+tmp_y13[31:10]) : tmp_y13;
assign tmp_y15 = (tmp_x10[5]) ? (tmp_y14+tmp_y14[31:11]) : tmp_y14;
assign tmp_y16 = (tmp_x10[4]) ? (tmp_y15+tmp_y15[31:12]) : tmp_y15;
assign tmp_y17 = (tmp_x10[3]) ? (tmp_y16+tmp_y16[31:13]) : tmp_y16;
assign tmp_y18 = (tmp_x10[2]) ? (tmp_y17+tmp_y17[31:14]) : tmp_y17;
assign tmp_y19 = (tmp_x10[1]) ? (tmp_y18+tmp_y18[31:15]) : tmp_y18;
assign y       = (tmp_x10[0]) ? (tmp_y19+tmp_y19[31:16]) : tmp_y19;
    
endmodule

2014년 11월 19일 수요일

[verilog] fixed point log


This algorithm based on here -> http://www.quinapalus.com/efunc.html
I coded this algorithm using a verilogHDL and I designed a combinational logic. so you can change the design using a sequential logic and pipeline architecture.

This is 32bit fixed point logarithme for verilogHDL.

/*
 * k log(k)
 * 32760 10.3969
 * 256 5.5452
 * 16 2.7726
 * 4 1.3863
 * 2 0.6931
 * 3/2 0.4055
 * 5/4 0.2231
 * 9/8 0.1178
 * 17/16 0.0606
 * 33/32 0.0308
 * 65/64 0.0155
 * 129/128 0.0078
 *
 * 32bit
 * fix point
 * 16bit.16bit
 * */

module fxlog(
                x,

                y
               );

input [31:0] x;
output [31:0] y;

wire [31:0] tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6;
wire [31:0] tmp_x0,tmp_x1,tmp_x2,tmp_x3,tmp_x4,
tmp_x5,tmp_x6,tmp_x7,tmp_x8,tmp_x9,
tmp_x10,tmp_x11,tmp_x12;
wire [31:0] tmp_y0,tmp_y1,tmp_y2,tmp_y3,tmp_y4,
tmp_y5,tmp_y6,tmp_y7,tmp_y8,tmp_y9,
tmp_y10,tmp_y11,tmp_y12;

assign tmp_x0  = (x < 32'h00008000) ? (x<<16) : x;
assign tmp_x1  = (tmp_x0 < 32'h00800000) ? (tmp_x0<< 8) : tmp_x0;
assign tmp_x2  = (tmp_x1 < 32'h08000000) ? (tmp_x1<< 4) : tmp_x1;
assign tmp_x3  = (tmp_x2 < 32'h20000000) ? (tmp_x2<< 2) : tmp_x2;
assign tmp_x4  = (tmp_x3 < 32'h40000000) ? (tmp_x3<< 1) : tmp_x3;
assign tmp_x5  = ((tmp0&32'h80000000) == 0) ? tmp0 : tmp_x4;
assign tmp_x6  = ((tmp1&32'h80000000) == 0) ? tmp1 : tmp_x5;
assign tmp_x7  = ((tmp2&32'h80000000) == 0) ? tmp2 : tmp_x6;
assign tmp_x8  = ((tmp3&32'h80000000) == 0) ? tmp3 : tmp_x7;
assign tmp_x9  = ((tmp4&32'h80000000) == 0) ? tmp4 : tmp_x8;
assign tmp_x10 = ((tmp5&32'h80000000) == 0) ? tmp5 : tmp_x9;
assign tmp_x11 = ((tmp6&32'h80000000) == 0) ? tmp6 : tmp_x10;

assign tmp0 = tmp_x4  + (tmp_x4 >>1);
assign tmp1 = tmp_x5  + (tmp_x5 >>2);
assign tmp2 = tmp_x6  + (tmp_x6 >>3);
assign tmp3 = tmp_x7  + (tmp_x7 >>4);
assign tmp4 = tmp_x8  + (tmp_x8 >>5);
assign tmp5 = tmp_x9  + (tmp_x9 >>6);
assign tmp6 = tmp_x10 + (tmp_x10>>7);

assign tmp_y0  = 32'ha65af;
assign tmp_y1  = (x < 32'h00008000) ? tmp_y0  - 32'hb1721 : tmp_y0;
assign tmp_y2  = (tmp_x0 < 32'h00800000) ? tmp_y1  - 32'h58b91 : tmp_y1;
assign tmp_y3  = (tmp_x1 < 32'h08000000) ? tmp_y2  - 32'h2c5c8 : tmp_y2;
assign tmp_y4  = (tmp_x2 < 32'h20000000) ? tmp_y3  - 32'h162e4 : tmp_y3;
assign tmp_y5  = (tmp_x3 < 32'h40000000) ? tmp_y4  - 32'h0b172 : tmp_y4;
assign tmp_y6  = ((tmp0&32'h80000000) == 0) ? tmp_y5  - 32'h067cd : tmp_y5;
assign tmp_y7  = ((tmp1&32'h80000000) == 0) ? tmp_y6  - 32'h03920 : tmp_y6;
assign tmp_y8  = ((tmp2&32'h80000000) == 0) ? tmp_y7  - 32'h01e27 : tmp_y7;
assign tmp_y9  = ((tmp3&32'h80000000) == 0) ? tmp_y8  - 32'h00f85 : tmp_y8;
assign tmp_y10 = ((tmp4&32'h80000000) == 0) ? tmp_y9  - 32'h007e1 : tmp_y9;
assign tmp_y11 = ((tmp5&32'h80000000) == 0) ? tmp_y10 - 32'h003f8 : tmp_y10;
assign tmp_y12 = ((tmp6&32'h80000000) == 0) ? tmp_y11 - 32'h001fe : tmp_y11;
 
assign tmp_x12 = 32'h80000000 - tmp_x11;
assign y = tmp_y12 - (tmp_x12>>15);

endmodule

2014년 10월 30일 목요일

[verilog] signal delay


module signal_dly (
                clk,
                rstb,
                sig,

                delay_sig
               );

input           clk;
input           rstb;
input           sig;
output          delay_sig;

reg             delay_sig;
reg             sig_buf_0;

always @(posedge clk or negedge rstb) begin // 1 clock delay
  if(!rstb) begin
    delay_sig   <= 1'b0;
    sig_buf_0   <= 1'b0;
  end
  else begin
    sig_buf_0   <= sig;
    delay_sig   <= sig_buf_0;
  end
end

endmodule





module signal_dly (
                clk,
                rstb,
                sig,

                delay_sig
               );

input           clk;
input           rstb;
input           sig;
output          delay_sig;

reg             delay_sig;
reg             sig_buf_0;
reg             sig_buf_1;
reg             sig_buf_2;

always @(posedge clk or negedge rstb) begin // 3 clock delay
  if(!rstb) begin
    delay_sig   <= 1'b0;
    sig_buf_0   <= 1'b0;
    sig_buf_1   <= 1'b0;
    sig_buf_2   <= 1'b0;
  end
  else begin
    sig_buf_0   <= sig;
    sig_buf_1   <= sig_buf_0;
    sig_buf_2   <= sig_buf_1;
    delay_sig   <= sig_buf_2;
  end
end

endmodule

2014년 10월 14일 화요일

[verilog] edge detector


module dual_edge_detect
(
  clk,
  signal,
  pulse
);
input clk;
input signal;
output pulse;

reg signal_prev;
always @(posedge clk)
  signal_prev <= signal;
assign pulse = (~signal & signal_prev) | (signal & ~signal_prev); 
endmodule



module rising_edge_detect
(
  clk,
  signal,
  pulse
);
input clk;
input signal;
output pulse;

reg signal_prev;
always @(posedge clk)
  signal_prev <= signal;
assign pulse = signal & ~signal_prev;
endmodule



module falling_edge_detect
(
  clk,
  signal,
  pulse
);
input clk;
input signal;
output pulse;
reg signal_prev;
always @(posedge clk) 
  signal_prev <= signal;
assign pulse = ~signal & signal_prev;
endmodule 

2014년 9월 25일 목요일

[verilog] Flip-Flop vs. Latch 차이와 표현

후.... 글을 쓰면 어느 정도 마음이 진정되는 효과가 있다.
나만 그런지는 모르지만 
나는 운동, 음악, 글쓰기가 나의 스트레스 해소법 인것 같다.
그래서 오늘도 언제나처럼 블로깅을 한다.

1.     Flip-Flop vs. Latch
차이
            A. Latch는 입력신호가 인가되는 순간 바로 출력되지만 Flip-Flop은 
               clock의 (상승 또는 하강)Edge에서 입력신호만 출력에 반영
            B. Latch는 clock신호와 무관하게 출력이 결정되는 
               Asynchronous(비동기식)이고 F/F은 clock신호에 맞추어
               출력이 결정되기 때문에 Synchronous(동기식)이라고 함

2.     Verilog
에서 Flip-Flop과 Latch의 표현
            A. Flip-Flop rising edge 동작 verilog code
               module D_FF(D,Clk,Q);
                 input D, Clk;
                 ouput reg Q;
                 always@(posedge Clk) // Clk이 상승 edge일 때 Q<=D 동작
                  if(Clk) Q<=D;
              endmodule

       B. Latch
동작 verilog code
               module D_latch(D,Clk,Q);
                 input D,Clk;
                 output reg Q;
                 always@(D,Clk) // Clk이 high(1)일 때 Q<=D 동작
                   if(Clk) Q<=D;
               endmodule