'Hardware 관련'에 해당되는 글 8건

I2C Bus

Hardware 관련/BUS 2008.03.16 15:38

http://www.hayanmail.com/jsy/index.html?board=cizblog_zboard3&ln_mode=news_view&id=5&ct_sel=2

I2C Bus


Inter-IC Bus (= TWI: Two-wire Serial Interface)

Philips에서 제안한 IC간 통신 방식으로 클럭(SCL)과 데이터(SDA)의 2라인을 사용하는 동기 양방향 2선식 Bus이다. 버스에 연결된 각 디바이스는 고유의 어드레스를 갖으며 필요에 따라 receiver와 transmitter로 동작한다. 전송속도는 standard mode에서 100kbps까지 이고 fast mode에서는 400kbps까지 가능하다.

transmitter: 버스에 데이타를 보내는 장치
receiver:     버스로부터 데이타를 받는 장치
master:       전송을 개시하는 장치로 클럭 펄스를 만들고, 전송을 종료하는 일을 한다.
slave:          master가 어드레싱한 장치

master가 start condition을 만들면 버스에 연결된 슬레이브 장치들이 이후의 데이터를 기다린다. master가 slave 어드레스를 보내면 각 칩은 자신의 고유 어드레스와 비교를 한다. 어드레스가 일치하는 칩은 이어지는 acknowledge 신호 구간에서 데이터를 low로 유지해 응답을 보낸다. 그러면 master는 데이터를 읽거나 쓰기를 할 수 있다. 모든 작업이 끝나면 master는 stop condition을 발생하고 버스를 release한다.

SDA H -\      /---\     /---\          /---\         /---\      /---
    L   \----/     \---/     \--------/     \-------/     \----/

SCL H ----\     /-\       /-\     /-\    /-\    /-\    /-\    /------
    L      \---/   \-----/   \---/   \--/   \--/   \--/   \--/


   | START   |   1    |    1    |   0  |  1   |  0   |   1   | STOP

* start condition
클럭과 데이터가 모두 high인 일반 상태에서 데이타 라인이 low로 떨어지는 상태.

SDA H ------\
    L        \-------
SCL H ---------\
    L           \----

* stop condition
클럭이 high인 동안에 데이타 라인이 low에서 high로 바뀌는 상태.

SDA H           /----
    L ---------/
SCL H        /-------
    L ------/

* 일반 데이터 전송에서는 클럭이 low일 때만 데이타의 상태를 바꿀 수 있다. 따라서 클럭이 high인 구간에만 유효한 데이타이다. master는 먼저 데이타 라인을 적당한 데이타로 바꾸고 클럭 라인을 일정시간 high로 하고 다음 SDA 라인의 상태를 바꾸기 전에 클럭을 low로 만든다. 데이타는 8bit이고 MSB가 먼저 전송된다. start 와 stop condition 사이에 전송되는 데이타의 수는 제한이 없다.

SDA H       /----------\
    L -----/\----------/\-------
SCL H          /----\
    L --------/      \----------

* acknowledge 조건
master든 slave든 transmitter는 8 bit 전송을 마치고 버스선을 high로 한다. 9번째 사이클 동안 receiver는 데이타 선을 low로 유지하여 acknowledge 를 표시한다.

write시

한 byte write시

S

slave address

A

data write

A

P

여러 byte write시

S

slave address

A

data write

A

data write

A

...

data write

A

P

Note : S = start condition
          A = Wait for Acknowledge (master <-- slave)
          P = stop condition

read시

slave address를 보낸후 SDA를 놓아주면 slave가 8bit 데이터를 보내고 master는 ack신호를 slave에게 보내준다.

한 byte reading

S

slave address

WA

read byte

GNA

P


여러 byte reading

S

slave address

WA

read byte

GA

...

read byte

GNA

P

Note: WA = Wait for Acknowledge (master <-- slave)
          GA = Give Acknowledge (master --> slave)
GNA = Give Acknowledge with NACK (master --> slave) : end of reading

I2C software driver pseudo code

#define SDA_HIGH()	  { ... your code here ... } // SDA pin high
#define SDA_LOW()	  { ... your code here ... } // SDA pin low
#define SCL_HIGH()	  { ... your code here ... } // SCL pin high
#define SCL_LOW()	  { ... your code here ... } // SCL pin low
#define SDA_OUPUT() { ... your code here ... } // SDA pin output mode
#define SDA_INPUT() { ... your code here ... } // SDA pin input mode
#define SDA_READ()	  { ... your code here ... } // SDA pin read

#define i2c_delay()  delay_us(5)	// delay time for 100khz clock
#define i2c_clock() \
{ i2c_delay(); SCL_HIGH(); i2c_delay(); SCL_LOW(); } #define i2c_start() \
{ SDA_HIGH(); SCL_HIGH(); i2c_delay(); SDA_LOW(); i2c_delay(); SCL_LOW(); } #define i2c_stop() \
{ SCL_LOW(); SDA_LOW(); i2c_delay(); SCL_HIGH(); i2c_delay(); SDA_HIGH(); i2c_delay(); } unsigned char i2c_write(unsigned char data) { unsigned char i; for(i=0; i<8; i++) { // MSB first if(data & 0x80) SDA_HIGH(); else SDA_LOW(); i2c_clock(); data = data << 1; } // read ACK SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line i2c_delay(); SCL_HIGH(); // clock back up i2c_delay(); i = SDA_READ(); // get the ACK bit SCL_LOW(); SDA_OUPUT(); // change direction back to output return i; } unsigned char i2c_read(void) { unsigned char i, data; SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line data = 0; for(i=0; i<8; i++) { // MSB first data = data << 1; SCL_HIGH(); // clock HI i2c_delay(); if(SDA_READ()) // get the Data bit data |= 1; SCL_LOW(); // clock LO i2c_delay(); } SDA_OUPUT(); // change direction back to output // send ACK SDA_LOW(); i2c_clock(); SDA_HIGH(); // leave with SDA HI return data; } unsigned char i2c_read_nack(void) { unsigned char i, data; SDA_HIGH(); // leave SDA HI SDA_INPUT(); // change direction to input on SDA line data = 0; for(i=0; i<8; i++) { // MSB first data = data << 1; SCL_HIGH(); // clock HI i2c_delay(); if(SDA_READ()) // get the Data bit data |= 1; SCL_LOW(); // clock LO i2c_delay(); } SDA_OUPUT(); // change direction back to output // send NACK SDA_HIGH(); i2c_clock(); SDA_HIGH(); // leave with SDA HI return data; }















EEPROM read/write sample (AT24C32)

#define EEP_SLAVE_ADR	0xA0
#define TWI_WRITE		0x00
#define TWI_READ		0x01
#define TWI_ACK		0
#define TWI_NACK		1
#define TWI_ERROR		TWI_NACK

void eep_write(unsigned short addr, unsigned char data)
{
	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_WRITE);  // slave address
	i2c_write(addr>>8);		// word address high
	i2c_write(addr & 0xFF);		// word address low

	i2c_write(data);
	i2c_stop();

	delay_ms(6);		// 5ms EEPROM write cycle time
}


unsigned char eep_read(unsigned short addr)
{
	unsigned char	data;

	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_WRITE);	// slave address
	i2c_write(addr>>8);		// word address high
	i2c_write(addr & 0xFF);		// word address low

	i2c_start();
	i2c_write(EEP_SLAVE_ADR|TWI_READ);	// slave address with READ
	data = i2c_read_nack();
	i2c_stop();

	return data;
}
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag I2C Bus
http://www.hayanmail.com/jsy/index.html?board=cizblog_zboard3&ln_mode=news_view&id=13&ct_sel=2


AT91SAM7S256

그래픽 처리등으로 많은 메모리와 좀더 빠른 처리시간이 요구 되면서 새로운 MCU가 필요했는데 ATmel에서 아주 유용한 놈이 나왔습니다. 보통 ARM은 CPU로 외부에 RAM과 ROM을 추가로 붙여야 하지만 이 녀석은 마이크로컨트롤러 식으로 RAM과 ROM이 내장된 방식이고 패키지도 LQFP 입니다. OS를 올릴 정도는 안되고 AVR로는 좀 부족한 중급 레벨의 시스템을 구성할 때 좋겠습니다.
드디어 32비트의 세계로 발을 들이게 되었는데 많이 낯설고 레지스터 한 개가 32 비트씩이니까 어지럽군요@.@
48메가로 돌리니까 AVR에 비해 붕붕~ 날아 다닙니다. 예전 486 급의 클럭 스피드니까요. 단순 수치상으로는 3배가 빠르지만 수 백번 반복 연산의 경우 전체 절약시간은 [수 백 x 단위 절약시간] 이 되어 3초 걸리는 일을 1초에 끝내는 것은 2초 절약으로 별 차이가 아니지만 3시간 걸리는 일을 1시간 만에 한다는 것은 2시간이 절약되어 체감상으로 큰 차이입니다.

특징

  • 내장 64KB 램, 256KB 플래시 롬
  • 12Mbps USB 내장
  • 3개의 UART 사용가능
  • 1개의 I/O 포트가 있어 32개의 입출력 핀 사용가능 (5V tolerance I/O)
  • 내장 PLL회로로 55MHz 까지 구동 (누군가는 105 MHz까지 오버클럭 해봤다는 군요^.^)
  • 내부 패리패럴 장치를 위한 13 채널의 DMA 컨트롤러
  • MHz당 0.9MIPS
  • SAM-BA 부트로더가 내부 마스크 롬에 내장
  • 64핀 LQFP 패키지

* 8비트 마이컴과의 차이점

  • 기동시 PLL 로 동작 주파수를 설정함
  • ARM의 전원관리 기능 때문에 사용하려는 내부 장치의 전원(클럭)을 먼저 살려줘야 함
  • set용 레지스터와 clear 용 레지스터가 분리돼 있음
  • 포트를 예전처럼 사용하려면 해당 핀을 direct drive 모드로 설정해야 함
  • int 형이 16비트에서 32비트로 바뀜
  • 구조체의 sizeof() 연산자 사용시 크기가 바뀔수 있음을 주의
    (gcc의 경우는 __attribute__ ((packed)), 일반적으로는 #pragma pack(1) ~ #pragma pack() 사용)

* 아트웍시 주의사항: TST, JTAGSEL, ERASE 핀은 사용하지 않을 시 GND에 연결하는 것이 좋음
외부 노이즈에 의한 HIGH 유입시 증상: TST 및 ERASE(부팅시 프로그램 지워짐), JTAGSEL(프로그램 정지)


WinARM GCC 컴파일러

AVR의 WinAVR 식으로 나온 것입니다.
홈페이지는
http://gandalf.arubi.uni-kl.de/avr_projects/arm_projects/index.html
역시 경로에 C:\WinARM\bin;C:\WinARM\utils\bin 을 추가해야 합니다.
WinAVR이 설치된 경우는 C:\WinARM\utils\bin 부분이 필요 없습니다.

SAM-BA 를 통한 ISP 지원

별도 롬에 내장된 부트로더로 USB 또는 RS232 포트(DBGU)로 인 시스템 프로그래밍(ISP)을 지원 합니다. PC측 프로그램은 Atmel 사이트에서 다운 받을 수 있습니다. SAM-BA는 플래시 롬에 있을 때 실행되며 사용자 프로그램을 라이팅하게 되면 플래시를 덮어쓰게 되므로 이 부트로더는 지워지게 됩니다. 지워졌을 경우는 System Recovery 과정을 통해 내장된 별도 롬에서 플래시 롬으로 다시 복사할 수 있습니다. 최초에는 플래시 롬이 비여있는 상태이므로 SAM-BA를 복사해야 합니다.
실제 사용에는 불편하여 별도 부트로더를 작성해 사용하게 됩니다. SAM-BA는 단지 부트로더를 처음 write할 때 사용합니다.

WinARM용 부트로더(bootloader)

SAM-BA의 불편함과 불합리한 점 때문에 다른 프로그램을 참고로 WinARM용 부트로더를 만들어 봤습니다.
사용자 프로그램에 통합된 형태이고 시리얼 포트를 이용합니다. 다른 컴파일러에서도 조금 수정하면 사용가능할 것입니다.
자세한 사항은 readme.txt 파일을 참고하세요.
sam7flash.zip ver 1.0.4 (134KB)

ARM은 RAM 에서 코드 실행이 가능합니다. makefile에서 RUN_MODE를 RAM_RUN으로 설정하면 RAM에서 실행되도록 컴파일 할 수 있습니다.
sam7flash 부트로더에서 사용 가능한 RAM 실행 데모 입니다.
ramdemo.zip (53KB)

위 부트로더를 롬 이미지로 만든 버전입니다. 평소에는 RAM을 소비하지 않습니다.
u_boot.zip (130KB)

JTAG 장비

단순 인터페이스 인데 가격이 좀 비싸군요. USB 패킷을 잡아보면 호환 제품을 자작하는 것도 가능할 것입니다.

WIGGLER는 패러랠 포트를 사용하는 초저가 형입니다.
DTC114 블럭은 디지털 TR로 단순 인버터 기능이므로 74HC14로 구성해도 됩니다.

Simple JTAG interface circuit.
==============================

25 pin Male parallel                                              20 pin JTAG header

    17-25 <--------------+-------------------------+--+-----------<  4,6,8,
              GND        |                         |  |              10,12,14,
                         |    AC244          200nF =  = 4.7uF        16,18,20 (GND)
                         | +------------+  Vcc     |  |
         TDI          0v +-| 1       20 |-+--------+--+-----------<  1,2 (VCC)
    5  >-------------------| 2       19 |-+
         TMS               | 3       18 |-----XXXX---------------->  5 (TDI)
    3  >-------------------| 4       17 |     51R     
         TCLK              | 5       16 |-----XXXX---------------->  7 (TMS)
    4  >-------------------| 6       15 |     51R
                           | 7       14 |-----XXXX---------------->  9 (TCK)
                      +----| 8       13 |     51R
                      |    | 9       12 |-----XXXX---+
                      |  +-| 10      11 |     51R    |
                      |  | +------------+            |
                      |  V 0v                        |
                      +------------------------------------------<   13 (TDO)
         TDO                                         |
    11 <---------------------------------------------+


                            DTC114   /-------xxxx----------------<   15 (nRST)
         RST            10k       | /        51R
    2  >----------------XXXX--+---|<
                              |   | \
                              X      V
                         47k  X      |  
                              X      |
                              |      |
                              V 0v   V

usbjtag USB포트를 사용하는 자작 JTAG 에뮬레이터
J-Link 수 백만원 대의 Multi-ICE 보다 저렴한 JTAG 에뮬레이터
AT91SAM-ICE J-Link의 ATmel 버전 (22만원) : 타 ARM CPU에 사용하려면 별도 라이센스를 구매해야 함

AT91SAM7X256

SAM7S 시리즈가 핀수가 적어 더 많은 제어핀이 필요한 경우 SAM7X 시리즈를 사용할 수 있습니다.
- 포트B 가 추가되어 31핀을 더 사용할 수 있음
- SPI 1채널 추가. Ethernet MAC 추가
- SAM-BA 를 호출하는 방식이 편리하게 바뀜.
즉, ERASE핀에 220ms 이상 high 신호를 입력해 주면 플래시가 지워지고 NVM 플래그가 초기화되어 내장 부트롬(SAM-BA)으로 부팅하도록 됨. SAM-BA로 라이팅후 다시 NVM 플래그를 설정해야 플래시로 부팅가능하여 사용자 프로그램이 실행되게 됨.
초기 출하상태는 내장 부트롬(SMA-BA)으로 부팅 가능한 상태임.
- USB 엔드포인트 2개 추가로 총 6개의 엔드포인트 지원.

AT91SAM7SE256

EBI 인터페이스가 있어서 DRAM 등을 추가로 장착할 수 있는 버전입니다.

openocd 사용법 (JTAG을 이용한 디버깅 방법)

1. openocd 설치

일단, JTAGSEL 핀은 사용하지 않습니다. 오픈 상태로 두거나 GND로 처리해야 합니다.
디버그에 필요한 파일은 WinARM 패키지에 모두 들어있습니다.
OpenOCD 홈페이지(http://openocd.berlios.de/web)에서는 현재 최신버전을 Yagarto(http://www.yagarto.de/)에서 제공한다고 돼있습니다.
최신 버전을 설치하고 사용하는 JTAG 장비의 PC인터페이스에 맞는 config 파일을 준비해야 합니다.
패러랠 포트나 FT2232를 사용한 USB포트를 지원하고 있습니다.
사용자 환경에 맞춰 OpenOCD를 실행합니다.

예) openocd-ftd2xx.exe -f arm7_ft2232.cfg (USB 포트의 경우)
openocd-pp.exe -f arm7_wig.cfg (Wiggler의 경우)

실행이 되어 JTAG 장비와 연결에 성공하면 아래와 같은 메시지가 출력됩니다.

Info: openocd.c:84 main(): Open On-Chip Debugger (2007-01-31 12:00 CET)
Warning: arm7_9_common.c:683 arm7_9_assert_reset(): srst resets test logic, too

여기까지만 성공하면 절반은 성공입니다.

2. openocd 사용법 I - 텔넷을 통한 연결

openocd 자체로는 아무것도 할 수 없습니다. 단지 드라이버를 통해 JTAG장비와 연결해주고 클라이언트 S/W와의 통신을 지원하는 디버그 서버의 역할만 합니다.

openocd는 telnet과 gdb 연결을 지원합니다. telnet은 4444 포트를, gdb는 3333 포트를 사용합니다.
이제 도스창에서 telnet을 실행해서 JTAG이 제대로 동작하는지 확인해 봅니다.

telnet localhost 4444

연결되면 아래와 같은 메시지가 출력됩니다.
Open On-Chip Debugger
]

플래시 메모리 정보를 보기 위해 다음 명령을 입력합니다.
] flash info 0

그러면 아래와 같은 메시지가 출력됩니다.

#1: at91sam7 at 0x00100000, size 0x00020000, buswidth 4, chipwidth 0

at91sam7 information: Chip is AT91SAM7X128
cidr: 0x275a0740, arch: 0x0075, eproc: ARM7TDMI, version:0x000, flashsize: 0x00020000
master clock(estimated): 52369kHz
pagesize: 256, lockbits: 8 0x0000, pages in lock region: 64
securitybit: 0, nvmbits: 0x4
]

플래시에 프로그램을 라이팅하기위해 아래의 명령을 사용해 lockbits을 해제합니다.
초기 상태는 lockbits이 해제된 상태입니다.

flash protect 0 0 15 off -- AT91SAM7S256의 경우 lockbits 해제
flash protect 0 0 7 off -- AT91SAM7X128의 경우 lockbits 해제

플래시에 프로그램을 기록하려면 아래의 명령을 사용합니다.

flash write 0 main.bin 0
여기서 main.bin 은 openocd가 실행된 폴더에 있어야만 가능합니다.

또는 경로를 지정하여 다음과 같이 입력합니다.

flash write 0 c:\test\main.bin 0

기타 명령으로는,
reg: 레지스터 정보를 출력합니다.
exit: 텔넷을 종료 합니다.
shutdown: openocd를 종료합니다.
help: 도움말을 출력합니다.

3. openocd 사용법 II - Insight를 통한 디버깅

먼저 플래시메모리에 디버깅할 프로그램을 굽고 시작합니다.

(1) WinARM/utils/insight/bin (또는 WinARM/bin) 폴더에서 arm-elf-insight.exe 를 실행합니다.
(2) File -- Open... 에서 디버깅하려는 elf 파일을 선택합니다.
(3) File -- Target settings..에서
Target은 Remote/TCP로, Hostname은 localhist로, 포트는 3333으로 설정합니다.
브레이크 포인트는 Set breakpoint at 'main' 만 선택합니다.
Run Method는 Continue from Last Stop을 선택합니다.
More options에서 Command to issue after attaching:에서 아래 내용을 입력하고 OK버튼을 누릅니다.
monitor arm7_9 force_hw_bkpts enable
(4) Run -- Connect Target을 실행합니다.
(5) Run -- Download를 실행합니다.
(6) Run -- Run 을 실행합니다.

그러면 main()에서 브레이크가 걸리게 됩니다.
원하는 라인의 왼쪽을 클릭하면 브레이크포인트가 설정됩니다.

여기서 주의사항은 소프트웨어브레이크 포인트는 2개만 지원합니다.
그 이상을 설정하고 진행하려 하면 openocd창에 아래와 같은 메시지가 출력됩니다.
Info: breakpoints.c:65 breakpoint_add(): can't add software breakpoint, resource not available
그러면 브레이크 포인트를 해제해야 진행이 가능합니다.
(Only two software breakpoints are supported. So, you have to remove some breakpoints to continue.)

링크

AT91SAM7S C-Startup Sequence
Procyon ARMlib
AT91 ARM Forum
WinARM User Forum
Philips ARM Design Contest 2005
FreeRTOS
TNKernel
OpenOCD Quick Reference

 

* 참고

Philips 의 LPC2101은 이와 유사한 마이크로콘트롤러이며 70MHz에 가격은 3,500원 대입니다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

SD card

Hardware 관련/Memory 2008.03.13 16:12


 

간략하게 SDHC드에 대해 설명하면 아래와 같습니다.


SDHC 메모리 카드는 성능 등급 및 용량을 재정의하는 SD Card Association가 제정한 새로운 표준입니다.  이러한 표준에 입각하여 SDHC 카드는 오늘날 SD 카드의 2GB 임계값을 뛰어넘는 용량을 가집니다.

SD카드와 SDHC카드는 크기가 똑같다.

SDHC(Secure Digital High Capacity)카드는 SD카드의 상위 버전이다.
SD카드의 한계를 극복하기 위해 나온 새로운 버전이다.

 SD카드와 SDHC카드의 가장 큰 차이점은 파일시스템이다.
SD카드는 구식인 FAT16 파일시스템을 사용하고, SDHC카드는 신식인 FAT32 파일 시스템을 사용한다.

SD카드는 FAT16이기때문에 2GB 이상의 파일을 인식하지 못한다.

그러나 SDHC는 FAT32를 사용하기 때문에 2GB 이상의 고용량을 지원한다.

SDHC에는 대용량의 디지털 비디오 녹화를 위해 최소로 유지되는 전송 속도를
보장하는 세 가지 속도 등급(Class 2, 4 및 6)이 있다. 클래스2는 2MB/s, 클래스4는 4MB/s,
클래스6은 6MB/s 전송속도를 보장한다는 뜻이다.

 SDHC 카드는 겉면에는 몇클래스 제품인지 써져 있다.


--------------------------

au1200 cpu를 사용하는 EVM 보드에서 sd card를 테스트 중입니다.
(kernel 2.6.11)

목표는 4G 이상 시판 되는 SD card를 사용하는 것입니다.

sd card spec에는 >=2GB 는 sdhc spec으로 사용 가능하다고 되어 있더군요.

그런데 시판되는 SD card 중에는 4G, 8G도 있습니다. 물론 sdhc로 별도 표기 되지 않은 제품입니다.

혹자는 sd card의 2G용량 한계가 fat16에 따른 것이라고 하는데 정확한지도 잘 모르겠네요.

어쨌든 리눅스 상에서 sd card를 4G 이상 쓰려면 어떤 방법이 있는지 알고 싶습니다.

또는 sd card를 사용하는데서 kernel version 상의 차이가 있다면 어떤 것이 있는지도 알려주시면 고맙겠습니다.



---

전용 SD 컨트롤러가 아니라면 사용하시는 SD카드리더에 더 영향을 많이 받습니다.
제가 파악하기론, 국내에서 애용되는 칩셋은 SDHC 를 검증을 받지 못했습니다. 언젠가 웹사이트를 돌아다니다 칩셋별로 테스트 결과를 적어놓은 것을 보긴 했는데... 기억이 나질 않네요.
다만, 중요한 것은, SDHC 를 지원하지 않는 칩셋을 사용한 SD카드리더라 해도 2G SD 카드를 읽고 쓰는덴 지장이 없다는 점입니다.

애석한 점은, 이것이 긍정적인 측면이 아니라 부정적인 측면의 중요한 점이라는 겁니다.
2G SD 는 tansfer block size 가 1024 byte 입니다.
4G SD 는 2048 byte 겠지요(없어서 확인 못했습니다)
FAT 에서 따지는 hard block size 즉 device sector size 가 됩니다.
removable media 는 파티션을 나누지 않는 것이 MS windows 의 관례이나 불가능한 것도 아닙니다.
파티션 테이블에는 각 파티션의 시작위치와 크기 정보가 담기게 되는데, 이는 전적으로 hard block size 로 계산된 block address 여야만 합니다.
왜냐하면 media 의 파티션 테이블을 분석하는 시점에서 OS 는 전적으로 h/w 가 보고하는 정보에만 의존해야 하기 때문입니다.
SDHC 를 지원하지 않는 칩셋을 사용한 카드리더들은 실제 media 가 제공하는 정보를 사용하지 않고 일률적으로 512byte 로 보고합니다.
이렇게 잘못된 정보를 기반으로 작성된 파티션 정보가 기록된 media 를 제대로 된 카드리더나 컨트롤러를 가지는 기기에 접속할 경우 파티션정보가 제대로 전달되지 않습니다.
더욱 더 불행한 것은, 이렇게 잘못된 카드리더가 이미 널리 퍼져있기 때문에... 그것들에 의해 사용된 카드를 제대로 읽어내기 위해 리눅스 커널 드라이버에서도 h/w 정보를 무시하고 hard block size 를 512 byte 로 고정시켜야 한다는 점이지요.
때문에, 현재 2.6 커널에 들어가 있는 몇몇 컨트롤러(주로 MPU 에 내장된)에 대한 드라이버(drivers/mmc/) 들은 2G 이상의 SD 카드를 사용하는데 애로사항이 많습니다. 드라이버가 원칙대로 작성되어 있기 때문입니다.

FAT16 의 한계가 있긴 하지만....
FAT 은 media 의 hard block size 말고 logical sector 를 따로 가져가며,
이보다도 sectors per cluser 라는 것을 통해 용량을 극복합니다.
FAT16 이라는 것은 관리할 수 있는 cluster 의 갯수가 최대 2^16-1 개라는 뜻입니다. 65535 개입니다.
리눅스의 mkdosfs 옵션을 살펴보시면 포맷 옵션에 sectors per cluser 갯수를 설정할 수 있는 옵션을 보실 수 있습니다.
기억이 정확지는 않지만 최대 127개까지 가능했던 것 같습니다.
logical sector size 가 512byte 라 해도 최대 512*127*65535=4261347840 까지 FAT16 으로 감당이 됩니다. 다만, 1byte 짜리 파일을 만들어도 단순 데이타만을 저장하기 위해 512*127=65024 byte 가 낭비된다는 단점이 있습니다.

간추리면, 카드리더를 사용하실 것이라면 카드리더에 사용된 칩셋을 알아보고 그 칩셋이 검증을 받은 칩셋인지 미리 확인해보는 겁니다. 사실상... 직접 확인하시기가 거의 불가능에 가깝겠습니다. 주변의 소문이나 이름난 전문 커뮤니티(디지털카메라등...)를 뒤져보면 혹시 정보가 있을지도 모르겠습니다.

전용 컨트롤러를 선택해야 하신다면,
컨트롤러의 스펙도 보세요. 제가 직업이 직업인지라 경험이 일천합니다만,
인기있는 MPU 들 중에서 SD 컨트롤러를 내장한 예를 들면 PXA25x 는 최대 transfer block size 가 1024byte 이고, PXA27x 는 2048byte 까지입니다.
윗 글에서 말씀드린 여자저차한 이유로 이리저리 꼼수를 부려 512 로 사용해야 하지만, 스펙은 스펙이죠.

사실상 SDHC 스펙은 용량보다는 속도 향상에 그 가치가 있습니다.

---

제가 사용중인 cpu에 sd 컨트롤러가 내장되어 있습니다.

따로 card reader를 사용하지 않지요.

그렇다면 내장 sd 컨트롤러의 transfer block size가 sd card의 block size를 지원한다면 mmc 이하의 드라이버를 수정해서 4G까지도 사용할 수 있다는 것으로 보아도 될는지요?

sd 관련 linux-mips 쪽의 메일링 리스트에 이것에 관한 간단 패치가 올랐다가 native directory 쪽의 강한 반대에 부딛힌듯 하던데...

가능한지 어떤지 모르겠습니다. 가능하기만 하다면 mmc 디렉토리를 손봐서라도 써야 하겠는데 말입니다.

--

커널 drivers/mmc/ 는 MMC protocol 을 사용하여 구현되어 있습니다.

read/write 커맨드의 아규먼트로 address 를 넘겨줘야 합니다.
행인지 불행인지 애매하지만,
이 address 는 tansfer block size 와는 상관없는 media offset 이며 단위(unit) 은 byte 입니다.
unsigned 32bit 이므로 4G 까지입니다.

2G 까지는 SD protocol 과 꼼수를 사용하여 PXA27x 에서 사용했는데 4G 는 잘 모르겠습니다.
실제로 해보기 전에는 누구도 뭐라 못 할 것 같네요.

8G SD 카드가 있다면, 아마도 SD memory 가 아니라 SDIO 로 만들어진 놈이 아닐까 조심스레 추측해봅니다.
하여간, 가난해서... 4G 8G 카드는 구경도 못 해봤습니다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag SD 카드

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag 68K

I2C

Hardware 관련/BUS 2008.03.09 20:44

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag I2C


출처: http://blog.empas.com/shiyoul/read.html?a=15628686

PWM에 관해서

저자: Michael Barr / 주재경 역
원문: http://www.oreillynet.com/pub/a/network/synd/2003/07/02/pwm.html

PWM은 프로세서의 디지털 출력으로 아날로그 회로를 제어하는 강력한 기법이다. PWM은 계측과 통신에서 전력제어와 전력 변환에 이르기까지 광범위한 영역에서 사용되고 있다.

아날로그 회로

시간과 크기 모두에서 제한되지 않은 분해능(resolution)을 가지는 아날로그 신호는 연속적으로 변하는 값을 가진다. 9볼트의 배터리는 출력 전압이 정확히 9V가 아니라 시간에 대해 항상 변하며 임의의 실수 값을 가질 수 있다는 점에서 아날로그 기기의 좋은 예이다. 이와 비슷한 예로 배터리에서 출력되는 전류의 양 또한 일정한 값으로 제한 되지 않는다. 디지털 신호는 항상 미리 결정된 집합(0V, 5V)와 같이 제한된 집합내의 값을 가진다는 면에서 아날로그 신호와 구분된다.

아날로그 전압과 전류는 자동차 라디오의 볼륨과 같이 직접적으로 무언가를 조절하는데 사용된다. 간단한 라디오에서 손잡이(역:볼륨조절기)는 가변 저항과 연결 되어있다. 손잡이를 돌리면 저항은 커지거나 작아진다. 이 순간 저항을 통해 흐르는 전류의 양 또한 많아지거나 적어진다. 이를통해 볼륨은 증가하거나 줄어든다. 아날로그 회로는 라디오와 같이 출력이 선형적으로 입력에 비례한다.

아날로그 제어가 직관적이고 간단하게 보인다고 해서 항상 경제적으로도 매력이 있거나 실용적인 것은 아니다. 하나의 예로 아날로그 회로는 시간에 대해 항상 변한다. 그래서 수정하기가 매우 까다롭다. 이러한 문제를 해결한 정교한 아날로그 회로는 아주 크고 무거우며 비싸다( 간단히 예전의 스테레오기기를 생각해 보라). 아날로그 회로는 매우 뜨거울 수도 있다. 소모전력 은 연결된 기기를 통해 흐르는 전류와 이들 사이의 전압의 곱에 비례한다. 아날로그 회로는 제한되지 않은 분해능으로 인해 또한 잡음에 민감할 수 있다. 심지어 아날로그 신호의 아주 작은 동요도 값을 변화 시킨다.

디지털 제어

디지털화 하여 아날로그 회로를 제어하면 시스템의 가격과 전력소모는 급격히 줄어든다. 이미 많은 마이크로 컨트롤러와 DSP들은 구현을 용이하도록 하는 PWM 컨트롤러를 칩에 내장하고 있다.

간단히 말해 PWM은 아날로그 신호를 디지털화 하여 인코딩하는 방법이다. 고분해능의 카운터를 통해 사각형파의 duty cycle은 특정 아날로그 신호를 인코드 하기위해 변조된다. 직류전원 공급장치는 ON 아니면 OFF 이므로 임의의 주어진 시간에 PWM 신호는 여전히 디지털 신호이다. 일련의 반복되는ON, OFF 펄스를 통해 전압이나 전류가 아날로그 장치에 공급된다. On-time은 DC가 아날로그 장치에 공급되는 동안을 말하며 off-time은 전원 공급 스위치가 꺼진 기간을 일컽는다. 충분한 대역폭이 주어진다면 어떠한 아날로그 값도 PWM을 통해 인코드 될 수 있다.

[그림 1]은 서로 다른 세 개의 PWM을 보여준다. 그림1a는 10%의 duty cycle에서 PWM 출력을 보여준다. 즉 주기의 10%동안만 신호가 ON이고 나머지 90%동안은 신호가 OFF이다. 그림 1b와 1c는 각각 50%와 90%에서의 PWM출력을 보여준다. 이 세가지 PWM출력은 전체 강도의 10%, 50%, 90%의 서로 다른 아날로그 신호를 인코딩한다. 예를 들어 9V로 전원 공급이 이루어지고 있고 duty cycle이 10%라면 0.9V의 아날로그 신호가 결과로 나온다.



사용자 삽입 이미지

[그림 1] 다양한 duty cycle에서의 PWM신호


[그림 2]는 PWM이 사용되는 간단한 회로를 보여주고 있다. 그림에서 9V배터리가 백열전구에 전원을 공급한다. 만약 50ms동안 배터리와 램프를 연결하면 전구는 9V의 전압 을 가지게 될 것이다. 그리고 나서 50ms동안 배터리와 램트사이의 연결을 차단하면 전구의 전압은 0V가 된다. 이와 같이1초 동안 10회 반복하면 전구는 마치 4.5V의 전원에 연결되어 있는 것 처럼 전구에 불이 켜질 것이다.(9V의 50%). 이럴 경우 duty cycle은 50%가 되고 변조 주파수는 10Hz이다.



사용자 삽입 이미지

[그림 2] 간단한 PWM회로


대부분의 장치는 10Hz이상의 변조 주파수가 필요하다. 스위치를 5초 동안 ON하고 5초 동안 OFF한다고 상상해 보라. Duty cycle은 여전히 50%이지만 전구는 처음 5초 동안 밝게 빛나고 다음 5초 동안은 꺼져 버린다. 전구가 4.5V의 전압을 가지게 하기 위해서는 장치(lamp)가 스위치의 상태변화(ON,OFF)에 반응하는 시간에 비해 상대적으로 스위치를 켜고 끄고 하는 시간이 더 짧아야 한다. 전구에 빛은 들어오는 상태에서 좀더 어둡게 하기 위해서는 변조 주파수를 더욱 증가 시켜야 한다. 다른 PWM의 응용도 위의 경우와 같다. 일반적인 변조 주파수의 범위는 1kHz에서 200kHz사이 이다.

하드웨어 컨트롤러

많은 마이크로 컨트롤러가 칩상에 PWM을 내장하고 있다. Micorchip의 PIC6C67은 2개를 내장하고 있는데 각각은 on-time과 그 기간을 선택할 수 있다. Duty cycle은 on-time과 그 길이에 대한 비율이다. 변조 주파수는 그 기간의 역수 이다. PWM을 동작시키기 위해서는 데이터 시트에 소트트웨어에 대해 아래와 같은 명세가 있어야 한다.

* 사각형파 변조를 제공하는 칩에 내장된 타이머와 카운터의 길이를 설정
* PWM 레지스터의 on-time을 설정
* 범용 목적의 I/O핀인 PWM output의 방향을 설정
* 타이머 시작
* PWM컨트롤러를 가능으로 설정

PWM컨트롤러에 대한 세부적인 프로그램 명세가 다양하다 하더라도 기본적인 것은 위에 설명된 것과 같다.

통신과 제어

PWM의 장점중의 한 가지는 프로세서에서 컨트롤된 시스템에 이르는 모든 길이 디지털화 되어 있다는 것이다. 어떠한 DAC(디지털/아날로그 변환)도 필요하지 않다. 디지털 신호를 계속 유지 함으로써 잡음을 최소화 한다. 잡음은 논리적인 1을 논리적인 0으로 바꿀 만큼 충분히 강한 경우에만 디지털 신호에 영향을 준다.

아날로그 제어를 위해 PWM을 선택하면 잡음이 어느 정도 증가 하더라도 상관없으며 이는 통신을 위해 PWM을 사용하는 주요한 이유가 된다. 아날로그 신호를 PWM으로 변환하면 통신 채널의 길이를 크게 증가 시킬 수 있다. 수신 말미에 적절한 RC(resistor-capacitor) 혹은LC(inductior-capacitor)회로는 고주파 사각형파 변조를 제거할 수 있고 아날로그 형태로 신호를 만들 수 있다.

PWM은 다양한 시스템에서 응용되고 있다. 좀더 구체적인 예로, PWM으로 제어되는 브레이크를 생각해 보자. 문제를 간단히 하기 위해 브레이크를 아주 강력히 제지하는 장치로 생각하자. 대부분의 브레이크에서 제지력의 크기는 아날로그의 입력신호로 제어된다. 브레이크에 전압이나 전류가 커질수록 브레이크의 제지 압력 또한 커진다.

PWM은 다양한 시스템에서 응용되고 있다. 좀더 구체적인 예로, PWM으로 제어되는 브레이크를 생각해 보자. 문제를 간단히 하기 위해 브레이크를 아주 강력히 제지하는 장치로 생각하자. 대부분의 브레이크에서 제지력의 크기는 아날로그의 입력신호로 제어된다. 브레이크에 전압이나 전류가 커질수록 브레이크의 제지 압력 또한 커진다.

100psi의 압력을 브레이크에 설정하기 위해서 소프트웨어는 해당 크기의 힘을 얻기 위한 duty cycle을 역순으로 찾기 시작한다. 새로운 값으로 PWM duty cycle을 설정하면 브레이크는 이에 따라 반응한다. 시스템에 센서가 있다면 원하는 정확한 압력을 얻을 때 까지 closed-loop control 하에서 duty cycle을 미세하게 조절 할 수 있다.

PWM은 경제적이고 공간을 절약하며 잡음에 강하다. 이제 이걸 익혔으니 사용해 보라.
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag PWM

http://blog.naver.com/zeta6262?Redirect=Log&logNo=150015704463

 

시리얼포트의 개요

 

흔히 시리얼통신에 대해 많은 사람들이 오해하고 있는 것 중의 하나가【시리얼통신 = RS-232C】관계라고 생각하는 것이고, 또 다른 오해는 시리얼통신이 터미널 디바이스간의 통신규약으로 생각한다는 점이다. (예컨대 원격에 떨어져 있는 PC() PC()간의 연결을 위한 회선규약이 RS-232C라고 생각하는 것)

여기서 데이터를 주고 받는 최 종단의 장비인 PC(甲과 乙) "데이터 터미널 장비"(줄여서 DTE)라고 부른다.

그런데, 시리얼통신은 이들 DTE사이의 통신선로에 대한 규약이 아니다. DTE 사이에는 이들을 연결시켜주기 위한 통신장비가 존재하는데(예컨대 모뎀 따위 등) 이들을 "데이터 통신 장비"(줄여서 DCE)라고 한다. 따라서, 양단의 통신에 대한 관계는 다음과 같이 표현할 수 있다.

(DTE) ━━━━ 모뎀(DCE) 〓〓〓〓 (원격) 〓〓〓〓 모뎀(DCE) ━━━━ (DTE)

 우리가 말하는 시리얼통신의 정확한 표현은 DTE DCE사이의 통신을 말한다. (그림에서 굵은 선에 해당하는 부분) 따라서, 모뎀과 모뎀 사이의 통신선로는 관여치 않는다. 우리가 과거 모뎀을 통해서 PC통신을 했을 때에는 전화망을 이용했고, 요즘의 초고속통신은 ADSL이나 케이블방송 또는 전력선 등의 회선을 이용하기도 한다.

RS-232C DTE DCE사이의 연결을 위한 인터페이스 방식 중의 하나에 불과하다. PC에서는 자주 볼 수 없지만, RS-422, RS-485와 같은 시리얼통신 인터페이스도 존재한다. 다만, PC에 사용되는 시리얼통신 인터페이스가 대부분 RS-232C를 사용하는 것이고, 그 중에서도 DB9(9핀으로 구성된 커넥터) 인터페이스를 주로 사용하고 있을 뿐이다(참고로, RS-232C에는 DB25라는 25핀 커넥터도 있음). DTE에 해당하는 우리의 PC를 기준으로 봤을 때 모뎀, 마이컴 보드, 기타 하드웨어는 대개 DCE로 취급한다.

DTE 장비의 인터페이스는 수컷(Male) 커넥터 구성되어 있다(지금 여러분의 PC의 뒷면을 확인하기 바람). 그리고, DCE에 해당하는 장비는 대체로 암컷(Female) 인터페이스로 구성되어 있다. 간혹 수컷 인터페이스로 구성되어 있는 경우도 있기는 한데, 이 때문에 시리얼 인터페이스를 이용하여 디바이스를 연결할 때 혼동이 오는 경우가 있다. (이것은 극히 예외에 해당됨)

사용자 삽입 이미지

 
위의 그림은 DTE DCE 인터페이스의 핀 아웃을 설명한 것이다. DTE를 컴퓨터, DCE를 모뎀 또는 마이컴 보드로 생각하면 기억하기 쉽다.(, 위의 그림이 마이컴, 아래그림이 PC라고 생각할 것)

 DTE(컴퓨터)는 수컷커넥터가 원칙이며, DCE(모뎀, 마이컴보드)는 암컷커넥터가 원칙이다.

 DTE DCE 디바이스를 연결하는 경우를 생각해보자. PC에서 데이터를 3번핀을 이용하여 송신(Tx)하면, 마이컴은 3번핀으로 수신(Rx)할 것이다. 따라서, DTE DCE가 각각 수컷, 암컷 커넥터로 구성되어 있다면 그냥 커넥터끼리 연결하면 된다. 다만, 디바이스의 크기로 인해 마이컴을 PC에 직접 연결하지 못할 경우에는 확장케이블(Extention Cable)을 이용하여 연결할 수 있다. 확장케이블은 한쪽은 수컷, 다른 한쪽은 암컷 커넥터로 연결되어 있다.

또 다른 상황으로서, DTE DTE DCE들을 거치지 않고 직접 연결되어 있다고 생각해보자(, 모뎀 없이 PC PC를 연결한 경우). 이 경우 DTE는 서로 수컷 커넥터로 구성되어 있으므로 직접 연결할 수 없다. 게다가, 두 디바이스가 송신(Tx) 3번핀으로 동일하고 수신(Rx) 2번핀으로 동일하다. 데이터가 재대로 송수신이 되기 위해서는 두 디바이스를 연결하는 케이블이 교차되어 연결되어야 할 필요가 있다. 그래야, 송수신에 아무런 문제가 없게 된다.

 따라서, 이러한 경우에 사용되는 케이블을 크로스케이블(또는 널 모뎀)이라고 부른다. 널 모뎀이라 불리는 이유는 모뎀 없이 두 PC가 연결되어 있어서 겉보기에는 마치 모뎀이 중간에 있는 것처럼 보이기 때문이다. 널 모뎀 케이블은 양쪽이 모두 암컷 커넥터로 이루어져 있다. 간혹, 양쪽 모두 수컷 커넥터로 이루어진 경우도 있는데, 이럴 경우에는 젠더(Gender)라는 것을 이용하면 암수 핀변환이 가능하다.

사용자 삽입 이미지


사용자 삽입 이미지

 위쪽사진은 연장케이블과 널모뎀케이블의 실물의 모습이고, 아래쪽 사진이 바로 젠더라고 하는 것이다. 보다시피 한쪽은 암컷, 반대편은 수컷으로 되어 있어 핀 변환이 자유롭다.

 간혹 변칙적으로 DCE(마이컴보드) 측의 인터페이스가 수컷커넥터로 되어 있거나, Tx신호라인이 3번핀에 위치한 경우가 종종 있다. 본좌도 간혹 이렇게 변칙적으로 구성된 디바이스로 인해 많은 혼동을 일으키기도 했는데, 이 경우는 예외에 해당하므로 원칙을 정확히 알아두면 케이블이나 젠더를 바꾸어 줌으로써 문제점을 충분히 해결할 수 있다.

항상 마이컴 보드는 암컷커넥터에 2번핀이 송신(Tx)이라는 것을 원칙으로 정하고 보드를 설계하는 것이 편리할 것이다. 그렇지 않으면 다양한 종류의 케이블과 변환 젠더 등을 항시 실험실에 보유하고 있어야 하므로 매우 불편해지기 때문이다.

 

 

RS-232C 커넥터의 핀배치 정리

RS-232C DTE(예컨대, PC 또는 터미널) 기준으로 아웃을 정의하고 있다. 또한, DCE(예컨대, 모뎀 또는 주변기기) DTE 직선케이블(Straight Cable 또는 Extension Cable) 연결하도록 되어 있다. 따라서, DCE측의 커넥터 배치도 DTE 동일할 밖에 없다.

 그런데, 이러한 배치의 표기는 대다수의 사람들뿐만 아니라 엔지니어에게조차 혼동을 유발하곤 한다. 본인도 예외는 아니어서 수첩에 적어놓고 사용하기도 . -,.;;

 예를 들어, DB9 커넥터의 경우, DTE TxD 라인은 3 핀인데 DCE 3 핀도 TxD라고 부르게 되면 이름상으로는 라인이 서로 충돌을 일으키는 셈이다. 또한 RTS CTS 같은 이유로 인해 혼동이 생긴다.

 따라서, 커넥터의 배치는 디바이스 자신을 기준으로 명기하는 것이 혼동을 피할 있는 가장 쉬운 방법이 아닐까 생각한다. 그래서, 여기저기 자료를 찾아 다니며 정리한 끝에 RS-232C 인터페이스 커넥터의 배치에 대한 명확한 정리를 해봤다.

사용자 삽입 이미지

 
그림이 다소 지저분하고 안보이므로 DB9 커넥터만 다시 정리해보면 다음과 같다.

사용자 삽입 이미지

 
위의 그림은, 통신이 성공적으로 이루어져야 한다는 전제하에 DTE DCE 다이렉트로 연결할 경우 디바이스를 기준으로 배치를 나타낸 것이다. 따라서, 아까 설명했던 Tx, Rx  디바이스의 관점에서 위와 같이 표기하면, 엇갈려 표기되어 있으므로 혼동의 여지가 없다.

 그런데, 한가지 여기서 짚고 넘어갈 것은 RTS CTS 또한 엇갈려 표기되어 있다는 점이다.

 RTS CTS 데이터 송수신을 위한 통신채널의 흐름제어에 사용되는 신호들인데, 원래 RS-232C 표준에는 DB9커넥터의 7 핀의 경우 RTS 할당되어 있고, 8 핀의 경우 CTS 할당되어 있다. , DCE 경우에도 RTS CTS 위치가 바뀌어야 정상이다. 하지만, 표준에서 설명하는 것과 같이 RTS 오직 DTE DCE 전송하는 신호이고, CTS DTE DCE로부터 수신하는 신호이다.

 다시 말해서 DTE 관점에서 보면, RTS 송신으로만 사용되며 CTS 수신으로만 사용된다. 이와 반대로 DCE 입장이라면 뒤바뀌어야 것이다. 이것 또한 혼동을 유발하기 일쑤다. (개인적으로 RS-232C 커넥터를 저런 식으로 DTE 관점으로만 정의했는지 불만이다. 인터넷 도처에 있는 커넥터의 그림을 보면 각각이다. 그리고, 그것이 마치 표준인 것처럼 설명하고 있다. DTE측에서 그림인지, DCE측에서 그림인지조차 설명 안되어 있는 그림도 많고, 심지어는 PC측의 DB9 커넥터를 암컷으로 명기하고 있는 그림도 있다. 결국, RS-232C 배치는 핀들이 방향성을 가지고 있기 때문에 디바이스를 기준으로 상대적으로 해석해야 올바르지 않나 싶다.)

그러므로 디바이스의 관점에서 RTS Tx 같이 나가는 신호, CTS Rx 같이 들어오는 신호로 파악하는 것이 나중에 핸드쉐이킹 부분을 이해하는데 도움이 것이다.

 

 

TTL RS-232C의 관계

마이컴이나 디지털회로에 사용되는 전압(보통 TTL전압이라고도 부른다) 대개 +5V 내외로서 DTE에서 DCE로의 연결에는 적합하지 못하다. 따라서, RS-232C는 이를 증폭하여 보다 높은 전압의 상태에서 DTE DCE의 디바이스를 연결할 필요가 있다.

사용자 삽입 이미지

 
그렇다면, TTL 레벨의 디지털회로에서 어떻게 RS-232C레벨의 전압을 얻을 수 있을까? 통상 저 전압의 디바이스에서 고전압을 얻는 방법 중에 차지 펌프(Charge Pump)라는 방식이 있는데 이 방법을 이용하여 디지털보드는 RS-232C와 인터페이싱이 가능하다. 그 때 사용되는 부품이 바로 그 유명한 MAX232라는 칩이다.

데이터송수신에 사용되는 칩을 흔히 라인 드라이버라고도 하는데, MAX232 TTL레벨과 RS-232C레벨을 변환해주는 라인 드라이버의 한 예이다. 아래는 MAX232의 구성을 나타내는 그림이다.

사용자 삽입 이미지

 MAX232
의 구성도를 보면 차지펌핑을 위해 커패시터 4개가 사용되고 있음을 알 수 있다. MAX233이라는 칩은 차지펌핑에 사용되는 커패시터가 칩에 내장되어 있어 별도로 붙일 필요가 없다. 대신 가격은.... ,. 5천원정도.. ㅋㅋ MAX232 600~800원정도. ㅋㅋ 

한편 3.3V의 디지털제품에 사용되는 MAX3232라는 칩도 있으며 그 외에 다양한 파생품들이 있으니 홈페이지를 방문하여 참고하도록 하도록 하자.

 

 

RS-232C의 전기적 특성

RS-232C의 전기적 특성을 설명하기 전에 다시 한번 기억해야 할 점은 RS-232C DTE DCE사이의 인터페이싱하기 위한 전기적 특성을 표준화한 것이라는 점이다. 따라서, DCE DCE사이의 전기적 특성은 고려하지 않는다. (, 전화로 연결을 하건, 광케이블로 연결을 하건 상관없다는 것)

먼저, 새롭게 등장하는 용어에 대해서 정리하도록 하자.

1. 로직레벨(신호레벨) 

시리얼케이블의 각 핀이 가지는 논리적 의미를 말한다. 쉽게 말해 이진수 1 0을 생각하면 되겠다. , 데이터신호의 경우 로직레벨은 '1' '0'이며 제어신호의 로직레벨(신호레벨이라고도 함) 'On' 'Off'이다.

로직레벨 '1'의 경우를 마크(MARK), 로직레벨 '0'을 스페이스(SPACE)라고 부르기도 한다. , 마크는 음의 전압레벨 상태를 말하며, 스페이스는 양(+)의 전압레벨 상태를 말한다. 주로 데이터 신호의 로직레벨을 설명할 때 사용한다.  

2. 전압레벨 

로직레벨이 의미를 가질 수 있는 전압의 허용범위를 말하는데, 통상 양(+)의 전압과 음(-)의 전압의 범위를 가질 수 있다.

전압레벨을 말할 때는 두가지 주의해야 할 점이 있다.

첫째, 전압레벨이 송신단과 수신단에서 그 허용범위가 다르다는 점이다. 먼저 양(+)의 전압레벨의 경우 송신단에서는 +5~+15V 인데 반해 수신단에서는 +3~25V이다. (-)의 전압레벨의 경우 송신단에서는 -5~-15V인데 반해 수신단에서는 -3~-25V이다. 이처럼 송수신단의 전압레벨이 다르다는 점은 매우 중요한 사실이다.

둘때, 데이터신호의 경우 로직레벨과 전압레벨의 역의 관계에 있다는 점이다. , 데이터신호의 로직레벨 '1'(마크)은 음(-)의 전압레벨을 가진다. 반대로 로직레벨 '0'(스페이스)은 양(+)의 전압레벨을 가진다. 이와 반대로 제어신호는 로직레벨과 전압레벨이 일치한다. 로직레벨 'On'은 스페이스(+)의 전압레벨을 가지며 로직레벨 'Off'는 마크(-)의 전압레벨을 가진다.

아래의 그림은 로직레벨과 전압레벨에 대한 관계를 그림으로 나타낸 것이다.

사용자 삽입 이미지

 
위의 그림에서 전압레벨이 의미가 없는 곳(빗금친 영역)이 있다. 송신단에서는 -5~+5V의 영역이고, 수신단에서는 -3~+3V의 영역이다. 이 대역의 전압은 의미가 없게 되므로 주의할 필요가 있다. 다시 말해 어떠한 이유로 빗금 친 대역의 전압레벨을 보일 경우 데이터 오류의 원인이 되는 것이다.

 

 

시리얼통신에서 자동으로 보레이트 설정하기

마이컴보드를 사용할 때 정확한 보레이트값을 모르면 시리얼통신이 재대로 되지 않아 답답할 때가 있다. 게다가, 매번 호스트의 터미널에서 보레이트를 설정하는 게 귀찮기까지 할 때도 있다. 사용자가 어떠한 보레이트의 속도로 접속하더라도 마이컴이 이를 감지하여 자동으로 보레이트를 일치시켜 통신이 가능하도록 하는 방법이 있는데... 이를 Automatic Baudrate Detection 기법이라고 한다.

 ABD 기법은 uC의 종류에 따라 다양한 방법으로 구현이 가능한데, 그 중 한 방법을 소개하려고 한다. 인식되는 보레이트는 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200bps이며 호스트의 터미널 프로그램 사양에 따라 다른 보레이트 또한 얼마든지 지원할 수 있다. (또한, 이 원리를 조금만 이용하면 ABD 기능을 터미널 프로그램에도 적용할 수 있다.)

ABD는 마이컴이 ON(또는 리셋)되고 나서 사용자가 특정문자를 맨 처음 보내면서 시작된다. 간단하게 엔터키를 사용자가 입력했다고 가정하고 ABD기능을 구현해보자.

우선, 마이컴을 부팅할 때 보드가 지원할 수 있는 최대 baudrate 속도로 부팅시키자. 통상 115200bps을 최대속도로 사용하므로 이 값으로 부팅되었다면... 호스트에서 입력한 엔터키는 호스트측의 보레이트에 따라 다음과 같은 값으로 수신될 것이다.

사용자 삽입 이미지

 엔터키의 아스키코드는 0x0D이며 시리얼통신에서는 LSB(최하위비트)부터 수신된다. 비동기 통신이므로 시작비트와 정지비트가 데이터비트를 감싸는 형태로 수신될 것이다. 시리얼포트의 수신핀은 맨처음 HIGH상태를 유지하면서 데이터가 들어오기를 기다린다. 이윽고, 시작비트(LOW)가 들어오면서 수신이 시작되는데 115200bps의 경우 1비트의 시간은 1/115200 초이므로 이 시간 간격으로 차례로 D0, D1, ... , D7 를 수신해서 데이터(바이트)값을 검사한다.

 

이 값이 0x0D라면 호스트는 115200bps로 설정되었음을 알 수 있다. 따라서, 마이컴은 115200bps로 포트를 초기화하면 된다.

만약, 115200bps보다 느린 속도로 접속했다면... 패킷의 수신 시간은 보레이트에 반비례하므로 위의 그림과 같은 형태로 수신될 것이다. 따라서, 이 값을 위의 57600, 38400bps등에서의 값과 비교해서 일치하는 보레이트로 초기화시켜주면 된다.

 

그런데, 9600bps이하의 저속의 보레이트로 접속했다면... 수신된 데이터는 어느 경우라도 0x00이므로 문제가 생긴다. 따라서, 일치하는 데이터가 없을 경우 마이컴을 9600bps로 재설정하여 호스트로부터 엔터키를 한번 더 입력받는다.

사용자 삽입 이미지

 호스트가 9600bps로 접속한 경우라면 2번째로 입력받은 엔터키는 0x0D로 수신될 것이며 그 이하의 속도로 접속했다면 위와 같은 형태의 값으로 수신하였을 것이다. 위의 값도 아닌 경우라면... 에러가 발생한 경우이거나... 지원되지 않는 속도로 접속한 경우이므로 예외처리를 하면 된다.

 이상의 알고리즘을 순서도로 구현하면 다음과 같다.

사용자 삽입 이미지
 

위의 방법은 uC의 종류에 구애받지 않고 구현할 수 있는 알고리즘으로 1 ~ 2번의 엔터키 입력으로 어떠한 속도의 보레이트라도 검출이 가능하다. 관심 있는 분들은 한번 도전해보시길...

 

< ABD 구현을 위한 >

 

1. 엔터키를 입력 받는 루틴(단계1 : 115200bps, 단계2 : 9600bps)은 날카로운 독자 분들이라면 통상의 시리얼 통신으로는 구현할 수 없다는 걸 짐작했을 것이다. 9600bps 2400bps의 경우 정지비트가 HIGH가 아니기 때문에 엔터키가 정상적으로 수신될 수 없기 때문이다. 따라서, ABD 루틴은 RxD핀을 시리얼포트가 아닌 일반 I/O포트로 가정하고 타이머나 다른 방법을 이용하여 bit-by-bit로 수신해야 한다. 다시 말해 일정시간 간격(1/115200 또는 1/9600초의 시간간격)으로 RxD핀의 I/O 레벨을 검출해야 한다는 것!

 

2. 해당 비트의 수신은 각 비트의 주기에서 중앙값에서 측정하는 것이 정확성이 높다. 따라서, 에지(edge)단에서 검출하지 말도록 하자.

 

3. 8개의 비트를 수신하여 1바이트 데이터를 만든 다음, 어느 정도 딜레이를 주어야 한다. 왜냐하면, 저속으로 접속한 경우... 마이컴은 1바이트를 검출하였더라도.. 호스트 쪽에서는 여전히 데이터를 보내고 있기 때문이다.

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

VHDL

Hardware 관련 2008.03.09 20:03


< CHIP DESIGN>


  • VHDL  (Very high speed integrated circuit Hardware Description Language)

  • HDL은 하드웨어를 기술하는 언어이다.


VHDL 소개

  HDL이전의 하드웨어 설계에서는 주로 레이아웃 편집기(layout editor)나 스키메틱 편집기(schematic editor)를 이용해 작은 블록을 설계하고 이것을 이용해 큰 블록을 설계하는 상향식 설계(bottom-up)를 했다. 하지만 설계해야 할 회로의 규모가 커지고 복잡도 가 증가 함에 따라 이러한 방법은 한계에 도달하게 되었다. 따라서 알고리즘이나 기능레벨에서 설계가 가능하도록 하는 HDL이 출현하게 되었다. HDL을 통해 회로를 설계하는 방식을 하향식(top-down)설계 방식이라 한다.


집적회로 설계의 변천과정
 제 1 단계  (60년 ~ 70년대)
 제 2 단계  (80년대)
 제 3 단계  (90년대)
 
설계방법
 트랜지스터 레벨의 레이아웃 설계 (상향식 설계)
 게이트나 RTL 레벨의 논리설계.  알고리즘이나 기능 레벨의 설계 (하향식 설계)
 
설계도구
 레이아웃 편집기  스키메틱 편집기  HDL과 합성
 
설계범위
 SSI, MSI (103게이트 이하)
 LSI, VLSI (103 ~ 105게이트)
 VLSI, GSI (105 게이트 이상)
 
설계 예
 게이트, 카운터, 멀티플렉서, 가산기, 마이크로프로세서, 주변장치, 고성능 마이크로프로세서, 실시간 영상처리

  HDL은 상위수준의 하드웨어 기술언어이기에 보다 낮은 레벨로 바꾸는 과정이 반드시 필요하게 된다. 이러한 과정을 합성(synthesis)라 한다.  HDL로 기술된 회로의 기능을 시뮬레이션 할 때는 합성까지는 필요없으나 실제 지연이나 타겟 소자(PLD, ASIC...)등의 크기와 특성을 고려한 시뮬레이션 할 때는 합성의 과정을 해 주어야 한다.  PLD(Altera, xilinx, ...)등은 전용 시뮬레이터가 있어서 쉽게 합성할 수 있다.

 1986년 3월부터 VHDL을 IEEE표준으로 제정하기 위한 노력이 기울여져 1987년 12월에 IEEE-1076이라는 IEEE표준 VHDL이 탄생했다. 1991년에는 IEEE1076에 추가하여 설계자들로 하여금 VHDL 모델을 공유하는데 도움을 주고 또한 합성 기능의 강화를 위해 9개로 구성된 표준 논리 레벨 MVL9('U', 'X', '0', '1', 'Z', 'W', 'L', 'H')를 정의한 IEEE1164(std_logic_1164)를 발표하였다. 1992년에는 VHDL이 미국 정부지원 공인 HDL(FIPS Pub172)로 정해졌으며 미국 정부와 하드웨어 개발을 계약하거나 표현하는 경우에는 반드시 사용해야 하는 유일한 표준언어가 되었다. 아울러 VHDL의 기능을 개선하기 위한 노력이 기울어져 1993년에는 VHDL1076-1987에 대한 새로운 버전인 IEEE1076-1993을 내놓게 되었다.

 VHDL을 시뮬레이션하고 합성하는 Tool은 대표적으로 Synopsys, Cadence, Compass, Mentor Graphics,... 등이 있고 PLD에서 이용되는 전용 시뮬레이터에는 Altera MAX+, Xilinx,.....등이 있으며 이외에도 기능 시뮬레이션에서 쓰이는 ActiveVHDL, Model tech(V system)등이 있다.



VHDL 개요

 전자 산업은 곧 부품산업이라고 해도 무리가 없는듯하다. 그중에서도 반도체분야는부품산업의 꽃이라고 할수 있다. 그러나 가치가 있는 만큼 어려움이 따르는것은당연한 이치라고 생각한다. 종래의 반도체 설계는 주로 숙련된 엔지니어가 schematic capture를 이용하였으나, time-to-market과 설계의 복잡도 증가로 새로운 방법이나타나게 되었는데 그것이 바로 (V)HDL이다.

1. (V)HDL이란?

HDL은 Hardware Description Language의 이니셜 문자이고 하드웨어 기술(표현) 언어라고 한다.이것은 타겟 프로젝트의 동작 특성을 문법을 갖는 언어로 표현(기술) 한다는 것을 의미한다. 동작 특성이라고 하는것은 일반적으로 spec., datasheet, idea등이 될수 있다.

즉, 종래에는 어떤 기능블럭을 설계할때 AND,OR,MUX,F/F등을 이용하여 회로를 구성하였으나 지금은 일반적인 프로그래밍 개념을 접목한 HDL을 이용하는데 그 대표적인 것이 VHDL과 Verilog-HDL이다. HDL이란 이와 같이 동작특정을 정해진 문법과 키워드 그리고 사용자 정의 객체들을 가지고 기술(description)하는 것이다. 본강좌의 주제인VHDL은 회로의 연결 정보를 포함할 뿐만아니라 C와 같은 프로그래밍 언어의 성격도 가지고 있어서 매우 다양한 하드웨어 기술 방법을 제공한다. HDL이 C와같은 프로그래밍 언어와 다른점은 프로그래밍 언어는 전부 순차구문(sequential statements)으로 구성 되어 있지만 HDL은순차구문 이외에 병렬구문(concurrent statements)과 타이밍 개념이 있는것이 차이점이다.


2. HDL의 종류

1) Verilog-HDL : HILO-HDL(GenRAD사)을 기본으로 만들어진 HDL로서 RTL특성이 강하여하드웨어에 가까운 문법과 구조로 이루어져 있다. 초보자에게 다소 접근이 용이한 언어이다.

2) AHDL : '80년대에 IBM에서 교육용으로 사용되다가 Altera사의 Maxplus에 접목하여사용되고 있는 언어이다.

3) UDL/I : RTL위주로 되어 있으며, 일본에서 VHDL에 대응하기 위해 만들어낸언어이다.

4) 기타 CDL,DDL,ISP,PMS등 교육용과 회사 내부용으로 여러가지가 있다.


3. VHDL의 역사적 배경

보다 대형화 및 복잡화하는 소프트웨어를 설계하기 위해 초창기 어셈블리 언어에서 지금은FORTRAN,PASCAL,C,LISP와 같은 하이레벨 프로그래밍 언어를 사용하듯이, 하드웨어 설계에 있어서도전통적인 schematic capture방법 대신에 CAD TOOL상에서 VHDL과 같은 HDL을 이용하여 TOP-DOWN 설계 방식을적용하게 되었다. 이러한 방법은 설계기간을 단축할수 있을뿐만 아니라 설계 데이타의 관리, 교환, 재사용등에 훨씬 용이하게 되었다.

이러한 이유로 미국방성(DoD)에서 VHSIC(Very High Speed Integrated Circuit) 프로그램을 수행하는 과정에서 VHDL이 공식 논의되기 시작하였다.(1981년)1983년에 VHDL에 대한 제안요청은 미공군이 작성하였고, 같은해 IBM,TI,Intermetrics사가 주축이 되어 1985년에 VHDL 7.2 버전을 발표하게 되었다.

1987년 12월에 IEEE에서 IEEE Standard 1076-1987로 확정되었다. 이후 계속된 노력으로 1993년도에 std_logic_1164를 포함하는IEEE 1076-1993과 이어서 IEEE 1076-1997이 발표되어 현재에 이르렀다.

아래는 산하 연구 그룹으로 다음과 같다.

IEEE 1076.1 : VHDL Analog Extension

IEEE 1076.2 : Math Package

IEEE 1076.3 : Synthesis Package (std_logic_1164)

IEEE 1076.4 : Timing Methodology (VITAL)

IEEE 1076.5 : utility

IEEE P1165 : EDIF EIA-567-A : Component modeling and Interface


4. VHDL의 특징

1) 표준화된 HDL : 표준화라는 말은 누구나 어떠한 환경하에서도 정보를 공유할수 있다는 의미이다.

그러나 종래의 표준화되지 못한 HDL은 특정 사람과 환경에서만 사용할수 있기 때문에정보공유, 재사용등에 문제가 있었다. 이러한 문제는 표준화된 VHDL의 등장으로 모두 해결되었다. 즉, 타겟 라이브러리와 테크놀러지에 상관없이 사용할 수 있게 되었다. 설계의 초기 단계에서 사양서에 따른 동작 특성과 알고리즘 검증은 반도체 공급업체의 라이브러리와 상관없이 VHDL로 기술하여 시뮬레이션을 할수 있다. 이러한 방법론은 시스템 관점에서 또는 알고리즘 관점에서 동작 특성을검증하는 표준화된 VHDL의 특징이라고 할수 있다. 즉, 특정 CAD 소프트웨어와 라이브러리에상관없이 사용할 수 있으므로 보다 쉬운 정보교환 등으로 설계상의 오류 및 개발 기간을 단축할 수 있으므로 전체적인 설계 비용을 줄일 수 있다.

2) 이용의 확대 : IEEE 표준으로서 미국방성 공인 HDL이다. 이러한 상황은 사용자 층이 유럽과 아시아로 점점 확대 되고 있다.

3) 설계 기술 능력 : 실제 IEEE 1076 매뉴얼을 보면 모든 하드웨어를 표현할수 있도록 되어 있다.

디지탈은 물론 아날로그 표현, 다양한 타이밍 표현, 시스템 레벨에서 트랜지스터 레벨까지 다양한 레벨을 표현할수 있도록 하였다. 또한 물리적인 양의 표현, 병렬 신호 할당문, resoluton function등 여러가지 표현이 가능하다.

그러나 현재는 상용 CAD TOOL의 제한으로 그리고 사용자의 요구로 지금은 시뮬레이션과 합성을 주로 사용하고 있다.

4) 언어로서의 기능 : 기본적인 하이레벨 언어의 특성을 가지고 있을 뿐만 아니라 논리적인 연산자와함수, 문자, 사용자 정의 자료 형태, 속성등의 특징이 있다.


5. VHDL의 표현방법(Y 차트라고함 : 나중에 자세히 설명)

임의의 기능 블럭에 대해서 다양하게 기술할수 있다. 기술하는 방법론을 우리는 모델링이라고한다. 일반적으로 behavioral modeling, dataflow modeling, structural modeling등 세가지로분류한다. 물론 사용자에 따라 사양서의 특성에 따라 혼합해서 사용할수도 있다.

1) Behavioral modeling : 인간과 가장 가까운 추상적인 표현으로서 시스템이 내부적으로 어떠한 동작 특성을 가지고 있는 지에 상관없이 설계자가 원하는 것을 기능적 또는 수학적인 알고리듬을 사용해서 시스템의 기능(function)을 기술하는 것을 말한다. 즉 초기 설계 단계에서 알고리즘 검증을 위해서 많이 사용한다.

2) Dataflow modeling: 신호 및 제어의 흐름과 같은 데이타의 흐름을 나타낸다. 주로 부울대수, 함수, RTL 또는 연산자(AND, OR 등)를 사용하여 입력으로부터 출력까지의 경로 표현을 위주로 한다. Behavioral modeling 단계보다는 하드웨어에 가깝게 기술한다.

3) Structural modeling: 세가지 모델링 중에서 하드웨어에 가장 가까운 표현으로서모든 컴포넌트 뿐만 아니라 이들의 상호연결도를 나타낸다. 즉 레지스터와 버스뿐만 아니라 게이트 수준의 설계를 가능하게 한다.


6. 한국의 VHDL

국내에서는 80년대 말쯤에 CADENCE TOOL을 사용하는 몇몇 대기업에서 Verilog-HDL을 일부 사용하고있었으나 극히 제한적이었다. 이즈음 VHDL도 발표가 되어 연구소와 학계에서는 국내 HDL 표준화 문제가등장하게 되었다. 결국 Verilog-HDL과 VHDL 둘중의 하나를 선택하는 일이었다.

그당시 Verilog-HDL은 CADENCE라는 회사 전용 언어이고, VHDL은 IEEE에서 표준화된 언어이기때문에 쉽게 VHDL에 관심을 가지게 되었다. 그러한 배경으로 1988년도부터 ETRI,인천대,홍익대와공동으로 VHDL에 관한 연구(주로 TOOL개발)를 하게 되었다. 이때도 대기업들만이 관심을 갖고 있던 터라 ASIC이라는 말도 생소하거니와 VHDL은 더더욱 낯설은 단어였다.

90년대 들어서, 상업용툴이 등장하게 되었는데, 한마디로 놀라운 작품이었다.

시뮬레이터로는 Vantage(지금은 어느회사로 합병되어 있는지...), 그다음 합성기로는SYNOPSYS가 나오고, 이후 여러회사들이 발표하게 되었다.

지금이야 전자과 학생들은 웬만하면 VHDL을 다 접하고 있으니 놀라운 발전이라 할수 있다.

물론 시스템 업체를 포함한 대부분의 전자관련 업체에서도 지대한 관심을 가지고 있다 할수 있다.


7. VHDL의 접근 마인드

VHDL도 일종의 프로그래밍 언어임에는 틀림없다. 그러나 앞에서 언급한 몇가지 특성때문에실제로 적용할때는 몇가지 유념해야할 사항들이 있다. 대부분 VHDL을 접하는 초보자들은 기본적으로 C와 같은 언어에는 익숙해져 있는 상태이다. 그런 경험을 바탕으로 VHDL을 접하게 되면 하드웨어 구현에 초점을 맞추기 보다는프로그래밍 관점에 얽매이게 된다. 즉, 타이밍 개념, 저장 기능, 병렬처리같은 하드웨어에서는필수적인 기능들이 이해하기 힘든 상황으로 발전한다. 그래서 이러한 초보자들은 C와같은 프로그래밍 경험이 VHDL을 배우는데 도움이 되겠지만때로는 고정관념 때문에 방해가 되기도 한다. 단지 잇점이라고 할만한 것들은 언어의 감각뿐이다. 그리고 중요한 것은 디지탈 시스템에서 사용되는 기능블럭의 동작 특성을 얼마나 잘 이해를 하느냐 이다. 이해를 했다면 이를 어떻게 VHDL로 옮기느냐가 관건이다. 그러나 디지탈 시스템은 크게 조합논리회로와 순차회로로 분류할수 있는데,조합논리회로는 VHDL에서 MUX를 표현하는 방법만 알고 있어도 8-90%는 쉽게 접근할수 있다. 그러나 순차회로는 메모리 기능과 타이밍 개념이 있기 때문에 다소 어렵지만 그래도signal문과 process문을 이해한다면 이 또한 8-90%는 커버하리라 생각한다. 다시한번 강조하지만 먼저 타겟 프로젝트에 대한 기능블럭의 동작 특성을 이해하는 일이 매우 중요하다. 그런 다음에 VHDL로 기술하는 것은 그리 어렵지 않게 할수 있다. 물론 VHDL 관점에서도 이를 어떻게 기술하느냐에 따라 최적화가 달라질수 있지만, 무엇보다도시스템 관점이 매우 중요하다고 할수 있다. 결국 ASIC이건 VHDL이건 모두가 시스템 설계자의 몫이기 때문이다. ASIC을 만드는 일중에서 7-80%를 차지하는 부분이 바로 시스템 설계자가spec.을 정하고 이를 토대로 동작특성을 이해하여 VHDL로 옮기는 작업이다. VHDL로 옮긴후 그다음 작업은 CAD TOOL을 이용하기 때문에 한마디로 단순작업이라고 할수 있다. 여기서 ASIC 설계자라고하는 것은 그 단순작업을 수행하는 사람을 칭한다.


9. VHDL Simulation & Synthesis

VHDL을 사용하는 입장에서 고려해야할 중요한 사항중에 하나는 시뮬레이션과 합성단계이다. 시뮬레이션이라고하는 말은 실제 ASIC으로 구현하기 전에 모의실험을 하는 과정이라고 할수 있다. 그리고 합성이라고 하는 말은 VHDL로부터 논리 회로도를 추출하는 과정이다. 그러면 여러단계를 거치는 시뮬레이션을 살펴보면 다음과 같다.

요즘에는 VHDL 시뮬레이터가 너무 많기 때문에 특정툴에 기반을 두고 설명하기란 쉽지 않다. 그래서 여기서는 일반적인 사항들을 설명하고자 한다. 먼저 고려해야할사항은 PC 기반이든 Unix기반이든 기본적으로 공통된 라이브러리가 존재하게 된다. 즉, 특정 라이브러리(예를들어 LSI, 삼성등등)가 없어도 시물레이션을 할 수가 있다는 얘기다. 어디까지나 자체툴에서 제공하는 형태(어떤 툴에서는 intermediate format이라고도 한다)이기 때문에 타이밍(통상 Unit delay라고 한다)을 제외한 기능만 확인할 수 있게 된다.

특정 라이브러리가 정해지면(물론 특정툴에서 요구하는 환경을 갖춘다는 의미) VHDL 파일을 컴파일하게 된다. 여기서 컴파일이라고 하는 말은 광의의 말이다. 구체적으로 살펴보면 1단계로 parsing이라는 것을 거친다. parsing에는 VHDL 파일이 문법에 맞게 코딩을 하였는지 그리고 의미가 제대로 맞는지를 검사한다. 검사결과 에러나 워닝이 없으면 일단 툴이 받아들일 준비는 OK, 그다음에는 테스트 벡터(test bench file)를 만들어 running을 하게 되면 타이밍관계를 볼 수 있다. 물론 이렇게 쉽게 시뮬레이션을 할 수 있다면 다행이지만 실제는 그렇지가 않다. 일종의 반복작업을 수 없이 해야하기 때문이다. 즉, 컴파일 단계에서 몇 번에 걸쳐 no error and no warning 메시지를 얻었다고 하더라도 테스트 벡터를 가지고 시뮬레이션을 하면 쉽게 만족할 만한 결과를 얻을 수가 없다. 그래서 다시 VHDL 파일을 수정하여 컴파일하고 시뮬레이션하고 반복과정을 거친다.

9-1. VHDL coding model guide (계속)
초보자에서 전문가까지 도움되는 아주 중요한 얘기들......(소개)

1. ASIC(FPGA,EPLD)에서 VHDL의 의미?

   사실 VHDL, Verilog-HDL, Schematic Capture, 등등의 사용목적은 반도체칩을 만들기 위한 매체(수단)에 불과하다. 물론 그외에도 여러 가지 요소와 고려사항이 있겠지만, 여기서는 칩을 만들 때 가장 처음에 고려되는 Spec.으로부터 할 수 있는 것은 블록도 추출과 그에 대한 동작설명이다.  Spec.을 이해하고 이로부터 어떤 정형화된 형태를 추출한다는 것은 보통 어려운 일이 아니다. 즉, 피나는 훈련이 필요하다는 얘기다.

 VHDL 이라는 언어를 알아야하고 그런다음 하드웨어 시스템을 알아야하기 때문이다. 기본적으로 ASIC은 시스템 설계자가 접근하는 일이지 CAD개발자, S/W 개발자, Firmware개발자가 접근하는 것은 아니다. 일례로 VHDL 언어감각은 후자가 뛰어날지 몰라도 시스템을 이해하는 능력이 부족다면 의미가 없겠지요. 물론 가능은 하겠지만 정상적인 경우는 아니죠. 그래서 개인이건 회사건 ASIC을 하기전에 시스템을 먼저 접하는게 순서가 아닐까요?

  따라서 VHDL은 하나의 High Level Language(C와 같은)이자 하드웨어 개념을 표현할 수 있는 구조로 되어있다. 큰 차이점은 VHDL에는 타이밍 개념이 있다는 것이다. 이러한 원론적인 의미를 벗어나서 설계자가 ASIC을 할 때 방법론을 선택해야하는 문제에 직면한다. 어떤 개발환경을 구축할 것인가? 즉, Design Entry를 HDL로 할 것인가, 아니면 스키캐틱으로 할 것인가를 정하게 된다. 요즘에는 많이 HDL에 익숙해 있지만 아직도 중요한 블록들은 스키매틱으로하고 있답니다. 아마도 최적화 측면이겠지요. 각가 장단점은 있지만 VHDL을 사용하게 되면 장점이 많은 듯 합니다.

2. Spec.에서 VHDL을 추출하는 방법?

   통상 시스템 설계자가 Spec.(물론 기능 검증을 위해서 S/W개발자도 포함되겠지만, 일종의 지원팀이죠)을 정하는데, 대략 입출력 타이밍과 핀들의 정의 그리고 좀더 구체화 되었다면 내부 기능블럭들의 동작 설명정도이겠지요. 이정도라면 상당한 수준이지요. 이러한 데이터로부터 어떻게 VHDL을 추출하느냐? 정말이지 막막할겁니다. 그러나 몇가지 방법론이 있답니다. 디지털에서도 순차 와 조합논리 그리고 메모리, 이게 전부잖아요. 마찬가지로 이러한 개념을 어떻게 VHDL로 변환을 하느냐? 그야 간단하죠.

   우선 스펙이 어떤 형태로 제공하느냐가 관건이죠, 요즘에는 표준규격(ITU같은..)이 있어서 좀 나은편이지요. 표준규격이 있는 경우는 통상 먼저 규격을 C언어로 시뮬레이션을 해보죠. 알고리즘 검증차원에서요. 또한 여기서 VHDL에서 사용되는 테스트 벡터도 뽑아낸답니다. 그러나 표준규격이 없을 때에는 전적으로 설계자가 알아서 만들어 내야하는거죠. 여기서는 표준 규격, 데이터 쉬트등과 같은 정형화된 것으로부터 VHDL을 추출하는 방법을 소개할까 합니다.


3. CAD Tool 선정?

가장 민감한 문제이다. 회사입장에서는 바로 돈이기 때문이다. 최근에는 이러한 투자비가 많이들어가서 ASIC관련부서를 많이 줄이고 있는 실정이다. 돈얘기를 하는 이유는 제품 가격이 천차만별이기 때문이다. 작게는 $100이하부터 $100,000이상가는 것까지 광범위하다. 따라서 향후 계획이 서야 한다는 것이다. 처음에는 FPGA를 했다가 ASIC으로 가는 경우는 FPGA Tool은 바로 쓰레기통행이기 때문이다. 결국 예산과 프로젝트 성질에 달려 있다고 생각한다. 여기서는 그러한 계획을 세우는데 도움이 될 만한 몇가지를 설명하고자 합니다.

4. ASIC Vender 선정?

이것또한 돈과 관계가 있다. ASIC을 한번 하는 경우(NRE라고 하죠, 쉽게 말해서 ASIC 칩을 만드는 비용)수천만원에서 수억까지 비용이 들기 때문이다. 여기서는 Vender를 선정할 때 고려사항들을 말씀드리겠습니다.

5. 우리나라에서 사용되는 CAD TOOL & ASIC Vender 특징 및 비교

아주 민감한 부분이라 본란은 제한을 하겠습니다.

6. 주요 CAD TOOL의 사용 방법

7. 우리나라 VHDL 역사



VHDL의 자료형(data types)


VHDL에서 사용하는 자료형 (data type)과 객체들, 그리고 보고 합성 가능한 자료형에 대하여 살펴 보기로 한다.
VHDL 자료형 (Data Types)
VHDL의 자료형은 스칼라 형 (scalar type)과 복합 형(composite type)으로 나뉘어 진다.

VHDL에서 자료형 검사는 매우 엄격하며 정의된 자료형에 따라 사용할 수 있는 연산자 또한 각각 정의 되어야 한다. 합성기(synthesizer)에 따라 서로 지원하는 데이터형이 다를 경우 VHDL 소스 사이의 호환성에 심각한 문제를 일으키며 많은 자료형 변환 함수와 타입 캐스팅 방법이 존재하게 된다. 이러한 문제를 해결하기 위하여 87년 IEEE 1076 VHDL의 표준에 이어 1991년에 IEEE 1164로서 디지털 회로의 합성 가능한 자료형에 대한 표준이 제정되기에 이르렀다. IEEE 1164는 디지털 회로에 대하여 9 가지 값(standard 9-valued logic)을 갖는 데이터 형 "std_logic"을 정의하였고 이는 IEEE 1076 의 "bit" 형을 확장한 것이다. IEEE 1076에는 VHDL의 언어에 대한 표준과 아울러 데이터 타입 및 각종 연산에 대한 표준이 정해져 있다. IEEE 1076에는 디지털 회로의 비트(bit) 형과 정수 및 실수형 문자형 등이 있으며 이중 bit와 정수형이 합성 가능하다. IEEE 1164의 "std_logic"은 bit의 '1'과 '0'이외에 Pull-up, Pull-down에 해당하는 'H' (Weak-High), 'L' (Weak-Low)와 'Z'(high-impedance), 'U'(uninitialize), 'X' (unknown), '-'(Don't care)등을 정의해 놓음으로써 디지털 회로의 합성뿐만 아니라 시스템 인터페이스에 대한 배려를 해두었다.


1-1. 열거형 (Enumeration type )

 

기본적으로 VHDL에서 사용하는 대부분의 자료형은 대부분 열거형 (enumeration type) 이다. IEEE 1076의 stanandard package에 정의되어 있는 열거형의 예를 들면 다음과 같다.

type boolean is (false,true);
type bit is ('0', '1');

IEEE 1164에 std_ulogic은 다음과 같이 열거형으로 정의 되어 있다.

TYPE std_ulogic IS ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

'U'는 초기화 되지 않은 상태(Uninitialized)를 의미하며 'X'는 Unknown으로서 디지털 값의 충돌등과 같은 에러상태를 나타낸다. '0' 과 '1'은 디지털 값에 해당하며 'Z'은 High Impedance, 'W', 'L', 'H'는 각각 Weak Unknown, Weak 0, Weak 1로서 Pull-up혹은 Pull-down된 디지털 값을 나타낸다. 끝으로 '-'은 합성 시 논리 최적화에 Don't care로서 이용된다.

열거형을 이용하면 사용자는 언재든지 자료형의 정의가 가능하다. 또한 열거형으로 정의된 경우 인 코딩(encoding) 방법을 지정할 수 있다. 인 코딩 방법으로는 2진 코드에 의한 방법(binary)과 One-Hot Encoding이 있다. One-Hot encoding 방법은 유한상태 머신(FSM : Finite State Machine)에서 상태를 나타내는 경우에 많이 이용되는 방법이다. 다음과 같은 예를 살펴보자.

type state is (IDLC, RECEIVE, SEND);

예제에서와 같이 열거형 "state"는 3개의 요소를 가지므로 Binary encoding하면 2비트가 필요한 반면 On-Hot encoding하는 경우 각 요소마다 1개의 비트를 할당하여 3비트로 표현된다.

VHDL에서 형 검사(type checking)가 치밀한 이유 중 하나가 위와 같은 열거형을 주로 다루기 때문이라고 할 수 있다. 각종 연산자 혹은 할당(assignment)의 경우 기본적으로 열거형으로 이루어진 서로 다른 두 타입은 비트 폭에서부터 다르기 때문이다. 다음과 같이 bit 형과 std_logic형의 할당문의 경우 예를 살펴보자.

Type bit is ('0', '1');
Type std_logic is ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

와 같이 정의된 두개의 시그널,

Signal A : bit;
Signal B : std_logic;

을 사용한 할당문,

A <= B;

은 하드웨어적인 연결의 의미를 고려해 볼 때 할당문은 성립할 수 없는 것이 당연하다.

1-2 정수형 (Integer Type)

IEEE 1076에 정의된 정수형의 기본적인 비트 폭(bit-width)은 32비트로 되어 있다.

type integer is range -2147483648 to 2147483647;

정수형은 산술연산이 가능하며 2의 보수형태로 이루어진다. 또한 정수형은 합성이 가능하며 범위를 지정하지 않을 경우 32비트가 된다. 따라서 과도한 비트 폭을 갖는 연산기의 합성을 피하려면 정수의 범위를 지정해서 사용하도록 한다. 다음의 예는 4비트 시그널을 선언한 예이다.

Signal count : integer range 0 to 15;


1-3 실수형 (Real, Floating-Point Type)

실수형(real type)은 합성가능하지 않다. 시스템 모델링 이나 아날로그 회로의 모델링 등에 사용될 수 있다. IEEE 1076의 실수형의 정의는 다음과 같다.

type real is range -1.0E308 to 1.0E308;

다음은 실수형으로 아날로그 회로의 한예로서 A/D 변환기를 기술한 예이다.

  function ADC_8b_10v_bipolar ( analog_in : in real ) return byte is
constant max_digital_value : integer := 256;
constant max_analog_value : real := 5.0;
variable digitized_signal : integer;
variable digital_out : byte;
begin

if (analog_in < 0.0) then

digitized_signal := 0;

else

digitized_signal := integer(analog_in * ( real(max_digital_value) / max_analog_value) );

if (digitized_signal > (max_digital_value - 1)) then

digitized_signal := max_digital_value - 1;

end if;

end if;

digital_out := byte(to_std_logic_vector(digitized_signal,8));

return digital_out;

end
 

아날로그 입력 값을 실수형으로 입력 받은후 디지털 변환을 수행한다.

digitized_signal := integer(analog_in * ( real(max_digital_value) / max_analog_value) );

이때 계산된 값은 정수형 데이터이며 이를 디지털 시스템으로 인터페이스 하기 위하여 정수형을 "std_logic"형으로 변환하기위한 함수를 이용한다. 정수로부터 "std_logic_vector"로 형 변환 (type conversion)을 수행하기 위한 함수 "to_std_logic_vector"는 다음과 같다.

  function to_std_logic_vector ( a : integer; width : integer ) return std_logic_vector is
constant y_length : integer := width;
constant a_threshold : integer := 2 ** (width-1);
variable y_ref : integer;
variable y : integer;
variable y_std_logic_vector : std_logic_vector(y_length-1 downto 0);
begin

y := a;

if (a >= 0) then

y_ref := a_threshold;

for i in y_length-1 downto 0 loop

if (y < y_ref) then

y_std_logic_vector(i) := '0';

else

y := y - y_ref;

y_std_logic_vector(i) := '1';

end if;

y_ref := y_ref / 2;

end loop;

else

for i in y_length-1 downto 0 loop

y_std_logic_vector(i) := '0';

end loop;

end if;

return y_std_logic_vector;

end to_std_logic_vector;
 

 A/D변환 값을 반환하기 위하여 "byte" 형을 std_logic 형으로부터 정의하여 사용하였다.

type byte is array (7 downto 0) of std_logic;


1-4. Physical Type

물리량의 단위(unit)와 배수 관계를 정의한 것이며 합성 가능하지 않다. IEEE 1076에는 시간에 대한 정의가 있는데 다음과 같다.

  type time is range -2147483647 to 2147483647
units

fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
ms = 1000 us;
sec = 1000 ms;
min = 60 sec;
hr = 60 min;

end units;
 

위에서 볼 수 있듯이 VHDL의 최소시간 단위는 fs (femto second, 10E-15) 이다.


1-5 배열형 (Array Type)

VHDL에서 배열형을 사용할 수 있다. 일 차원 배열형의 경우 대부분 합성기에서 지원 하지만 2차원 배열을 지원하지 않는 합성기도 많다. 디지털 회로의 기본 데이터 단위는 "bit" 이다. 이를 버스형태로 정의하기 위해서 "bit_vector"형을 사용한다. 즉 버스를 정의하는 것은 "bit"의 일 차원 배열이다. 배열형을 정의 할 때 그 크기를 지정하는 경우가 있고 임의의 배열 크기를 지정할 수도 있다.

type byte is array ( 7 downto 0) of bit;

일 차원 배열로 8-비트 크기의 데이터 타입 "byte" 을 정의한 것이다.

TYPE std_logic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_logic;

"std_logic" 형으로 일 차원 배열형 "std_logic_vector"를 선언한 것이다. 이때 배열의 크기를 제한 시키지 않은 것으로서 시그널을 선언할 때 그 크기를 정하여 사용할 수 있다. 배열형의 선언한 예는 다음과 같다.

Signal byte_a : byte;
Signal count : std_logic_vector( 7 downto 0);

1-6 레코드 형(Record Type)

VHDL에서는 레코드형을 지원한다. 디지털 회로에서의 레코드형 사용 예는 기계어 명령의 비트맵 표현 등에 이용될 수 있다. 다음은 레코드 형의 사용 예이다.

  type month_name is (jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dev);

type date is
record

day : integer range 1 to 31;
month : month_name;
year : integer range 0 to 4000;

end record;

constant my_birthday : date := (21, nov, 1963);

SIGNAL my_birthday : date;


my_birthday.year <= 1963;
my_birthday.month <= nov;
my_birthday.day <= 21; -- 5-bit
-- my_birthday(0) : LSB
-- my_birthday(4) : MSB
 

파생형 (Subtype)과 형 변환(Type Conversion)
VHDL에서의 파생형(subtype)을 정의할 수 있으며 다음의 예는 정수로부터 일정한 크기를 갖는 파생 정수형을 정의한 예이다.

type big_integer is range 0 to 1023;
subtype small_integer is big_integer range 0 to 7;

 

"small_integer"는 "big_integer"의 파생형으로 정의되었다. 이 경우 파생형 "small_integer"의 의미는 10-비트 크기의 "big_integer"의 하위 4-비트를 차지하도록 정렬된다는 의미로서 두 데이터 형의 호환됨을 나타낸다. 다음의 예는 VHDL에서 자료형 검사(type checking)의 엄격함을 보여준다.

type big_integer is range 0 to 1000;
type small_integer is range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= intermediate * 5; -- type mismatch error

위의 예에서 "big_integer"와 "small_integer" 형은 비록 서로 정수형 이긴 하지만 서로 호환 돼지 않는다. 이러한 경우 "small_integer"를 파생형으로 정의 함으로서 형 불일치(type mismatch) 에러를 해결할 수 있다.

type big_integer is range 0 to 1000;
subtype small_integer is big_integer range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= intermediate * 5;

또 다른 방법으로 type casting을 이용할 수 있는데 이 경우는 기본적으로 두 형의 기본형이 같아야 한다.

type big_integer is range 0 to 1000;
type small_integer is big_integer range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= big_integer(intermediate * 5);

만일 정수형과 "std_logic_vector"형으로 변환하기 위해서는 두 데이터 타이의 기본형이 전혀 다르므로 형 변환 함수(type conversion function)를 사용하여야 한다. 형 변환 함수는 사용자가 임의로 만들어 쓸 수 있으나 IEEE 1164의 산술 패키지(numeric_std, numeric_bit)에는 정수와 "std_logic_vector", "bit" 사이의 형 변환을 위한 함수를 다수 가지고 있으므로 가급적 이를 이용하도록 권장한다. IEEE 1164 라이브러리의 산술연산과 형 변환 함수는 합성 가능한 산술 연산을 다루면서 자세히 살펴 보기로 한다. 다음의 예는 산술연산과 형 변환 함수의 이용에 대한 것이다.

  package my_type is

type big_integer is range 0 to 1023;
subtype small_integer is big_integer range 0 to 7;

end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.my_type.all;

entity subtype_test is

port (

a : in small_integer;
b : in small_integer;
c : out std_logic_vector(9 downto 0) );

end subtype_test;

architecture behave of subtype_test is
signal t_int : big_integer;
begin

t_int <= a + b;
c <= std_logic_vector(to_unsigned(natural(t_int), 10));

end;
 

위의 예는 정수 입력을 받아서 연산을 수행한 후 이를 10 비트 크기의 "std_logic_vector" 로 출력하는 경우이다. 입력된 2개의 정수형("small_integer") a,b를 계산하여 "big_integer"로 할당한다.

t_int <= a + b;

사용자 정의형 "big_integer"인 "t_int"로 부터 std_logic_vector"로 변환하는 과정은 약간 복잡하게 보이지만 이러한 변환과정이 시스템 설계와 서로 다른 모듈사이의 인터페이스 할 때 자주 직면하게 되는 문제이므로 잘 이해해둘 필요가 있다.

c <= std_logic_vector(to_unsigned(natural(t_int), 10));

Numeric_std package에 정수-unsigned 변환 함수가 to_unsigned()로 제공되고 있다. 이 함수의 argument가 natural이므로 사용자 정의형으로부터 정수형(natural)으로 type-casting 한다. Unsigned 형으로 변환할 것이므로 integer가 아닌 natural로 type-casting 한 것이다. 정수형을 std_logic_vector로 직접 변환하는 함수를 가지고 있지 않다. 따라서 to_unsigned() 함수를 사용하여 정수를 10비트 unsigned로 변환 한후 다시 type-casting 하여 "std_logic_vector"인 출력 포트에 연결한 것이다. unsigned는 IEEE 1164의 numeric_std에 다음과 같이 정의 되어 있으므로 type-casting이 가능하다.

type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;

이 변환 과정을 보면 알 수 있듯이 같은 기본형으로부터 파생된 자료형은 type-casting 할 수 있지만 기본형이 다른 경우 형 변환 함수를 써야 한다. 그러나 "t_int <= a + b;" 에서와 같이 기본형이 같은 파생형(subtype)의 경우에는 변환을 수행할 필요가 없다. 위의 예를 합성한 결과는 그림 4와 같다. 0~7까지의 범위를 갖는 두개의 "small-integer"형 입력이 4비트로 연산기로 합성된 후 10비트 출력의 하위 4비트로 출력 되는 것을 볼 수 있다.


                 VHDL의 출현 배경 및 변화 과정

  미국 정부의 VHSIC Program의 주요 목적은 설계, 공정 및 제조 기술 분야에 있어서 미국의 기술 수준을 향상시키는 데 있었다. 또한 미국 정부는 이 Program의 일부로써 VHDL의 개발 노력을 지원하고 있었다.  그  지원 목적은 VHDL의 개발로 좀더 빠른 생산과 회사들간의 연락 기능 강화 및 개발 과정을 능률적으로 처리함으로써 비용 절감 효과를 제공하는 것이었다. 이러한 목적들을 효과적으로 달성할 수 있는 방법을 논의하기 위하여 메사추세츠의 Woods Hole에서 개최된 학술 대회를 시발점으로 1981년부터 VHDL이 개발되기 시작하였다. Technology independent(기술 독립적)하며 표준 하드웨어 기술 언어의 개발을 목표로 한  Woods Hole 학술 대회에서 정부의 공식적인 제안 요구서를 위한 초안이 제출되었으며, 이것은 전자 공학 분야에 종사하는 전문가들에 의해서 검토되는 과정을 거쳐 1983년 초에 수정, 확정되었다. 1980년대 중반 이후부터 VHDL이 문서용이 아닌 Simulation용으로 검증되어져야 한다는 여론이 강해지면서 몇몇 VHDL Simulator가 등장하였으나 업체간에 표준화가 이루어지지 않은 관계로 호환성에 문제가 있었다. 이러한 문제를 해결하고 늘어가는 VHDL관련 CAD Tool 회사간의 표준 및 호환성을 위하여 IEEE에서 1987년에 IEEE-1076이라는 표준을 만들어 공포하였다.  
  이 시점에서  Synthesis(회로합성)는 아직 등장하지 않았으며  VHDL은 Simulation용으로 사용되었다.  1990년대에 들어서면서 VHDL 관련 Software 회사가 많이 등장하고 simulation뿐만 아니라 Synthesis의 기능을 갖춘 CAD Tool이 등장하면서 진정한 VHDL의
표준화가 요구되었고 1991년 IEEE-1164이 발표되면서 업체에서 공통으로 사용할 수 있는 VHDL이 탄생하였다.


 ASIC 이란


 많은 사람들이 알고 있는 말 중에 하나인 ASIC이란  Application Specific IC의 약자로 우리말로 옮기게 되면 특정용도 주문형 반도체이다.  이 ASIC이란 광범위하게는 특정용도 목적으로 사용되는 모든  반도체를 가리키기도 하지만 좁게는 특히 Gate Array를 가리키는 말이다.  우리가 흔히  ASIC이라 부르며 알고 있는 상식은 Gate Array, Embedded Array, Standard Cell (또는 Cell Based IC)세 종류를 가리키는 말로 알고 있다.   ASIC  - Programmable IC Type : PLA, SPLD, CPLD, FPGA    

   - Memory IC Type: MICOM, ASIC Memory, FIFO
   - Logic Based IC Type: Gate Array, Embedded Array,
                                Standard Cell, Full-Custom IC.

 하지만 ASIC이란 반도체 회사에 제품의뢰를 하는 Gate Array 종류만을 가리키는 것이 아닌 특정 용도나 주문형 IC모두를 다 포함하고 있다.  위에서 보는 바와 같이 ASIC의 두 가지 동류로서의 Full Custom(완전 설계 방식)과 Semi Custom(반주문형 설계 방식)이라는
말은 일본에서 인위적으로 만들어 낸 것이다.   물론 ASIC에 대하여 정확하게 정의된 것이 없는 관계로 어쩌면 Gate Array 종류를 진짜
ASIC으로 부는 것도 옳다고 할 수도 있다. 어쨌거나 일반적으로 반도체 설계를 할 수 있는 방식은 일반인들이 ASIC이라 부르고 있는 Logic Based IC Type형태의 Gate Array와 Standard Cell, 그리고 Programmable IC Type형태의 EPLD, FPGA가 대표적이다.


 FPGA


 FPGA란 Field Programmable Gate Array의 준말로 Array Based와 Row Based 두 가지 방법이 있으며 구조는 Gate Array와 매우 흡사하지만  Program에 의해 내부 회로 배선이 연결되는 형식을 취하고 있다. FPGA는 Logic Cell 위주의 설계 방식이기 때문에  SPLD Block 내부의 배선이 외부와 직접 연결될 수 있도록 고안되어 있어 일반 Gate Array와 매우 비슷하며 Timing Simulation이 반드시 필요하다.  다른 Programmable Device에 비해 속도가 월등히 뛰어나고 집적도가 좋으며 부품 단가도 훨씬 저렴하지만 이 종류는 단 한번밖에 구울 수 없기 때문이 주로 연구 개발용보다는 제품 생산용으로 많이 사용된다. FPGA는 대개 2,000-20,000 Gates 급의 회로에 적당하며 JEDEC을 이용하여 굽도록 되어 있는 일반  PLD 종류에 비해  Programming 하는  File이 제품을 만든 회사의 고유  Programming Netlist인 ADL, QDF, XNF 등을 사용하도록 되어있다. Array Based 형식의  FPGA는 SPLD Block들을 2차원 배열 형식으로 늘어뜨린 다음 중간에 Interconnect Channel이 서로 교차하며 연결될 수 있도록 되어 있다. 이  Array Based형식의 FPGA는
그림에서 보는 바와 같이 두가지 종류가 있다.  대체로 MUX와 AND로 이루어진 Combinational Logic과 하나의 Flip-Flop으로 구성되어 있는 형식의 SPLD Block구조가 일반적이며  MUX들을 일렬로 배열한 다음 중간 중간에 Flip-Flip을 끼워 넣는 형식의 Logic Array형 제품도 있다. 일반적인 내부구조는 Xilinx의  CLB, Cypress와 QuickLogic의 Logic Cell 등이 대표적인 이 형식을 취하고 있으며 Logic Array형의 내부 구조는 Altra의 LAB가 이러한 형식을 취하고 있다. 반면 Row Based FPGA의 내부 구조는  MUX 구조형식의  Combinational Logic이 각 행마다 나열되어 있고 중간 중간에  Flip-Flop이 끼워져 있는 형식을 취하고 있다. Array Based FPGA의  SPLD Block은 Logic Array 구조 형식이 가로가 아닌 세로로 된것과 비슷하다.  다만  Array Based FPGA와의 다른 점이라면  Logic Cell끼리 연결할 수 있는  Interconnect가 나열된 Cell의 아래나 위에만 위치하여야 된다는 것이다.  Actel이 이 Row Based FPGA의 대표적인 구조이다. "
                       
                           

1. Overrall Structure

--  Context Clauses

        --  Library Clause

        --  Use Clause

--      Library Units

        --  Package Declaration (optional)

        --  Package Body (optional)

        --  Entity Declaration

        --  Architecture Body


2. Full Design : Counter

-- MAX+plus II VHDL Template
-- Clearable loadable enablable counter

ENTITY __entity_name IS
        PORT
        (
                __data_input_name               : IN    INTEGER RANGE 0 TO __count_value;
                __clk_input_name                : IN    STD_LOGIC;
                __clrn_input_name               : IN    STD_LOGIC;
                __ena_input_name                : IN    STD_LOGIC;
                __ld_input_name         : IN    STD_LOGIC;
                __count_output_name     : OUT   INTEGER RANGE 0 TO __count_value
        );
END __entity_name;

ARCHITECTURE a OF __entity_name IS
        SIGNAL  __count_signal_name     : INTEGER RANGE 0 TO __count_value;
BEGIN
        PROCESS (__clk_input_name, __clrn_input_name)
        BEGIN
                IF __clrn_input_name = '0' THEN
                        __count_signal_name <= 0;
                ELSIF (__clk_input_name'EVENT AND __clk_input_name = '1') THEN
                        IF __ld_input_name = '1' THEN
                                __count_signal_name <= __data_input_name;
                        ELSE
                                IF __ena_input_name = '1' THEN
                                        ount_signal_name <= __count_signal_name + 1;
                                ELSE
                                        __count_signal_name <= __count_signal_name;
                       

        END IF;
                        END IF;
                END IF;
        END PROCESS;
        __count_output_name <= __count_signal_name;
END a;



3. Full Design : Flipflop

-- MAX+plus II VHDL Template
-- Clearable flipflop with enable

LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY __entity_name IS
        PORT
        (
                __d_input_name          : IN    STD_LOGIC;
                __clk_input_name        : IN    STD_LOGIC;
                __clrn_input_name       : IN    STD_LOGIC;
                __ena_input_name        : IN    STD_LOGIC;
                __q_output_name         : OUT   STD_LOGIC
        );
END __entity_name;

ARCHITECTURE a OF __entity_name IS
        SIGNAL  __q_signal_name : STD_LOGIC;
BEGIN
        PROCESS (__clk_input_name, __clrn_input_name)
        BEGIN
                IF __clrn_input_name = '0' THEN
                        __q_signal_name <= '0';
                ELSIF (__clk_input_name'EVENT AND __clk_input_name = '1') THEN
                        IF __ena_input_name = '1' THEN
                                __q_signal_name <= __d_input_name;
                        ELSE
                                __q_signal_name <= __q_signal_name;
                        END IF;
                END IF;
        END PROCESS;
        __q_output_name <= __q_signal_name;
END a;





4. Full Design :  Tri-State Buffer

-- MAX+plus II VHDL Template
-- Tri-State Buffer

LIBRARY ieee;
USE ieee.std_logic_1164.all;

ENTITY __entity_name IS
        PORT
        (
                __oe_input_name                 : IN    STD_LOGIC;
                __data_input_name               : IN    STD_LOGIC;
                __tri_output_name               : OUT   STD_LOGIC
        );
END __entity_name;

ARCHITECTURE a OF __entity_name IS
BEGIN
        PROCESS (__oe_input_name, __data_input_name)
        BEGIN
                IF __oe_input_name = '0' THEN
                        __tri_output_name <= 'Z';
                ELSE
                        __tri_output_name <= __data_input_name;
                END IF;
        END PROCESS;
END a;


5. Architecture Body

ARCHITECTURE a OF __entity_name IS
        SIGNAL __signal_name : STD_LOGIC;
        SIGNAL __signal_name : STD_LOGIC;
BEGIN
        --  Process Statement

        --  Concurrent Procedure Call

        --  Concurrent Signal Assignment

        --  Conditional Signal Assignment

        --  Selected Signal Assignment

        --  Component Instantiation Statement

        --  Generate Statement

END a;


6. Case Statement

CASE __expression IS
        WHEN __constant_value =>
            __statement;
            __statement;
        WHEN __constant_value =>
            __statement;
            __statement;
        WHEN OTHERS =>
            __statement;
            __statement;
END CASE;


7. Component Declaration

COMPONENT __component_name
        PORT(
                __input_name, __input_name              : IN    STD_LOGIC;
                __bidir_name, __bidir_name              : INOUT STD_LOGIC;
                __output_name, __output_name    : OUT   STD_LOGIC);
END COMPONENT;


8. Component Instantiation Statement

__instance_name: __component_name
        PORT MAP (      __formal_parameter => __actual_parameter,
                                __formal_parameter => __actual_parameter);


9. Concurrent Procedure Call

__label: __procedure_name(__actual_parameter, __actual_parameter);


10. Concurrent Signal Assignment Statement

__signal <= __expression;


11. Conditional Signal Assignment

__label:
__signal <= __expression WHEN __boolean_expression ELSE
                        __expression WHEN __boolean_expression ELSE
                        __expression;


12. Constant Declaration

CONSTANT __constant_name : __type_name := __constant_value;


13. Entity Declaration

ENTITY __entity_name IS
        PORT(
            __input_name, __input_name             :  IN           STD_LOGIC;
                __input_vector_name         :  IN   STD_LOGIC_VECTOR(__high downto __low);
                __bidir_name, __bidir_name          :  INOUT    STD_LOGIC;
                __output_name, __output_name   :  OUT   STD_LOGIC);
END __entity_name;


14. For Statement

__loop_label:
FOR __index_variable IN __range LOOP
    __statement;
    __statement;
END LOOP __loop_label;


15. Generate Statment ( For Statement)

__generate_label:
FOR __index_variable IN __range GENERATE
    __statement;
    __statement;
END GENERATE;


16. Generate Statment ( If Statement)

__generate_label:
IF __expression GENERATE
    __statement;
    __statement;
END GENERATE;



17. If Statement

IF __expression THEN
    __statement;
    __statement;
ELSIF __expression THEN
    __statement;
    __statement;
ELSE
    __statement;
    __statement;
END IF;



18. Library Clause

LIBRARY __library_name;



19. Package Declaration

PACKAGE __package_name IS

        --  Type Declaration

        --  Subtype Declaration

        --  Constant Declaration

        --  Signal Declaration

        --  Component Declaration
END __package_name;




20. Procedure Call Statement

__procedure_name(__actual_parameter, __actual_parameter);


21. Process (Combinatorial Logic)  

__process_label:
PROCESS (__signal_name, __signal_name, __signal_name)
        VARIABLE __variable_name : STD_LOGIC;
        VARIABLE __variable_name : STD_LOGIC;
BEGIN
        --  Signal Assignment Statement

        --  Variable Assignment Statement

        --  Procedure Call Statement

        --  If Statement

        --  Case Statement

        --  Loop Statement

END PROCESS __process_label;


22. Process (Sequential Logic)

__process_label:
PROCESS
        VARIABLE __variable_name : STD_LOGIC;
        VARIABLE __variable_name : STD_LOGIC;
BEGIN
        WAIT UNTIL __clk_signal = '1';
        --  Signal Assignment Statement
 
        --  Variable Assignment Statement

        --  Procedure Call Statement

        --  If Statement

        --  Case Statement

        --  Loop Statement

END PROCESS __process_label;



23. Selected Signal Assignment Statement

__label:
WITH __expression SELECT
        __signal <= __expression WHEN __constant_value,
                                __expression WHEN __constant_value,
                                __expression WHEN __constant_value,
                                __expression WHEN __constant_value;


24. Signal Declaration

SIGNAL __signal_name : __type_name;


25. Signal Assignment Statement

__signal_name <= __expression;

26. State Machine with Asynch. Reset

ENTITY __machine_name IS
        PORT(
                clk                             : IN    STD_LOGIC;
                reset                                   : IN    STD_LOGIC;
                __input_name, __input_name              : IN    STD_LOGIC;
                __output_name, __output_name    : OUT   STD_LOGIC);
END __machine_name;

ARCHITECTURE a OF __machine_name IS
        TYPE STATE_TYPE IS (__state_name, __state_name, __state_name);
        SIGNAL state: STATE_TYPE;
BEGIN
        PROCESS (clk)
        BEGIN
                IF reset = '1' THEN
                        state <= _state_name;
                ELSIF clk'EVENT AND clk = '1' THEN
                        CASE state IS
                                WHEN __state_name =>
                                        IF __condition THEN
                                                state <= __state_name;
                                        END IF;
                                WHEN __state_name =>
                                        IF __condition THEN
                                                state <= __state_name;
               

                        END IF;
                                WHEN __state_name =>
                                        IF __condition THEN
                                                state <= __state_name;
                                        END IF;
                        END CASE;
                END IF;
        END PROCESS;

        WITH state SELECT
                __output_name   <=      __output_value  WHEN    __state_name,
                                        __output_value  WHEN    __state_name,
                                        __output_value  WHEN    __state_name;
END a;



27. State Machine without Asynch. Reset

ENTITY __machine_name IS
        PORT(
                clk                             : IN    STD_LOGIC;
                __input_name, __input_name              : IN    STD_LOGIC;
                __output_name, __output_name    : OUT   STD_LOGIC);
END __machine_name;

ARCHITECTURE a OF __machine_name IS
        TYPE STATE_TYPE IS (__state_name, __state_name, __state_name);
        SIGNAL state: STATE_TYPE;
BEGIN
        PROCESS (clk)
        BEGIN
                IF clk'EVENT AND clk = '1' THEN
                        CASE state IS
                                WHEN __state_name =>
                                        IF __condition THEN
                                                state <= __state_name;
                                        END IF;
                                WHEN __state_name =>
                                        IF __condition THEN
                                                state <= __state_name;
                                        END IF;
                                WHEN __state_name =>

                                        IF __condition THEN
                                                state <= __state_name;
                                        END IF;
                        END CASE;
                END IF;
        END PROCESS;

        WITH state SELECT
                __output_name   <=      __output_value  WHEN    __state_name,
                                        __output_value  WHEN    __state_name,  
                                        __output_value  WHEN    __state_name;
END a;


28. Subtype

SUBTYPE __subtype_name IS __type_name RANGE __low_value TO __high_value;
SUBTYPE __array_subtype_name IS __array_type_name(__high_index DOWNTO __low_index);
29. Type

TYPE __enumerated_type_name IS (__name, __name, __name);
TYPE __range_type_name IS RANGE __integer TO __integer;
TYPE __array_type_name IS ARRAY (INTEGER RANGE <>) OF __type_name;
TYPE __array_type_name IS ARRAY (__integer DOWNTO __integer) OF __type_name;


30. Use Clause

USE __library_name.__package_name.ALL;


31. Wait Statement

WAIT UNTIL __clk_name = '1';


32. Variable Declaration Statement

VARIABLE __variable_name : __type_name;


33. Variable Assignment Statement

__variable_name := __expression;




34. While Statement

__loop_label:
WHILE __boolean_expression LOOP
    __statement;
    __statement;
END LOOP __loop_label;


 위에 있는 것들은 VHDL에 사용할 문법들입니다. 조금 많아보이죠. 이것은 Altera의 문법들입니다. VHDL이 하드웨어 표준 언어이지만 각 회사들마다 조금씩 문법의 차이는 있습니다. 그것은 숙지하시고 문법은 맞는데 컴파일이 되지 않는다고 불평하지 마세요. 실예로 Lodecap에서 모든 컴파일과 시뮬레이션을 마친 상태에서 그 소스를 Altera에서 실행한 적이 있습니다. 그런데 상태 이름이Next였습니다. 그런데 MaxPlusⅡ에서는 Next가 Reserved word였습니다. 그래서 몇 일을 고생한 적이 있습니다. 자기가 사용하는 툴에 대해서는 어느 정도의 지식이 있어야 합니다. 툴에 대한 설명은 제가 할 수 있는 것이 못됩니다.그러니 각 회사 사이트에 접속하면 Manual을 구할 수 있습니다. 그리고 공개용 버전도 어느 정도 구할 수 있을 것입니다. 직접 접속해 보시는 것도 좋은 방법입니다. 위에 있는 문법들을 한 번 잘살펴 보시고 다음 시간부터 사용되는 문법들과 잘 적용해 보시기를 바랍니다.


ASIC 용어 요약


 
 1 ASIC : Application Specific Integrated Circuit
  주문형반도체
 시스템 업체가 자기 시스템의 특정회로 부분을 하나의 반도체로 집적시켜 개발하여, 반도체 제조 업자에게 주문 제조한 반도체 수요 업체가 주문 제조한 특정회로용으로만 사용되기 때문에 기존의 범용 반도체(반도체 업체가 생산하는 표준화된 반도체:Standard IC
)와 상대적인 개념으로 특정 용도 IC(ASIC)라 통칭함.

2 ATVG : Automatic Test Vector Generation
 일반적으로 결점 적용 범위(Fault Simulation)의 레벨을 증가시키고, 기능을 검사하기 위한 테스트 패턴 (Test Pattern)들을 증가시키기 위해 이용된다.

3 Back Annotation
 레이아웃(Layout)후에 R.C값을 추출하는 작업

4 Behavioral Description
 알고리즘 또는 수학적인 방정식의 항으로부터 소자 또는 기능을 모델화하는것.

5 Bottom-up Design
 계층적 설계방법 (Hierarchical Design)을 이용하여 트랜지스터나 게이트같은 기본적인 소자로부터 셀(cell),모듈(module)등 중간레벨의 구조를 만들고 정의하여, 높은 레벨의 시스템 구조를 꾸며 나가는 설계방식(Top-Down Design과 상대적 개념)

2.6 Cell
 특정한 전기적 기능을 수행하기 위해 이미 정의된 회로 소자의 레이아웃이나 파일

7. Cell Library
 특성을 가진 셀들의 모임으로 일반적 ASIC 벤더(Vendor)회사에 특정된다.

8. CIF : Caltech Intermediate Format
 표준형 기계가 읽을 수 있도록 마스크 레벨인 도형적 레이아웃을 표현하기 위한 형식. 레이아웃의 표준으로 GDSII도 있다.

9. Core
 I/O 패드링 (Pad Ring)을 제외한 영역 또는 ASIC의 능동 영역

10. Critical Path
 회로망에서 가장 긴 경로. 임계 경로 전달 지연은 소자의 최대 클럭 주파수를 제한한다.

11. Design Rule
 도형적 레이아웃을 이루는 다각형들에 대한 최소의 너비와 간격에 대한 요구 사항들을 정의한것. 테크놀러지별로 Metal1,Metal2, Poly등의 값들을 정의.

12. DFT : Design For Testability
 테스트 용이화 설계(DFT)는 회로 설계단계시, 논리회로의 테스트를 손쉽게 할 테스트 패턴 생성을 고려하여 설계하는 것이다.

13. DIE
 칩이라고도 부름. 다이는 회로나 소자의 어레이를 포함하는 웨이퍼를 스크라이브 선 (Scribe Line)을 따라 잘라서 얻은 하나의 짖적된 회로이다.

14. DRC : Design Rule Checker
 설계 아트워크가 어떤 특정 공정에서 아무런 문제없이 제작될 수 있는가를 검토하기 위하여, 완전한 레이아웃을 공간적인 면에서 공정 설계 규칙에 맞는지 검토하는 프로그램.

15. EDA : Electronic Design Automatic
 컴퓨터를 이용한 회로 설계 자동화 엔지니어링 툴들에 상응함.

16. EDIF : Electronic Data Interchange Format
 어떤 설계 툴에서 만들어진 데이터를 다른 설계 툴로 전송하기 위한 표준화된 중간 서식.

17. ERC : Electronic Rule Checker
 과다한 팬아웃, 개방(Open), 단락(Short)과 같은 전기법칙의 위반들에 대하여 회로 레이아웃을 검토하는 프로그램.

18. Fault
 어떤 회로의 개방또는 단락으로 인하여 기능적 고장을 초래하는 제조상의 결함.

19. Floating Node
 연결되지 않은채 남겨진 게이트의 입력 또는 출력으로 놓아두면 기능적 고장을 유발하게 된다. 부동단자는 대개 논리적으로 High 상태로 부동한다. ERC 프로그램들이 이런 레이아웃 에러를 검색하는데, 이것들은 공정중에 불안전한 접촉에 의해 발생하기도 한다.

20. Floor Planning
 최적의 레이아읏을 얻기 위하여 칩 레이아웃 영역내의 기능 블럭들을 배치하고, 그 기능 블럭들 사이를 연결하여 할당하는 과정.

21. Foundry
 ASIC 설계 업체와 고객들이 자신들이 갖고있는 공정에 적합한 기능 블럭들을 사용, 완성된 설계를 제조하기 위하여 이용할 수 있는 반도체 제조 설비

22. Gate
 두개 이상의 입력들과 하나의 출력을 가진 회로로, 출력은 입력 신호의 논리함수로 표시된다. 기본적인 논리 게이트 형태로는 AND, OR, NAND, NOR와 같은
불린함수(Boolean Function)들이 있다.

23. GDSII
 마스크를 만들기 위한 레이아웃을 생성시키기 위하여 사용되는 설계 데이타 형식의 하나로 다른 형식으로는 CIF가 있다.

24. Hierarchical Design
 하나의 모듈을 여러 종속 모듈들로 나누어 설계하는 방식으로 ,하나의 논리를 구조적으로 표기하는 방법. 예를 들면 하나의 마이크로프로세서 블럭은 게이트 블럭드로 구성된 플립플롭 블럭을 포함하고 이 블럭들로 구성된 하나의 프로그램 카운터 블럭을 포함하고 있다.

25. Load
 구동 소자의 출력에 존재하는 저항이나 커패시턴스.

26. Macro Cell / Hard Macro
 코아 기능이라고도 하는데 , 매크로는 본래 표준형 카탈로그 부품으로 제공되는 어떤 기능을 수행하는 복잡한 ASIC 셀이다. 하드 매크로로 불리기도 한다. (레이아웃이 설계 규칙에 맞게 고정되어 있기 때문)

27. Maintenance
 소프트웨어 회사의 툴에 대해 기술적 지원,오류 정정 소프트웨어 개선, 서비스 등을 제공받기 위해 , 사용자가 소프트웨어 회사에 지불하는 비용.

28. MPW : Multi Project Wafer
 여러 다른 설계자에 의해 설계된 여러개의 다른 프로젝트들을 한 웨이퍼 상에 제조함으로써 NRE비용을 여러 설계자들에게 분담시키는 방법.

29. Netlist
 임의의 설계 구성 셀들과 이들의 연결 상태에 대한 정보 나열.

30. Net Comparison or Netcompare
 스키메틱 캡쳐에서 얻어진 네트리스트와 레이아웃의 네트리스트가 같은 기능과 연결성을 갖는지를 비교 검토하는 것.

31. Node
 회로 요소 또는 한 회로망의 임의 가지의 단자.

32. NRE : Non Recurring Engineering
 ASIC 시제품 제작을 위한 개발 노력 행위와 그에 연관된 비용에 관한것.

33. Pad
 I/O 회로를 패키지 또는 기판에 연결하기 위해 사용되는 칩 가장자리에 위치한 금속 영역.

34. P & R
 레이아웃의 배치및 배선

35. PGA : Pin Grid Array
 어떤 그리드에 나열된 패키지의 리드(Lead)를 패키지 몸체 밑의 아래방향으로 나오게 하는 Through Hole 장착 패키지 기술.

36. Physical Design
 트랜지스터,셀,블럭과 그것들의 배치와 배선을 포함하는 기하학적 요소들의 항으로 집적회로 레이아웃을 도형적으로 구현하는것.

37. Placement
 칩 레이아웃내의 세 또는 블럭들을 물리적으로 위치시키는것.

38. Primitive
 게이트와 같은 낮은 레벨의 기능.

39. Prototype
 어던 특정한 응용에 대해 첫번째 설계 또는 첫번째 동작 모델의 형태. 정확성과 기능을 평가하기 위한 시제품 혹은 시작품.

41. Routing
 셀들 사이의 연결 통로.

42. Scribe Line
 인접한 다이의 위치를 분리시키는 웨이퍼상의 영역. 스크라이브 영역선은 각각의 칩을 산출하기 위해 줄쳐 있거나 잘려지는 선  

43. Sea of Gate
 배선용 채널을 따로 가지지 않으며 트랜지스터가 연속적으로 배열된 게이트어레이 구조의 한 형태.

44. Silicon Compiler
 고수준 설계 표기가 주어졌을때 , 도형적 설계와 시뮬레이션을 포함하는 모든 필요한 설계 관점들을 컴파일하거나 종합하는 설계 툴.

45. Simulation or Test Vector
 회로의 입력에 적용되어 연산되었을때 , 도형적 설계와 시뮬레이션을 포함하는 모든 필요한 설계 관점들을 컴파일하거나 종합하는 설계 툴.

46. Standard Cell
 고정된 물리적,전기적 특성들에 의해 특정지어지는 게이트 또는 래치오같은 기본적인 기능적인 요소.

47. Symbol
 셀의 경계 박스와 I/O 포트를 그림으로 나타낸것.

48. Synthesis
 상태천이기계, 진리표, 진리도는 불린 방정식등의 고수준 설계 서술을 특정한 게이트 레벨
논리 구현으로 변환하는 것.

49. VHDL : VHSIC Hardware Description Language
 언어적 사양에 따라 기능적 등가 칩을 생산할 수 있는 많은 ASIC회사들에 의해 이상적으로 선정된 사양을 만드는데 사용되는 기술도립적인 표준형 설계 표기 언어. (IEEE
1076)

50. Yield
 웨이퍼 상의 올바로 동작하는 칩 수와 전체 칩수의 비율.


 < VHDL 문법>


1. if 문

if-else 구문은 다음과 같은 형태를 합니다.
if ( 조건 )  then
    수행식;
else
    수행식;
end if;

if-else 구문은 순차적으로 진행되므로 반드시 Process 문안에서 실행됩니다. 중요한 사항
입니다. 언어의 형태와 비슷하죠. 괄호는 필요한 사항은 아닙니다만 자기가 보기가 편하기
때문에 저로 주로 괄호를 이용합니다.

Enable 신호가 있으면 0000으로 Set되고 Enable 신호가 영이면 Mux의 기능을 수행합니다.
라이브러리에서는 Symbol로 구현되어 있으므로 반듯이 그 형태를 따라가야 하지만 VHDL
에서는 자기 자신에 맞는 코딩을 할 수 있다는 것은 굉장히 유용한 사실입니다.

다음은 Decoder와 Encoder에 대해서 알아보기로 하겠습니다. 기능은 모르고 있다면 디지털
논리 회로를 참조하기여 알아보시기를 바랍니다.

ex) 2-to-4 decoder
library ieee;
use ieee.std_logic_1164.all;
entity decoder is
port ( a : in std_logic_vector(1 downto 0);
      d : out std_logic_vector(3 downto 0));
end decoder;
architecture decoder1 of decoder is
begin
   process
   begin
      case a is
         when "00" => d <= "0001";
         when "01" => d <= "0010";
         when "10" => d <= "0100";
         when others => d <= "1000";
      end case;
   end process;
end decoder1;


ex) 4-to-2 decoder
library ieee;
use ieee.std_logic_1164.all;

entity encoder is
port ( a : in std_logic_vector(3 downto 0);
       z : out std_logic_vector(1 downto 0));
end encoder;

architecture encoder1 of encoder is
begin
   z <= "00" when a(0) = '1'
    else "01" when a(1) = '1'
    else "10" when a(2) = '1'
    else "11";
end encoder1;

여기서 a(0)라고 하는 것은 입력 a가 4비트이므로, 4비트의 LSB(최하위 비트)를 말하는 것입니다. a(3)이라고 한다면 MSB(최상위 비트)를 말하는 것입니다. 이 구문은 앞에서 다른 적이 있는데 기억하고 있습니까? Concurrent 문에서 사용되는 구문이라고 앞에서 설명 드렸지요. 논리 회로의 기초적인 지식이 없으면 아무리 제가 쉽게 설명한다고 해도 따라오기가 힘들 것입니다. 부족하다고 느끼시면 다시 시작하십시오. 지금은 늦은 때가 아닙니다. 앞으로도 너무 많은 것이 남아 있습니다. 제가 언제 이것을 다할 지는 모르겠지만 하는데 까
지는 해 봅시다. 자신감을 가지세요. 오늘은 여기까지 합시다.


ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity inc is
port ( pc_in  : in std_logic_vector(4 downto 0);
       pc_out : out std_logic_vector(4 downto 0));
end inc;

architecture rtl of inc is
begin
  pc_out <= pc_in + 1;
end rtl;

여기에서는 결과 파형을 조금 살펴봅시다.
입력이 0, 1, 3, 1f, 3으로 되어 있습니다. 파형을 관찰할 때 주의 할 점은 모든 구간의 영역을 다 살펴보아야 합니다. 5비트 입력이므로 0h에서 1fh까지 모두 살펴보아야 하지만 사실 그러기는 어렵죠. 그래도 시작점과 끝부분 그리고 입력이 바뀔 수 있는 부분은 모두 체크해
야 합니다. 그리고 이 그림에서 알 수 있는데 delay라는 것을 느낄 수가 있죠. 그리고 왜 입력이 4비트가 이니라 5비트인가? 이 점에 대해서 살펴보아야 할 것입니다. Intel의 기본은 8비트입니다. 그러나 이 8비트는 4비트 두 개가 모여서 8비트를 이루는 것입니다. 4비트 연산을 위해서는 5비트의 공간이 필요합니다. 여기에서 보면 11111이 입력입니다. 출력은 00000으로 나와 있지만 값은 원래 값은 100000이 될 것입니다. 그러면 왜 출력을 6비트로 정의하지 않았느냐 하는 질문을 할 수 있을 것입니다. 그러나 상태 Flag에서 이 값을 체크해 carry로 그 값을 보낼 것입니다. 지금은 간단하게 5비트 입력, 5비트 출력 이렇게 되어 있지만, 다음에 살펴볼 ALU에서 입력이 4비트 출력이 4비트인 회로를 설계할 것입니다. 그 때는 내부 Siganl이라는 것을 이용하게 될 것입니다. 내부 시그널은 다음, 다음 시간에 배우게 될 것입니다.
 
 
ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity dec is
port ( pc_in  : in std_logic_vector(4 downto 0);
       pc_out : out std_logic_vector(4 downto 0));
end dec;

architecture rtl of dec is
begin
  pc_out <= pc_in - 1;
end rtl;

+, - 기호 하나만 바꾸면 됩니다.
 그리고 결과는 다음과 같습니다.


ex) less than 비교연산 회로
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity less is
port ( a, b  : in std_logic_vector(1 downto 0);
         z   : out std_logic);
end less;

architecture rtl of less is
begin
   process(a, b)
   begin
      if (a < b) then
         z <= '1';
      else
         z <= '0';
      end if;
   end process;        
end rtl;

간단한 비교기를 보았는데 less than만 될까요? 아닐 것 같지요. 그럼 변형을 해봅시다.
  if (a < b) then  -- b가 a보다 크다면
  if (a > b) then  -- a가 b보다 크다면
  if (a <= b) then  -- b가 a보다 크거나 같다면
  if (a >= b) then  -- a가 b보다 크거나 같다면  
  if (a = b) then  -- a와 b가 같다면
  if (a /= b) then  -- a와 b가 같지 않다면
한 줄을 바꿈으로서 6개의 회로를 설계할 수 있습니다.
관계 연산자는 위의 6가지 형태입니다. 유용하게 쓰일 때가 있을 것입니다.


 우리는 제일 먼저 논리 회로에서 and, or, not 게이트를 먼저 배우고 그 다음에 nand, nor 게이트를 배우게 됩니다. and, or의 기능을 가지면 nand와 nor를 설명하기 쉽기 때문입니다. 그러나 실제 회로에서는 그 개념이 아닙니다. 회로의 최적화를 이루기 위해서는 and나 or보다는 nand와 nor 게이트를 가지고 설계하는 것이 가장 최적화 되어 있는 회로입니다. 집적회로의 입장에서 보면, PNP Junction에서 Nmos와 Pmos를 가지고 설계할 수 있는 가장 기본의 형태가 Nand, Nor 게이트입니다.(집적회로까지 설명하면 너무 깊이 들어가야 함으로 간단하게 설명하겠습니다. 궁금한 점이 있는 집적회로를 공부하는 것이 도움이 될 것입니다. Spice Tool을 이용하여 간단한 Layout 설계를 해보시면 알 것입니다.) nand 게이트는 and 게이트에 not 게이트를 붙여서 설계한 회로입니다. 그러니 nand, nor, not가 회로의 기본입니다. nand만 보면 pmos 두 개를 병렬로 연결하고 nmos 두 개를 직렬로 연결한 것이 nand 회로입니다. 참고로 말씀드리면 설계의 기본은 Layout 과정입니다. 배워두시면 도움이 될 것이라 생각은 들지만 시간이 많이 걸린다는 것이 단점입니다. 그럼 Asic 설계에서 가장 기본적으로 알아야 하는 것은 무엇일까요? 아마도 DFF이라고 저는 생각하는 데요. 이제 설계자의 입장에서말씀드리겠습니다. 기본적인 회로의 설계가 끝나면 여러분은 설계자 입장에서 모든 것을 생각하고 설계를 해야 합니다. 하드웨어 디자이너가 되는 것입니다. 기쁘겠죠.


 디자이너가 가장 중요하게 생각해야 하는 Factor가 네가지 있습니다. 아니 더 많을 수도 있지만 기본적인 4가지가 있습니다. 그 중에 한 가지인 Area(yield and pcakageing cost) 문제가 있습니다. 그 문제가 인해 회로 면적이 작게 차지하는 DFF을 이용하는 것입니다. 그래서 VHDL 코딩을 하면 컴파일을 하고 synthesis를 하고 나서 logic으로 구현된 설계도를 보면 메모리 소자를 DFF으로 설계된 것을 확인할 수 있을 것입니다. 지금 살펴 볼 문제는 아니지만 설계시 고려해야 할 4가지요소에 대해서 설명드리면 다음과 같습니다.

 Performance :
    - Delay and cycle-time.
    - Latency.
    - Throughput ( for pipeline application).
 Area ( yield and pcakageing cost).
 Testability
 Power

기분 나쁘게 전부 영어로 적었죠. 다른 사람과 설계에 대해서 이야기를 한다면 영어로 말을 해야죠. 다른 사람이 성능이 어때? 라고 묻지는 않을 것입니다. Performance가 어때라고 묻지. 위의 설명은 여러분이 디자이너가 되면 시작할 것입니다. 그 때를 기대하세요.
그렇게 어려운 용어가 아닌지 대강은 감을 잡을 수 있을 것입니다.지난 시간에 DFF과 latch에 차이에 대해서 알아보셨나요. 부지런한 디자이너는 조사해서 알아있을 것이고, 귀찮은 사람은 그냥 기다리겠죠. 그러나 이런 단순한 이론에서 오는 차이가 크다는 것을 알아야 합니다. 그만큼 회로 설계 시간의 단축을 가져올 수 있습니다.

              ┏━ 조합회로 (Combinational logic)
  디지털 회로 ┃                  ┏━ 동기형 순서회로 (synchronous)
              ┗━ 순서회로       ┃    
               (Sequential logic)   ┗━ 비동기형 순서회로 (Asynchronous)

이해하기 위해서는 조합회로가 무엇이고 순서회로가 무엇인지 알아야 합니다.

   Inputs                  Combinational                   Outputs
                               circuit
                         조합회로의 블럭선도


   Inputs               Combinational                                    Outputs
                          circuit                     Memory
                                                     elements

                          순서논리회로의 블록선도


조합회로는 임의의 시간에서 출력이 이전의 입력에는 관계없이 현재의 입력조합으로부터 직접 결정되는 논리회로를 말합니다. 반면 순서회로는 출력은 외부로부터의 입력이 기억상태를 바꾸게 된다. 즉 순서회로의 입력, 출력 그리고 내부상태의 시간에 따른 순서로서 규정된다.  쉽게 말하면 조합논리의 결과가 출력이 되는 것이 아니라 메모리 요소에 저장되어 있는 변화된 값이 다시 조합회로로궤환되어 결과 값이 출력되는 것이다. 이것은 다시 두 가지로 나누어진다. 클럭펄스가 들어오는 시점에서 입력신호로부터 그 동작을 정의할 수 있는 시스템이 동기형(synchronous) 순서논리회로이다. 비동기형(Asynchronous) 순서회로의 동작은 입력신호가 변화하는 순서에 따라 언제라도 영향을 받을 수 있다. Flip-flop이나 latch는 one-bit 메모리 소자입니다. 클럭이 있는 순서논리회로에 쓰이는 기억소자를 플립플롭이라고 한다.  FF은 edge-triggered memory device라고 합니다. 이 말은 플립플롭의 상태는 입력신호의 순간적인 변화에 따라 바뀌기 때문입니다. 순간적인 입력 변화를 트리거(trigger)라고 합니다. FF을 흔히 레지스터라고도 합니다.  비동기식 순서회로에서는 클럭펄스를 사용하지 않는다. 비동기식 순서회로에서의 기억소자로는 클럭이 없는 플립플롭(latch)이거나 시간지연소자(time-delay element)를 사용한다. 비동기식 순서회로의 설계는 타이밍문제 때문에 설계가 더 어렵습니다.  latch는 level-sensitive memory device입니다. 그 말은 클럭을 사용하지 않기 때문에, 입력이 변화되는 즉시 시스템의 상태가 변화할 수 있게 되어야 한다는 뜻이죠.  클럭이 있는 동기식 시스템의 예를 많이 보았을 것이고, 비동기식 회로에서는 빠른 동작속도가 요구될 때 사용합니다. 예를 들자면 그 자체에 독립적인 클럭을 가진 각각의 장치가 있는 2개의 시스템간의 교신은 비동기식 회로로 이루어져야 합니다. 적절한 시스템 설계를 위해서는 동기식의 일부가 비동기식 특성을 갖는 혼합된 시스템을 설계해야 합니다.  그럼 간단히 정리하죠.동기식 순서회로에서 사용되는 기억소자는 플립플롭이고, 비동기식 순서회로에서 사용되는 기억소자는 래치입니다. 플립플롭은 클럭이 있고, 래치는 클
럭이 없습니다. 좀 어렵게 설명하면 펄스지속시간에 민감한 플립플롭군을 래치라고 하고, 펄스에 전이에 민감한 플립플롭군을 레지스터라고 합니다.  이 부분은 조금 중요한 부분이라 조금 길게 설명이 됐는데 되도록 논리회로의 설명은 자제하는 방향으로 하겠습니다.

 예제는 모두 DFF으로 구현된 예제입니다. 다른 플립플롭으로 구현은 아마 힘들겁니다. 칩 설계를 위해서 그런 것이니 JKFF, RSFF, TFF 등을 구현하고자 한다면 Logic에서 설계된 것을 이용하시면 될 것입니다.


 생각보다 구현은 간단하죠. process 문안에 재미있는 표현이 있군요.
if (clk='1' and clk'event) then
      q <= data;
이 구문은 어떤 의미일까요? 플립플롭에서는 Trigger 방법을 이용한다고 했는데 말이죠.event를 이용해서 상승 에지를 표현한 것입니다. 외우세요.그럼 그 반대로 하강에지를 표현하면 어떻게 될까요? 1을 0으로 바꾸면 되겠죠.
if (clk='0' and clk'event) then
      q <= data;
설명할 것은 이것뿐이네요. 다음 예제로 넘어가지 전에 결과를 비교해 볼까요.

.

래치는 입력에 따라 값이 변한다는 것을 알 수 있을 것입니다.

ex) Rising Edge Flip-Flop with Asynchronous Reset
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, reset : in std_logic;
          q           : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk, reset)
begin
   if (reset='0') then
      q <= '0';
   elsif (clk='1' and clk'event) then
      q <= data;
   end if;
end process;
end behav;

설명할 것이 없네요. 말 그래로입니다. reset을 가진 플립플롭입니다. 다만 reset이 0일 때 플립플롭의 기능을 수행하겠죠. 코딩은 reset이 1일 때라고 의문을 가지는 분은 위의 그림을 유심히 보시면 됩니다. reset에 not가 붙어있죠.


ex) Rising Edge Flip-Flop with Asynchronous Preset
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, preset : in std_logic;
          q           : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk, preset)
begin
   if (preset='0') then
      q <= '0';
   elsif (clk='1' and clk'event) then
      q <= data;
   end if;
end process;
end behav;

C 언어에서 if-else 구문이 있죠. 이것과 사용법은 거의 비슷합니다. 다만 C 언어에서는 else if 라고 쓰지만, VHDL에서는 elsif 라고 씁니다. 다른 언어와 틀리니 주의하세요.다른 언어에서처럼 if 구문 속에 if 문이 계속해서 들어갈 수 있습니다. 나중에 예제에서 보
겠죠.
 


ex) Rising Edge Flip-Flop with Asynchronous Reset and Preset
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, reset, preset : in std_logic;
          q                  : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk, reset, preset)
begin
   if (reset='0') then
      q <= '0';
   elsif (preset='0') then
      q <= '0';
   elsif (clk='1' and clk'event) then
      q <= data;
   end if;
end process;
end behav;

Asynchronous Reset and Preset은 시스템이 불안정할 수 도 있다는 것을 알고 있어야 합니다. Asynchronous Reset and Preset보다는 Synchronous Reset and Preset이 안정적이라는 것을 알고 있어야 합니다. 다시 말하면 Asynchronous Reset은 클럭에 관계없이 Reset이 1이면 모든 것을 리셋시키는 기능을 합니다. 그렇지만 시스템 회로 설계에는 Asynchronous Reset이 더 많이 사용되고 있습니다.  

ex) Rising Edge Flip-Flop with Synchronous Reset
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, reset : in std_logic;
          q          : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk)
begin
   if (clk='1' and clk'event) then
      if (reset='0') then
         q <= '0';
      else
         q <= data;
      end if;
   end if;
end process;
end behav;

ex) Rising Edge Flip-Flop with Synchronous Preset
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, preset : in std_logic;
          q          : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk)
begin
   if (clk='1' and clk'event) then
      if (preset='0') then
         q <= '0';
      else
         q <= data;
      end if;
   end if;
end process;
end behav;


ex) Rising Edge Flip-Flop with Asynchronous Reset and Clock Enable
library ieee;
use ieee.std_logic_1164.all;

entity dff is
port ( data, clk, reset, en : in std_logic;
          q              : out std_logic);
end dff;

architecture behav of dff is
begin
process(clk, reset)
begin
   if (reset='0') then
         q <= '0';
   elsif (clk='1' and clk'event) then
      if (en ='1') then  
         q <= data;
      end if;
   end if;
end process;
end behav;

Asynchronous Reset과 Clock이 Enable 될 때 data에 있던 값이 q로 assign 되는 것입니다. 한 가지 예제를 알면 응용하는 범위가 VHDL은 굉장히 넓기 때문에 많은 회로를 쉽세 만들 수 있다는 잇점이 있습니다. 우리가 설계한 회로를 라이브러리에 저장해 그것을 불러
서 사용할 수도 있습니다. REUSE 가능한 언어가 VHDL입니다.


ex) D-Latch with Gated Asynchronous Data
library ieee;
use ieee.std_logic_1164.all;

entity d_latch is
port ( data, enable, gate : in std_logic;
           q            : out std_logic);
end d_latch;

architecture behav of d_latch
is
begin
process(enable, data, gate)
begin
   if (enable='1') then
      q <= data and gate;
   end if;
end process;
end behav;  

 래치의 간단한 변형입니다. 그렇게 어려운 것은 없고 출력값이 변하는 것을 유심히 살펴보기를 바랍니다. 클럭이 시작될 때 변하는 것이 아니라 enable이 1인 영역에서 data와 gate가 둘다 1인 시점에서 변한다는 점을 시뮬레이션 결과에서 잘 살펴보기를 바랍니다.


ex) D-Latch with Gated Enable
library ieee;
use ieee.std_logic_1164.all;

entity d_latch is
port ( data, enable, data : in std_logic;
           q            : out std_logic);
end d_latch;

architecture behav of d_latch is
begin
process(enable, data, gate)
begin
   if ((enable and gate)='1') then
      q <= data;
   end if;
end process;
end behav;  


ex) D-Latch with Asynchronous Reset
library ieee;
use ieee.std_logic_1164.all;

entity d_latch is
port ( data, enable, data : in std_logic;
           q            : out std_logic);
end d_latch;

architecture behav of d_latch is
begin
process(enable, data, reset)
begin
   if (reset='0') then
      q <= '0';
   elsif (enable='1') then
      q <= data;
   end if;
end process;
end behav;  

간단한 예제들을 중심으로 플립플롭과 래치에 대해서 알아보았습니다. 8비트 레지스터를 설계하다보면 이 부분에 대해서 다시 한번 살펴볼 기회가 있을 것이라 생각됩니다. 위 예제들을 직접보고 코딩하지 마시고, 이런 기능을 가지고 있으므로 어떤 식의 설계가 들어가야 한다라고 자꾸 생각하시면서 직접 설계해 보시는 것이 기억에 오래 남을 것입니다. 전에도 말씀드렸지만 자기 자신의 고유의 코딩 방식을 절대로 잊지 마십시오.


 VHDL의 자료형과 객체형, Signal과 Variable과 Constant에 대해서 배우게 될 것입니다. 배울 것은 VHDL의 자료형과 객체형입니다. 이제까지는 std_logic과 bit_logic 그리고 Array인 std_logic_vector 만을 배웠습니다. 다른 언어들처럼 VHDL도 많은 자료형을
사용할 수 있습니다.

  VHDL에서 자료형 검사는 매우 엄격하며 정의된 자료형에 따라 사용할 수 있는 연산자 또한 각각 정의되어야 합니다. 합성기(synthesizer)에 따라 서로 지원하는 데이터형이 다를 경우 VHDL 소스 사이의 호환성에 심각한 문제를 일으키며 많은 자료형 변환 함수와 타입 캐스팅 방법이 존재하게 된다. 이러한 문제를 해결하기 위하여 87년 IEEE 1076 VHDL의표준에 이어 1991년에 IEEE 1164로서 디지털 회로의 합성 가능한 자료형에 대한 표준이 제정되기에 이르렀다. IEEE 1164는 디지털 회로에 대하여 9 가지 값(standard 9-valued logic)을 갖는 데이터 형 “std_logic”을 정의하였고, 이는 IEEE 1076 의 “bit”형을 확장한 것이다. IEEE 1076에는 VHDL의 언어에 대한 표준과 아울러 데이터 타입 및 각종 연산에 대한 표준이 정해져 있다. IEEE 1076에는 디지털 회로의 비트(bit) 형과 정수 및 실수형 문자형 등이 있으며 이중 bit와 정수형이 합성 가능하다.  IEEE 1164의 “std_logic”은 bit의 ‘1’과 ‘0’이외에 Pull-up, Pull-down에 해당하는 ‘H’(Weak-High),  'L’(Weak-Low)와 ‘Z’(high-impedance), ‘U’(uninitialize),
‘X’ (unknown), ‘-‘(Don’t care)등을 정의해 놓음으로써 디지털 회로의 합성뿐만 아니라 시스템 인터페이스에 대한 배려를 해두었다.


 우선 용어부터 정리를 할까요. VHDL에서 signal, variable, constant 등과 같이 어떠한 값을 가지고 있는 것을 객체(Object)라고 하며, 모든 object는 data type을 갖는다. 각 object가 가지는 data type은 시뮬레이션 도중에는 변하지 않는 정적(static)이다.

    signal     a, b  :    std_logic;
   객체선언   객체      자료형(data type)

 우선 VHDL에서 사용하는 3가지 객체 종류에 대해선 먼저 살펴봅시다.

1. Signal(신호)
 ex) signal a, b, c : bit;
     c <= a and b;

2. Variable(변수)
 ex) variable temp : bit;
     temp := a and b;

3. Constant(상수)
 ex) constant p1 : integer := 314;

위의 세 가지 객체형은 다음 시간에 자세하게 다루게 됩니다.
 
 그럼 다음은 어떤 데이터 타입이 있는지 어디 한번 봅시다.
                                               
                      ┏━━  Scalar Types    
VHDL Data Types   ┃               ┃              
                      ┃               ┣━  Enumeration Type              
                      ┃               ┣━  Integer Type
                      ┃               ┣━  Real, Floating-Point Type
                      ┃               ┗━  Physical Type
                      ┃
                      ┃  ┏━  Array Type
                      ┗━┫
                          ┗━  Record Type


1. 열거형 (Enumeration type )
 기본적으로 VHDL에서 사용하는 대부분의 자료형은 대부분 열거형 (enumeration type) 이다. IEEE 1076의 standard package에 정의되어 있는 열거형의 예를 들면 다음과 같다.

   type boolean is (false,true);
   type bit is ('0', '1');

 IEEE 1164에 std_ulogic은 다음과 같이 열거형으로 정의 되어 있다.

TYPE std_ulogic IS ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

  'U'는 초기화되지 않은 상태(Uninitialized)를 의미하며 'X'는 Unknown으로서 디지털 값의 충돌 등과 같은 에러상태를 나타낸다. '0' 과 '1'은 디지털 값에 해당하며 'Z'은 High Impedance, 'W', ‘L’, ‘H’는 각각 Weak Unknown, Weak 0, Weak 1로서 Pull-up혹은
Pull-down된 디지털 값을 나타낸다. 끝으로 ‘ -‘은 합성 시 논리 최적화에 Don't care로서 이용된다. 열거형을 이용하면 사용자는 언제든지 자료형의 정의가 가능하다. 또한 열거형으로 정의된 경우 인코딩(encoding) 방법을 지정할 수 있다. 인코딩 방법으로는 2진 코드에 의한 방법(binary)과 One-Hot Encoding이 있다. One-Hot encoding 방법은 유한상태 머신(FSM : Finite State Machine)에서 상태를 나타내는 경우에 많이 이용되는 방법이다. 다음과 같은 예를 살펴보자.

type state is (idle, receive, send);

와 같이 정의된 자료형 “state”의 경우 binary와 One-Hot encoding 되었을 때 차이는 다음과 같습니다.

 type state is (idle, receive, send)

            bit2  bit1  bit0                    bit1  bit0  
  idle         -    -    1         idle          0     0    
  receive      -    1    -        receive        0     1    
  send        1    -    -         send          1    0    

     One-hot Encoding              Binary Encoding


  예제에서와 같이 열거형 “state”는 3개의 요소를 가지므로 Binary encoding하면 2비트가 필요한 반면 One-Hot encoding하는 경우 각 요소마다 1개의 비트를 할당하여 3비트로 표현된다. 잠시 소개가 있었지만, 회로의 Performance를 고려할 때 One-hot Coding은 아주 유용한 방식 중에 하나이다. VHDL에서 형 검사(type checking)가 치밀한 이유 중 하나가 위와 같은 열거형을 주로 다루기 때문이라고 할 수 있다. 각종 연산자 혹은 할당(assignment)의 경우 기본적으로 열거형으로 이루어진 서로 다른 두 타입은 비트 폭에서부터 다르기 때문이다. 다음과 같이 bit 형과 std_logic형의 할당문의 경우 예를 살펴보자.

 Type bit is (‘0’, ‘1’);
 Type std_logic is ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

와 같이 정의된 두개의 시그널을 사용한 할당문

Signal A : bit;
Signal B : std_logic;

A <= B;

은 하드웨어적인 연결의 의미를 고려해 볼 때 할당문은 성립할 수 없는 것이 당연하다.


2.. 정수형 (Integer Type)

 IEEE 1076에 정의된 정수형의 기본적인 비트 폭(bit-width)은 32비트로 되어 있다.

     type integer is range -2147483648 to 2147483647;

 정수형은 산술연산이 가능하며 2의 보수형태로 이루어진다. 또한 정수형은 합성이 가능하며 범위를 지정하지 않을 경우 32비트가 된다. 따라서 과도한 비트 폭을 갖는 연산기의 합성을 피하려면 정수의 범위를 지정해서 사용하도록 한다. 다음의 예는 4비트 Signal을 선언
한 예이다.

     Signal count : integer range 0 to 15;
     Signal count : std_logic_vector(3 downto 0);


ex1)
library ieee;
use ieee.std_logic_1164.all;

entity add is
port ( a, b : in integer range 0 to 15;
         c  : out integer range 0 to 15);
end add;

architecture rtl of add is
begin
   c <= a + b;
end rtl;

 위의 예제는 4비트 Adder를 설계한 것이다. 다음과 비교해 보라.
ex2)
library ieee;
use ieee.std_logic_1164.all;

entity add is
port ( a, b : in std_logic_vector(3 downto 0);
         c  : out std_logic_vector(3 downto 0);
end add;

architecture rtl of add is
begin
   c <= a + b;
end rtl;

구현을 해보면 같은 회로라는 것을 알 수 있다. 그러나 수학적인 연산 기능을 수행할 때 비트 단위로 계산하는 것보다는 Integer로 변환해서 사용하는 것이 이해에 훨씬 도움을 줄 것이다.

3. 실수형 (Real, Floating-Point Type)

  실수형(real type)은 합성가능하지 않다. 시스템 모델링이나 아날로그 회로의 모델링 등에 사용될 수 있다. IEEE 1076의 실수형의 정의는 다음과 같다.

   type real is range -1.0E38 to 1.0E38;

 실수형의 디폴트 범위가 위의 범위이다. 그렇지만 우리가 설계하는 회로가 위의 범위를 항상 사용하는 것은 아니다. 그래서 범위를 지정해주는 것이 효율적일 것이다.
 


4. Physical Type
 
  물리량의 단위(unit)와 배수 관계를 정의한 것이며 합성 가능하지 않다. IEEE 1076에는 시간에 대한 정의가 있는데 다음과 같다.

time is range -2147483647 to 2147483647
units
  fs;
  ps = 1000 fs;
  ns = 1000 ps;
  us = 1000 ns;
  ms = 1000 us;
  sec = 1000 ms;
  min = 60 sec;
  hr = 60 min;
end units;

위에서 볼 수 있듯이 VHDL의 최소시간 단위는 fs (femto second, 10E-15) 이다.


5. 배열형 (Array Type)

 VHDL에서 배열형을 사용할 수 있다. 일 차원 배열형의 경우 대부분 합성기에서 지원 하지만 2차원 배열을 지원하지 않는 합성기도 많다. 디지털 회로의 기본 데이터 단위는 “bit” 이다. 이를 버스형태로 정의하기 위해서 “bit_vector”형을 사용한다. 즉 버스를 정의하는 것은 “bit”의 일 차원 배열이다. 배열형을 정의 할 때 그 크기를 지정하는 경우가 있고 임의의 배열 크기를 지정할 수도 있다.

 type byte is array ( 7 downto 0) of bit;

 일차원 배열로 8-비트 크기의 데이터 타입 “byte” 을 정의한 것이다.

TYPE std_logic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_logic;

"std_logic" 형으로 일 차원 배열형 “std_logic_vector”를 선언한 것이다. 이때 배열의 크기를 제한 시키지 않은 것으로서 시그널을 선언할 때 그 크기를 정하여 사용할 수 있다. 배열형의 선언한 예는 다음과 같다.

  Signal byte_a : byte;
  Signal count : std_logic_vector( 7 downto 0);


6. 레코드 형(Record Type)

 VHDL에서는 레코드형을 지원한다. 디지털 회로에서의 레코드형 사용 예는 기계어 명령의 비트맵 표현 등에 이용될 수 있다. 다음은 레코드 형의 사용 예이다.
       
type month_name is (jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dev);

type date is
 record
 day : integer range 1 to 31;
 month : month_name;
 year : integer range 0 to 4000;
end record;

constant my_birthday : date := (21, nov, 1963);
SIGNAL my_birthday : date;
 
my_birthday.year <= 1963;
my_birthday.month <= nov;
my_birthday.day <= 21; -- 5-bit

-- my_birthday(0) : LSB
-- my_birthday(4) : MSB


7. 파생형 (Subtype)과 형 변환(Type Conversion)

  VHDL에서의 파생형(subtype)을 정의할 수 있으며 다음의 예는 정수로부터 일정한 크기를 갖는 파생 정수형을 정의한 예이다.

        type big_integer is range 0 to 1023;
        subtype small_integer is big_integer range 0 to 7;
 
“small_integer”는 “big_integer”의 파생형으로 정의되었다.  이 경우 파생형 “small_integer”의 의미는 10-비트 크기의 “big_integer”의 하위 4-비트를 차지하도록 정렬된다는 의미로서 두 데이터 형의 호환됨을 나타낸다. 다음의 예는 VHDL에서 자료형 검사(type checking)의 엄격함을 보여준다.

        type big_integer is range 0 to 1000;
        type small_integer is range 0 to 7;

        signal intermediate : small_integer;
        signal final : big_integer;
        final <= intermediate * 5; -- type mismatch error

   위의 예에서 “big_integer”와 “small_integer” 형은 비록 서로 정수형이긴 하지만 서로 호환 돼지 않는다. 이러한 경우 “small_integer”를 파생형으로 정의함으로서 형 불일치(type mismatch) 에러를 해결할 수 있다.

        type big_integer is range 0 to 1000;
        subtype small_integer is big_integer range 0 to 7;
        signal intermediate : small_integer;
        signal final : big_integer;
        final <= intermediate * 5;

또 다른 방법으로 type casting을 이용할 수 있는데 이 경우는 기본적으로 두 형의 기본형이 같아야 한다.
       type big_integer is range 0 to 1000;
       type small_integer is big_integer range 0 to 7;
       signal intermediate : small_integer;
       signal final : big_integer;
       final <= big_integer(intermediate * 5);
  만일 정수형과 “std_logic_vector”형으로 변환하기 위해서는 두 데이터 타이의 기본형이 전혀 다르므로 형 변환 함수(type conversion function)를 사용하여야 한다. 형 변환 함수는 사용자가 임의로 만들어 쓸 수 있으나 IEEE 1164의 산술 패키지(numeric_std, numeric_bit)에는 정수와 “std_logic_vector”, “bit” 사이의 형 변환을 위한 함수를 다수 가지고 있으므로 가급적 이를 이용하도록 권장한다. IEEE 1164 라이브러리의 산술연산과 형 변환 함수는 합성 가능한 산술 연산을 다루면서 자세히 살펴보기로 한다. 다음의 예는 산술연산과 형 변환 함수의 이용에 대한 것이다.

package my_type is
type big_integer is range 0 to 1023;
subtype small_integer is big_integer range 0 to 7;
end package;

library ieee;
 use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;
 use work.my_type.all;

entity subtype_test is
port (
a : in small_integer;
 b : in small_integer;
 c : out std_logic_vector(9 downto 0) );
end subtype_test;
architecture behave of subtype_test is
 signal t_int : big_integer;
 begin
t_int <= a + b;
 c <= std_logic_vector(to_unsigned(natural(t_int), 10));
end;

 위의 예는 정수 입력을 받아서 연산을 수행한 후 이를 10 비트 크기의 “std_logic_vector”로 출력하는 경우이다. 입력된 2개의 정수형(“small_integer”) a,b를 계산하여 “big_integer”로 할당한다.

              t_int <= a + b;

  사용자 정의형 “big_integer”인 “t_int”로 부터 std_logic_vector”로 변환하는 과정은 약간 복잡하게 보이지만 이러한 변환과정이 시스템 설계와 서로 다른 모듈사이의 인터페이스 할 때 자주 직면하게 되는 문제이므로 잘 이해해둘 필요가 있다.

       c <= std_logic_vector(to_unsigned(natural(t_int), 10));

 Numeric_std package에 정수-unsigned 변환 함수가 to_unsigned()로 제공되고 있다. 이 함수의 argument가 natural이므로 사용자 정의형으로부터 정수형(natural)으로 type-casting 한다. Unsigned 형으로 변환할 것이므로 integer가 아닌 natural로 type-casting 한 것이다. 정수형을 std_logic_vector로 직접 변환하는 함수를 가지고 있지 않다. 따라서 to_unsigned() 함수를 사용하여 정수를 10비트 unsigned로 변환한 후 다시 type-casting 하여 “std_logic_vector”인 출력포트에 연결한 것이다. unsigned는 IEEE 1164의 numeric_std에 다음과 같이 정의되어 있으므로 type-casting이 가능하다.

         type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
         type SIGNED is array (NATURAL range <>) of STD_LOGIC;

 이 변환 과정을 보면 알 수 있듯이 같은 기본형으로부터 파생된 자료형은 type-casting 할 수 있지만 기본형이 다른 경우 형 변환 함수를 써야 한다. 그러나 “t_int <= a + b;” 에서와 같이 기본형이 같은 파생형(subtype)의 경우에는 변환을 수행할 필요가 없다. 위의 예를
합성한 결과는 그림 4와 같다. 0~7까지의 범위를 갖는 두개의 “small-integer”형 입력이 4비트로 연산기로 합성된 후 10비트 출력의 하위 4비트로 출력되는 것을 볼 수 있다.


 다음은 입출력 타입을 다시 한번 설명하고 넘어가겠습니다.  디지털 신호가 '1' 과 '0' 만으로 회로를 다룰 것인지 아니면 하이 임피던스(Z)도 있고 풀업(H), 풀다운(L), 그리고 합성과 시뮬레이션의 상태를 나타내기 위해서 Don’t care(-), Unknown(U), 버스 충돌 등에 의한 에러상태(X) 등도 구분할 것인지 결정해야 한다. 전자의 경우 bit 타입이라고 하고 후자의 경우 std_logic 이라고 하기로 규정했다. VHDL 언어 자체적으로는 std_logic에 대한 규정은 없다. 다만 IEEE 1076을 정할 때 std_logic_1164 라는 것을 정해 놓고 이곳에 bit라는 것은 1 과 0으로 규정한다거나 std_logic은 1, 0, Z, H, L, X 등등으로 규정한다고 정했다.


  우선 Constant에 대해서 먼저 설명하겠습니다. Signal과 Variable의 차이점은 좀 미세한 부분이 많아서 둘을 비교해 가면서 설명하는 것이 좋을 것이라 생각됩니다.

 constant는 초기에 선언한 상수의 값을 유지하는데 사용되며 VHDL의 문장 작성에 도움을 주어 쉽게 수정하거나 확장하는데 주로 이용한다. constant의 대입기호는 ' := '를 사용하고 있다. Variable과 같은 기호를 사용합니다. constant의 초기값은 즉시 대입되며 한 번 대입된 값은 바꿀 수 없다. 예를 들자면 Pi 값을 먼저 설정해 두고 계속 사용하면 편리할 것이다. 사용방법은 간단하다.
 
 constant p1 : integer := 314;
 constant length : integer := 345;
 constant pi : real := 3.1415119;

 제가 가장 어렵다고 생각되는 부분이 Signal과 Variable입니다. 이 부분 때문에 너무 많은 고생을 한 기억이 납니다. 차이점을 잘 알고 있어야 합니다. 우선 Signal에 대해서 알아봅시다. signal은 VHDL 합성시에 Wire(선)로 구성되며, 각 부품의 연결에 사용되는 외적변수이다. 세 가지로 사용됩니다.

 우선 포트 signal로 사용됩니다. 포트를 정의할 때 사용됩니다.

        port ( a, b : in bit;
                z   : out bit);
 여기에서 a, b, z는 port signal로 사용되었습니다. 입출력의 정의가 signal로 정의됩니다.

architecture rtl of and_1 is
begin
   z <= a and b;
end rtl;
 
 위의 예제에서 보면 알 수 있듯이 포트 시그널로 정의가 되어 있기 때문에  z <= a and b; 라는 표현이 가능합니다. 만약 z := a and b; 와 같이 variable assign 한다면 에러가 날 것입니다.

 두 번째로 signal을 정의하고 이것을 초기치로 설정할 수 있습니다. 사용방법은 열거형으로 정의하면 됩니다. 그러나 Assign의 방법이 조금 다릅니다.

signal temp : std_logic_vector(3 downto 0) := "1100";

 세 번째로 일반적인 signal의 표현입니다. 저는 포트 시그널과 구별하기 위해서 이것을 내부 signal이라는 표현을 사용합니다. (그러나 포트 시그널과 내부 시그널을 구별없이 signal이라고 하는 것이 보통입니다.) 내부 시그널이라고 표현하는 이유는 a, b, c, d라는 입력이 있고 출력이 z라는 포트 선언이 있습니다. 그러나 a와 b를 더해서 e라는 값에 저장을 하고 c와 d를 더해서 f라는 값에 저장을 합니다. e와 f를 더해서 z라는 값에 출력을 하는 회로가 있다고 합시다.

-- 필요없는 부분은 삭제를 했습니다.
entity adder is
port ( a, b, c, d : in std_logic_vector(3 downto 0);
        z       : out std_logic_vector(3 downto 0));
end adder;

architecture temp of adder is

signal e : std_logic_vector(3 downto 0);
signal f : std_logic_vector(3 downto 0);

begin
   e <= a + b;
   f <= c + d;
   z <= e + f;
end temp;

 위 부분에서 e와 f가 내부 시그널로 표현되었습니다. 그리고 Process 문에서도 사용가능 합니다. 다만 그 시점에서 값이 바로 대입되지 않고 end process를 만나면 완료되어 값이 결정됩니다. 위의 예제는 그 시점에서 바로 값이 대입된다는 것을 알 수 있습니다.
 왜 내부 시그널이라는 개념을 사용하는지 알겠습니까? 그리고 항상 내부 시그널은 architecture와 begin 사이에 들어가야 합니다. 이와 반대로 variable은 process 문 안에서만 사용할 수 있고 process 문과 begin 사이에 들어가야 합니다.

 Variable은 process나 부프로그램(function과 procedure)에서만 사용되며 variable이 지니는 값도 process나 부프로그램 내에서만 유효한 내적변수이다. variable은 signal과 같이 VHDL 합성시에 바로 선으로 구현되는 것이 아니며, 중간 연산단계에 주로 사용된다. variable에서 사용되는 assign 기호는 ' := '이고, 즉시(immediately)라는 의미를 가진다. signal과 비슷한 선언 방식을 사용한다.


-- 입력이 a와 b이고 출력이 c와 d일 때
variable tmp1, tmp2 : std_logic;
signal tmp3 : std_logic;
..
tmp1 := '1';
tmp2 := a and b;
..
c <= tmp1;
d <= tmp2;

 그 값을 돌려줄 때 signal <= variable; 라는 방식을 사용한다.

다음 예제는 3입력 and 게이트의 구현이다. 좀 차이점을 실감할 수 있을 것이다.
ex1) 3입력 and gate
library ieee;
use ieee.std_logic_1164.all;

entity and_3 is
port ( a, b, c : in bit;
        z       : out bit);
end and_3;

architecture temp of and_3 is
begin
  process(a, b, c)
  variable temp : bit;
  begin
     temp := '1';
     temp := a and temp;
     temp := b and temp;
     temp := c and temp;
     z <= temp;
  end process;  
end temp;  

 architecture 내에 process와 begin 사이에 variable temp를 선언하며, temp는 중간 단계의 연산 결과를 잠시 보관한다. 그러나 시그널처럼 즉시 그 값을 temp에 기록하지는 않는다.이것이 signal과 variable의 미세한 차이이다. 다음 예제를 가지고 그 결과 값을 확인해 보기를 바란다. signal로 표현한 3입력 and 게이트이다. 분명히 에러 또는 warning을 보게 될 것이다.

ex2)
library ieee;
use ieee.std_logic_1164.all;

entity and_3_1 is
port ( a, b, c : in bit;
        z       : out bit);
end and_3_1;

architecture temp of and_3_1 is
signal temp : bit;
begin
  process(a, b, c)
  begin
     temp <= '1';
     temp <= a and temp;
     temp <= b and temp;
     temp <= c and temp;
     z <= temp;
  end process;  
end temp;  

 이 두 예제의 차이점을 이해했다면 어느 정도 signal과 variable의 차이점을 이해할 수 있을 것이다.

 다음 예제를 구별할 수 있다면 충분히 다음으로 넘어갈 수 있을 것입니다. 이번 예제는 8비트 Parity 체크 회로입니다. 패러티를 검사하는 회로에서 signal과 variable로 정의되었을 때와 다른 회로도를 보입니다.  그 차이점을 충분히 이해할 수 있었으면 하는 바람입니다. 그리고  for loop 구문이 사용됩니다. 어떻게 사용되는지 자세히 보고 다음에 활용해 보세요.


ex3) 정상적인 Parity 체크 회로
library ieee;
use ieee.std_logic_1164.all;

entity parity is
port ( word : in bit_vector(7 downto 0);
       parity : out bit);
end parity;

architecture rtl of parity is
begin
process
variable result : bit;
begin
   result := '0';
   
   for i in 0 to 7 loop
      result := result xor word(i);
   end loop;
   
   parity <= result;
end process;
end rtl;    

 for loop 문은 별로 어려움없이 이해할 수 있을 것입니다. 범위 시작에서 범위 끝까지 증가하면서 수행하게 된다.
 
for 변수 in 범위시작 to 범위끝 loop
   statement;
end loop;  
ex4)
library ieee;
use ieee.std_logic_1164.all;

entity parity is
port ( word : in bit_vector(7 downto 0);
       parity : out bit);
end parity;

architecture rtl of parity is
signal result : bit;
begin
   process
   begin
      result <= '0';
   
      for i in 0 to 7 loop
         result <= result xor word(i);
      end loop;
   
      parity <= result;
   end process;
end rtl;  


ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity upcount is
port ( clk, reset : in std_logic;
        count_out  : out std_logic_vector(5 downto 0));
end upcount;

architecture rtl of upcount is
signal tmp : std_logic_vector(5 downto 0);
begin
   count_out <= tmp;
   process(clk, reset)
   begin
      if (reset='1') then
         tmp <= "000000";
      elsif (clk='1' and clk'event) then
         tmp <= tmp + '1';
      end if;
  end process;
end rtl;            

 우선 내부 시그널의 위치를 살펴봅시다. architecture와 begin 사이에 들어갑니다. 그리고 모든 회로는 Concurrent하게 동작한다고 했죠. 그러니  count_out <= tmp; 와 Process 문과는 두 개의 구문이 concurrent하게 동작합니다. Process 구문에서 마지막으로 tmp의 값이 결정되어 나옵니다. 그러면 count_out의 값이 결정됩니다.  process 내의 내용을 조금 살펴봅시다. reset이 1이라면 tmp의 값이 000000으로 결정됩니다. elsif 구문에서 reset이 0이고, 클럭이 상승에지에서 1 증가된 값을 가지게 됩니다.  그리고 if 구문에 대해서 알아봅시다. if 구문이 사용된 예제는 앞에서 많이 보았죠.
if  ...  then    ....    ;
end if;
위의 경우는 플립플롭의 경우라면 래치가 될 가능성이 많군요. 약간 불안정한 형태입니다.

if  ...    then  ....  ;
else   ....    ;
end if;        
가장 대표적인 형태의 if 구문입니다.

if    ...   then   ....   ;
elsif   ....      ;
end if;
위의 예제의 경우가 사용된 형태입니다.
if   ...    then    ....    ;
elsif    ....      ;
....
else   ....      ;
end if;
조금 복잡한 형태의 구문입니다.

ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity upcount2 is
port ( clk, reset, enable, load : in std_logic;
        databus    : in std_logic_vector(5 downto 0);
        count_out  : out std_logic_vector(5 downto 0));
end upcount2;

architecture rtl of upcount2 is
signal tmp : std_logic_vector(5 downto 0);
signal clkenable : std_logic;
begin
   count_out <= tmp;
   clkenable <= clk and enable;
   process(clkenable, reset, load)
   begin
      if (reset='1') then
         tmp <= "000000";
      elsif (clkenable='1' and clkenable'event) then
         if (load='1') then
            tmp <= databus;
         else
            tmp <= tmp + '1';
         end if;  
      end if;
  end process;
end rtl;      
 load가 1이면 databus의 값을 로드하게 되어 있군요. 약간 복잡하게 보입니다만 그렇게 복잡한 형태는 아닙니다. 다만 clkenable라는 이상한 신호를 발견했을 것입니다.  clkenable <= clk and enable; 클럭 신호와 enable 신호의 and를 한 것이 clkenable 신호입니다. 전문적인 용어로 gated clock이라고 합니다. 이 신호를 사용할 때는 Timing을 고려해야 합니다. 그렇지 않으면 glitch가 발생할 가능성이 너무 많습니다. 그럼 왜 gated clock을 사용할까요. Synchronous 회로의 단점은 무엇일까요. 아마도 파워 소모가 너무 많다는 것입니다.
 다음 Asynchronous 회로를 살펴봅시다.

ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity upcount3 is
port ( clk, reset, enable, load : in std_logic;
        databus    : in std_logic_vector(5 downto 0);
        count_out  : out std_logic_vector(5 downto 0));
end upcount3;

architecture rtl of upcount3 is
signal tmp : std_logic_vector(5 downto 0);
signal clkenable : std_logic;
constant lastvalue : std_logic_vector := "111011";
constant initialvalue : std_logic_vector := "000000";
begin
   count_out <= tmp;
   clkenable <= clk and enable;
   process(clkenable, reset, load)
   begin
      if (reset='1') then
         tmp <= initialvalue;
      elsif (clkenable='1' and clkenable'event) then
         if (load='1') then
            tmp <= databus;
         elsif (tmp=lastvalue) then
            tmp <= initialvalue;
         else  
            tmp <= tmp + '1';
         end if;  
      end if;
  end process;
end rtl;      

 초기치와 마지막 값을 constant를 통해 설정해 두었다는 것이 틀리다는 것을 알 수 있겠죠. constant의 위치도 유심히 보시고, 초기치가 0이고 마치막치가 59입니다. 이 회로를 어떻게 변형하면 시계가 될 수 있는 지도 한 번 생각해 보십시오.

ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity downcount is
port ( clk, reset, enable, load : in std_logic;
        databus    : in std_logic_vector(5 downto 0);
        count_out  : out std_logic_vector(5 downto 0));
end downcount;

architecture rtl of downcount is
signal tmp : std_logic_vector(5 downto 0);
signal clkenable : std_logic;
constant zero : std_logic_vector := "000000";
begin
   count_out <= tmp;
   clkenable <= clk and enable;
   process(clkenable, reset, load)
   begin
      if (reset='1') then
         tmp <= zero;
      elsif (clkenable='1' and clkenable'event) then
         if (load='1' or tmp=zero) then
            tmp <= databus;
         else
            tmp <= tmp - '1';
         end if;  
      end if;
  end process;
end rtl;      

 위에서 했던 예제와는 반대로 다운 카운터입니다. '+' 대신에 '-' 가 사용되었다는 것이 다르죠. 하나의 예제를 정확하게 알 수 있다면 비슷한 응용회로는 이해하기도 쉽고, 변형하기도 쉽죠.


ex)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity updown_count is
port ( clk, reset, up_down, enable, load : in std_logic;
        databus    : in std_logic_vector(5 downto 0);
        count_out  : out std_logic_vector(5 downto 0));
end updown_count;

architecture rtl of updown_count is
signal tmp : std_logic_vector(5 downto 0);
signal clkenable : std_logic;
constant zero : std_logic_vector := "000000";
begin
   count_out <= tmp;
   clkenable <= clk and enable;
   process(clkenable, reset, load)
   begin
      if (reset='1') then
         tmp <= zero;
      elsif (clkenable='1' and clkenable'event) then
         if (load='1') then
            tmp <= databus;
         elsif (up_down='1') then
            tmp <= tmp + '1';
         else
            tmp <= tmp - '1';
         end if;  
      end if;
  end process;
end rtl;

 업다운 카운터는 up_down이라는 새로운 입력이 하나있죠. up_down 입력이 이면 업카운터를 나타내고 0이면 다운 카운터의 기능을 수행합니다. 종합적인 기능을 수행하는 회로입니다. 문법적인 기능은 천천히 읽어보시면 쉽게 이해가 될 것이라 판단됩니다.  
 이외에도 많은 카운터의 종류가 있습니다. 그 중에 몇 가지만 더 살펴보겠습니다.

     
ex)
library ieee;
use ieee.std_logic_1164.all;

entity johncnt is
port ( clk, reset : in std_logic;
        count_out  : out std_logic_vector(4 downto 0));
end johncnt;

architecture rtl of johncnt is
signal tmp : std_logic_vector(4 downto 0);
begin
   count_out <= tmp;
   process(clk, reset)
   begin
      if (reset='1') then
         tmp <= "00000";
      elsif (clk='0' and clk'event) then
         tmp <= tmp(3 downto 0) & not(tmp(4));
      end if;
  end process;
end rtl;    

 위의 예제는 Johnson Counter를 기술했습니다.  tmp <= tmp(3 downto 0) & not(tmp(4)); 여기에서는 몇 가지 설명을 드리고 갈 것이 있
네요. tmp는 5비트입니다. tmp의 최상위 비트는 tmp(4)가 됩니다. 비트를 구분할 수 있다는 말입니다. not는 그 비트의 역의 값을 취합니다. 0이면 1의 값을 가진다는 말입니다. tmp가 5비트이므로 오른쪽의 tmp 비트도 당연히 5비트가 되어야 합니다. &라는 기호를 사용했습니다. & 표시는 비트를 합한다는 표시입니다. tmp(3 downto 0)가 4비트이고 tmp(4)가 1비트이므로 합이 5비트가 되는 것입니다. & 표시는 시프트 레지스터를 구현할 때 아주 유용한 표현입니다. 시프트 레지스터를 구현할 때 참 편리합니다. 위의 예제를 보면 알 수 있듯이 카운터를 조금만 변형하면 아주 유용한 시프트 레지스터를 구현할 수 있습니다.

 다음은 Gray Counter입니다. gray code 식으로 구현한 카운터입니다. 예제7은 동작적으로 기술된 Gray Counter이고 예제8은 행위적으로 기술된 카운터입니다. 비교해 보시면 이해할 수 있을 것입니다.

ex7)
library ieee;
use ieee.std_logic_1164.all;

entity graycnt is
port ( clk, reset : in std_logic;
        count_out  : out std_logic_vector(2 downto 0));
end graycnt;

architecture rtl of graycnt is
signal tmp : std_logic_vector(2 downto 0);
constant zero : std_logic_vector := "000";
begin
   count_out <= tmp;
   process(clk, reset)
   begin
      if (reset='1') then
         tmp <= zero;
      elsif (clk='0' and clk'event) then
         case tmp is
            when "000" => tmp <= "001";
            when "001" => tmp <= "011";
            when "010" => tmp <= "110";
            when "011" => tmp <= "010";
            when "100" => tmp <= "000";
            when "101" => tmp <= "100";
            when "110" => tmp <= "111";
            when "111" => tmp <= "101";
            when others => tmp <= "000";
         end case;  
      end if;
  end process;
end rt

l;



ex8)
library ieee;
use ieee.std_logic_1164.all;

entity graycnt2 is
port ( clk, reset : in std_logic;
        count_out  : out std_logic_vector(2 downto 0));
end graycnt2;

architecture rtl of graycnt2 is
signal tmp : std_logic_vector(2 downto 0);
alias c : std_logic is tmp(2);
alias b : std_logic is tmp(1);
alias a : std_logic is tmp(0);
begin
   count_out <= tmp;
   process(clk, reset)
   begin
      if (reset='1') then
         c <= '0';
         b <= '0';
         a <= '0';
      elsif (clk='0' and clk'event) then
         c <= (not(a) and b) or (not(c) and not(b));
      end if;
  end process;
end rtl;          

 위의 예제에서는 alias 라는 재미있는 기능을 사용했네요. tmp(2) 대신에 c를 사용한다는 말입니다. Unix나 Linux에서 사용하는 alias의 기능과 같습니다. alias 기능을 사용하기 싫다면 c대신에 tmp(2)라고 입력하면 됩니다. 회로 구분을 위해 포트이름이 길다면 alias를 사용
하는 것도 좋은 것같네요. 쓰기 싫다면 쓰지 않으면 됩니다. 회로를 설계하는데 있어 동작적으로 기술하든지 아니면 행위적으로 기술하든지 아니면 구조적으로 기술하는 것은 설계자의 마음입니다. 어떤 식으로든지 설계하면 됩니다.  좀 구체적으로 말하면 VHDL의 표현방법은 설계의 의도와 용도에 따라 방법을 선택하거나 혼합해서 사용할 수 있습니다. 부울대수, RTL, 논리연산자를 이용해서 자료 흐름적으로 기술하는 방법을 자료흐름표현(data flow description) 방법이라 하고, 시스템의 동작을 알고리즘으로 기술하는 방법을 동작적 표현 방법이라 부릅니다. 동작적 표현 방법은 porcess문을 이용하여 시스템의 동작을 편리하게 표현 할 수 있습니다. 구조적 표현 방법은 하드웨어의 Conponent의 상호연결로 구성되며, 게이트 레벨에서 서브 시스템 레벨로 구성된 컴포넌트의 Interface를 가능하게 한다. 하드웨어 표현에 매우 가까운 표현 방식이며 계층구조의 하드웨어 설계 시에 주로 이용된다. 쉽게 말하면 port map을 이용하는 방식입니다.  


ex9)
library ieee;
use ieee.std_logic_1164.all;

entity ringcnt is
port ( clk, reset : in std_logic;
        count_out  : out std_logic_vector(3 downto 0));
end ringcnt;

architecture rtl of ringcnt is
signal tmp : std_logic_vector(3 downto 0);
begin
   count_out <= tmp;
   process(clk, reset)
   begin
      if (reset='0') then
         tmp <= "0001";
      elsif (clk='0' and clk'event) then
         tmp <= tmp(2 downto 0) & tmp(3);
      end if;
  end process;
end rtl;                    


위의 예제는 간단한 기능의 4비트 Ring Counter입니다. 그냥 쉽게 읽어 보세요.


 다음 예제는 0에서 999까지 카운터가 가능한 회로입니다. 이 예제는 조금 중요하다고 생각
됩니다. 많은 응용이 가능한 회로라고 생각이 드니까요.

ex10)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity count999 is
port ( clk, reset : in std_logic;
        out_3  : out std_logic_vector(3 downto 0);
        out_2   : out std_logic_vector(3 downto 0);
        out_1    : out std_logic_vector(3 downto 0));
end count999;
architecture rtl of count999 is
signal tmp_d100 : std_logic_vector(3 downto 0);
signal tmp_d10  : std_logic_vector(3 downto 0);
signal tmp_d1   : std_logic_vector(3 downto 0);
constant zero  : std_logic_vector := "0000";
constant nine  : std_logic_vector := "1001";
begin
   out_3  <= tmp_d100;
   out_2  <= tmp_d10;
   out_1  <= tmp_d1;
   process(clk, reset)
   begin
      if (reset='1') then
         tmp_d100 <= zero;
         tmp_d10  <= zero;
         tmp_d1   <= zero;
      elsif (clk

='1' and clk'event) then
         if (tmp_d1=nine) then
            tmp_d1 <= zero;
            if (tmp_d10=nine) then
               tmp_d10 <= zero;
               if (tmp_d100=nine) then
                  tmp_d100 <= zero;
               else
                  tmp_d100 <= tmp_d100 + '1';
               end if;
            else
               tmp_d10 <= tmp_d10 + '1';
               tmp_d100 <= tmp_d100;
            end if;
         else
            tmp_d1 <= tmp_d1 + '1';
            tmp_d10 <= tmp_d10;
            tmp_d100 <= tmp_d100;
         end if;                  
      end if;
   end process;
end rtl;

 만약 이 회로를 구현한다면 세그먼트 3개가 필요할 것입니다. 잘 생각하시면 전자 시계에 대한 답도 나올 것입니다.

 제 강좌를 계속보시는 분은 적어도 한번은 컴파일 과정을 통해 에러를 체크하며 시뮬레이션 과정까지 한번은 실행해 보았을 것입니다. 그렇지 않으면 오늘 강좌를 이해하기가 좀 힘들지 않을까 생각됩니다.  오늘은 What is VHDL? 오늘은 조금 무거운 주제입니다. 처음에 시작하지 않은 이유는 어느 정도의 이해가 힘들기 때문에 뒤에 하는 것입니다. 이제부터는 여러분은 설계자의 입장에서 모든 것을 이해해야 합니다. 조금 복잡한 회로는 아직 시작하지 않았지만 여러분들이 잘 알고 있어야 하는 중요한 부분입니다.

 Time to Market.  이런 말을 들어본 적이 있습니까? 이 말은 설계자들이 항상 염두에  두고 있어야 하는 말입니다. 빠르게 변화하는 하드웨어 시장에서 아주 중요한 말입니다. 하드웨어 설계에서 시장까지 나오는 시간을 말합니다. 누가 먼저 얼마나 빨리 설계해서 시장
까지 나오는가 이것이 중요합니다. 예를 들자면 지금의 펜티엄 프로세서가 있습니다. 그렇지만 내가 다시 설계해서 성능과 가격을 낮춘 설계를 한다고 합시다. 그렇지만 이 설계는 벌써 의미가 없다는 말입니다. 지금의 펜티엄 프로세서를 얼마나 빨리 생산하는가 하는 것이
중요하다는 말입니다. 설계에서 시장까지.  요즘은 TR의 개수가 중요한 것이 아닙니다. 옛날에는 TR의 개당 가격이 비싸지만 요즘은 그렇게 중요한 요소가 아니라는 말입니다. 누가 빨리 시장에 선보이는가 이것이 중요한 의미입니다.

 다음은 설계자가 고려해야 할 요소를 생각해봅시다.
1. Performance :
    - Delay and cycle-time
    - Latency
    - Throughput ( for pipeline application)
 당연한 이야기입니다. 자기가 만든 회로의 성능이 다른 사람의 회로보다 우수하고 품질이 좋아야 한다는 것은 상식입니다. Delay적인 요소도 상당히 중요한 요소에 포함됩니다. 그리고 면적(Area)과 Delay는 반비례하는 관계가 있습니다. 면적이 커지면 Delay는 감소하고 면적이 작아지면 Delay는 증가합니다. 입력의 시작에서 출력의 끝까지의 시간(Latency), 출력속도(Throughput) 등을 다각적인 방향에서 설계해야 합니다.
         Area  
                           Cycle-time  
                                            이런 비례 관계를 가지고 있습니다.
                                            어느 하나만을 중점적으로 설계하는 것은
                                            별로 좋은 생각이 아닙니다.
                              Latency

2. Area ( yield and packaging cost)
  면적이 커진다면 칩의 개수가 늘어나는 것은 사실입니다. 그래서 무작정 회로를 크게 설계할 수는 없습니다. 회로의 크기를 줄일 수 있다면 가능한 최대로 줄이는 것은 좋습니다. 그렇지만 면적만을 최우선으로 줄이는 것은 좋지 않습니다. 칩의 단가를 줄이는 것도 중요
하지만 성능적인 요소뿐만 아니라 다른 요소도 생각해야 합니다.

3. Testability
 아주 큰 회로를 설계했다면 그것을 테스트하는 데에도 상당히 많은 비용이 든다는 사실입니다. 하나의 회로를 테스트하는 데 시간과 비용을 생각하지 않을 수 없습니다. 자기가 VHDL로 구현한 회로를 스키메틱으로 보았을 때 약간 추가된 부분을 볼 수 있을 것입니다.
그것은 Synthesis할 때 회로를 테스트하기 쉽도록 약간의 추가적인 회로가 포함됩니다. 이상한 것은 절대 아닙니다.  

4. Power
 회로가 복잡해지면 복잡해질수록 파워를 줄여야 합니다. 마이크로 프로세서 데이터 북을 보면 쉽게 확인할 수 있을 것입니다. 5V에서 3.5V로 이것이 다시 3.3V로 계속해서 파워를 줄이고 있습니다. 파워 소모를 줄이는 문제입니다. 점점 저 파워 회로가 주를 이루고 있습니
다. 이것은 무시할 수 없는 요소입니다.

 이 네 가지 요소를 복합적으로 이해하면서 네 가지 요소를 모두 충족할 수 있는 회로를 설계해야 합니다. 한 가지라도 무시하면 안 됩니다. 추가적인 요소로 생각하면 Coding style도 고려해서 설계해야 합니다. 그리고 Software적인 요소에서 소프트웨어로 처리할 수 있는 부분과 처리할 수 없는 구분을 생각해서 설계해야 합니다.
 

 자 그럼 우리는 왜 VHDL을 사용해서 설계를 해야 할까요? 아니면 왜 VHDL을 공부하고 있습니까?  ASIC과 VHDL 이라는 이상한 주제. 이것을 한 번 생각해 봅시다. 왜 시작해야 하는지를 역사적인 인식에서 다시 시작합시다. 이제는 설계자의 입장에서 생각해야 합
니다.

 VHDL(Very High Speed Integrated Circuit Hardware Description Language :
VHSIC Hardware Description Language)은 공인된 표준 하드웨어 설계언어이다. 70년대는 트랜지스터 레벨의 레이아웃(Layout) 편집기와 80년대부터 지금까지 사용하는 스키메틱(Schematic) 편집기가 등장하였다. 그런 이들 설계 기술은 대규모 회로 설계와 고도
의 기능적 레벨의 회로 설계를 다루기에 적합하지 않았다. 예를 들면 Schematic으로 25,000 내지 30,000 개의 게이트를 설계하려면 250페이지 이상의 도면이 필요하다. 종이 값이 너무 많이 들겠죠. 이처럼 많은 도면을 그려야 하는 것은 물론이고 각 도면의 회로 복잡도를 조절하고 회로 도면간 배선 등을 관리하는 것은 명백히 기술적인 문제뿐만 아니라 개발비용  및 기간 등의 문제가 야기된다. 이러한 상황이 계속된다면, 대규모 회로를 개발하는데 있어 개발비용이 과대해지거나 개발 기간이 길어저 실현 불가능한 상태에 이르고 말 것이다. 스키메틱으로 구현하는데 5만 게이트가 한계라고 한다. 이러한 이유로 VHDL이 필요성이 적실하게 느껴진다.
 VHDL은 초기에 하드웨어의 사양을 표준화된 방식으로 시술하는 문서화의 모델링(Modeling)을 위한 언어로 출발하였으며, 1980년대 후반에는 VHDL이 simulation에 의한 검정용 언어로 사용해야  한다는 여론에 의해 몇몇 VHDL simulator가 등장하게 되었다.
VHDL simulator가 등장한 시점에서 VHDL 관련 CAD 회사간에 VHDL의 표준화를 위해 1987년 IEEE에서 IEEE-1076이라는 표준을 만들어 공인하게 되었다. 그러나 이 시점까지도 VHDL은 simulation용으로 사용되었지만, 하드웨어 합성(synthesis)을 위한 설계 언어로 사용되지는 않았다. 1990년 초에 VHDL 관련 소프트웨어 회사가 많이 등장하고 하드웨어 설계 기능을 가진 합성 Tool이 개발되었다. 그리고 1991년 IEEE에서 IEEE-1164의 표준을 만들었으며, simulation뿐만 아니라 합성을 위한 설계 기능을 갖춘 표준화된 언어로 VHDL을 인식하게 되었다. 즉 VHDL은 소규모 회로에서 대규모 시스템 설계에 이르기까지 문서화, 검정 및 설계(합성)를 위한 표준화된 설계 방식으로 사용되고 있다. 그럼 VHDL을 가지고 어떻게 설계할 것인가? 라는 질문은 합시다. 먼저 시스템 설계 요구 사양을 결정해야 한다. 무엇을 만들 것인지를 결정해야 한다. 간단한 예를 들자면 전자 시계를 만든다고 하자. 다음은 시스템 사양(SystemSpecification)을 결정해야 한다. 시스템 사양은 시스템 모델링을 통해 이루어진다. 시스템 모델링은 하드웨어 구현에 염두를 두지 않고 시스템의 알고리즘을 표현하는 것이다. 시스템 모델링의 목적은 형식적 설계 사양으로서 사용할 수 있는 시뮬레이션 모델을 생성시키기 위한 것이다. 이 모델은 시뮬레이션 수행을 통해 시스템의 기능을 점검하고 확인하게 된다. 이러한 시스템의 사양은 설계자와 설계 의뢰자의 요구 사항을 명확하게 하기 위해서도 필요하다. 시스템의 모델링은 최종 하드웨어 합성을 위해서 RTL(Register Transfer Logic) 설계로
변환시킨다. 이 변환의 최종 목표는 하드웨어 구현이며 RTL설계를 넷리스트(Netlist)로 생성시키는 합성 과정을 수행하게 된다. 이 단계에서 VHDL은 특정 하드웨어 지원을 받게 되며 초기의 사양에서 제시한 칩상의 면적, 속도 및 Timing 요구에 대한 제한을 주게 되고
최초 계획된 시스템 사양의 요구에 만족하지 못하면 시스템의 모델링과 RTL변환 및 합성 과정을 다시 거치게 된다.


 이제 설계 계층 구조(Design hierarchy)에 대해서 알아봅시다.

 구      시스템 레벨(컴퓨터, 디스크 장치, 버스 인터페이스 등)     추
 체      칩 레벨(마이크로 프로세서, RAM, ROM, UART 등)       상
 적      RTL 레벨(레지스터, ALU, 카운터, MUX 등)              적
 설      게이트 레벨(NAND, NOR, Flip-flop 등)                  설
 계      Circuit 레벨(Transistor, Resister 등)                     계
         Layout 레벨

 ASIC 설계 프로세서에는 어느 레벨에서도 설계가 가능하다. 각 레벨간 표현 방식은 다르지만, 설계하려는 회로 자체에는 변함이 없어 서로 다른 레벨간 변환은 항상 가능하다.  시스템 레벨이 가장 상위레벨이다. 가장 추상적인 레벨이기도 하지만, 설계가 가장 어렵
다. 아직 VHDL Tool로 시스템 레벨을 정의하기는 어렵다. 상위 레벨의 알고리즘을 가지고 설계하기는 아직 단계적으로 어렵다는 뜻이다. 그러나 가능성은 있다.  하위 레벨로 갈수록 실제 회로적인 문제를 다룰 수 있다. 정확한 타이밍 정보라든지 실질
적인 회로 구현을 말한다. 지금 우리가 하고 있는 단계는 주로 레지스터 레벨의 설계를 주로 하고 있다. 큰 프로젝트를 설계한다면 상위 레벨부터 시작할 것이다. 이것이 Top-down 설계이다. 주로 ASIC은 Top-down 설계 방식을 이용한다. Layout 편집기나 Schematic으
로 설계하는 방식은 Bottom-up 방식을 사용한다. 어떤 식으로 설계를 하는 것은 문제가 되지 않는다. 하나의 큰 프로젝트를 시작하면 시스템 레벨을 정의하고 그것의 Simulation이 완전하다면 다음 단계로 내려간다. 각각의 칩 레벨을 설계할 것이다. 이 단계에서는 분업을
이용할 것이다. 전문적인 분야로 나누어서 각각의 레벨을 설계하고 검증할 것이다.      그럼 간단하게 전체적인 설계 과정을 잠깐 살펴봅시다.


1. Design
  1.1 Modeling
  1.2 Synthesis & Optimization
  1.3 Validation

   Test1(Simulation) 설계에 대한 최종적인 테스트를 말합니다.

2. Fabrication : 공장에서의 제조 과정을 말합니다. 줄여서 Fab.이라고 하지요.
 2.1 Mask Fabrication
 2.2 Wafer Fabrication

  Test2 : 제조 과정에서의 테스트를 합니다.

3. Packaging
 3.1 Slicing
 3.2 Packaging

 Test3 : 칩 속에 Packaging을 해야합니다. 그 과정에서의 테스트.

4. Testing : 실제적인 칩 테스터를 Emulation이라고 합니다.(이 비용도 고려해야 함)
 
위 과정 중에서 1. Design의 과정이 우리의 과정입니다. Fab에 관계된 것을 알고 있다면 설계에 많은 도움을 줄 것이라 생각합니다. 시간이 가능하다면 공부해보세요. 혼자서는 하기가 조금 힘들다는 단점이 있지만 가능하다면 집적회로 공정기술에 대해서 공부하는 것도 도움이 되겠죠. 저도 집적회로에 많은 시간을 투자해 어느 정도의 기초적인 과정은 알고 있습니다. Cmos 제조 과정은 알고 있습니다. 그래서 layout 과정을 이해하는데 어느 정도 도움이 됩니다.  
 
 지금부터는 VHDL의 실제 설계에 관한 내용입니다. 위의 내용은 Asic에 관계된 내용이지만 지금부터는 설계에 관계된 내용입니다. 어떻게 언어만으로 설계가 가능한지를 나타내는 과정입니다. 잘 알아두세요.
 Modeling
 Synthesis & Optimization
 Validation

 Modeling. 이것은 설계를 한다는 말입니다. 어떻게 설계할 것인지는 설계자에 달려있죠. 그러나 어떤 방식의 설계가 있는지는 알고 있어야 하겠죠. 모든 것의 기초가 되는 것입니다. 어떻게 코딩할 것인지를 선택해야 합니다.  Modeling abstraction의 종류에는 세 가지가 있습니다. 먼저 Architectural Level(추상적인 동작 모델링 - 번역이 다를 수도 있습니다. 우리 나라의 박사님들이 우리가 이해하기 쉽
도록 번역되었으므로 번역된 것에 신경 쓰지 마세요.)에 대해서 먼저 알아봅시다. 이 레벨에서는 구체적인 하드웨어 시스템이 어떻게 동작해야 하는가를 기술한 최상위  모델링 기법을 제공한다. 이유는 각종 시스템 설계용 알고리즘들이 어떻게 동작하는가를 비교 평가한다든지 이들 알고리즘들이 예측 가능한 입력 조건하에서 제대로 작동하는지 알아보고 싶을 때, 그리고 구체적인 회로 설계 과정에서 하드웨어 구현 방식과 설계 사양 등을 함께 고려하고자 할 때 매우 유용하기 때문입니다. 이 레벨에서는 구체적인 정보보다는 시스템 레벨의 추상적인 기술형태이다.
 Architectural Level의 설계가 끝나면 다음으로 Logic Level(다시 말하면 RTL Level)의 설계를 합니다. 이 레벨은 논리 회로 설계시 상세한 블록 다이어그램과 같습니다. 블록 다이어그램에서 하드웨어 함수 블록은 그 블록에 연결된 입출력 신호 및 데이터 버스 등을 통해 알아낼 수 있다. 이 레벨에서는 Boolean 식에서 RTL에 이르기까지 다양한 방식으로 기술할 수 있습니다. 흔히 RTL 모델링을 Data flow description이라고 합니다. 다음 단계로는 Geometrical Level입니다. 이 레벨에서의 코딩 구문은 netlist 표현 방식과 유사하다. 게이트 또는 플립플롭이거나 동작적 기술 레벨 내지는 RTL 코드로 기술된 Component들이 선으로 연결된 회로로 표현됩니다.
 VHDL에서는 설계 과정에서 이들 세 가지 기술 형태를 임의로 혼합된 형태도 허용합니다. 다시 말하면 Behavioral View에서는 What to do?(무엇을 하는가?)의 기술이고 Structural View에서는 How to do?(어떻게 하는가?)의 기술입니다.  이 세 가지 레벨이 기술되면 이 각각의 과정을 Synthesis 과정을 수행합니다. Architectural-level synthesis, Logic-level synthesis, Geometrical-level synthesis를 수행합니다. Architectural-level synthesis는 macroscopic structure를 결정합니다. macroscopic structure란 큰 빌딩 블록들을 말합니다. ALU나 Rom 같은 블록을 말합니다. 이 과정은 주로 Manual 기계를 할 때 주로 사용됩니다. Logic-level synthesis는 microscopic structure를 결정합니다. 로직 게이트의 상호 연결을 말합니다. 그럼 synthesis(합성)에 대해서 조금 자세히 알아봅시다. 소스를 코딩했다면 이것을 다시 게이트 레벨이나 RTL 레벨로 바꾸어 주어야 합니다. Synthesis란 번역만의 작업이 아닙니
다. 소스 코드의 Translation(번역)뿐만 아니라 회로의 Optimization(최적화) 기능을 동시에 수행합니다. 합성을 하는 이유는 설계 생산성 향상을 도모할 수 있고(Schematic에 비해 10배정도), Time-to-market(시장 출하 시간)을 단축시킬 수 있고, 시스템 수준의 설계를 가
능하게 해줍니다.  Asic에서의 합성 단계를 보면 첫 번째로 상위 합성(High-level(Architectural) synthesis)을 거치고 다음으로 논리 합성(Logic synthesis)을 거칩니다. 다음 단계로는 테스트 합성(Test synthesis) 과정을 거치고, 그 다음으로 레이아웃 합성(Layout synthesis)을 거칩니다. 여기서 테스트 합성이란 회로 테스트를 위해서 넣어주는 회로에 대한 합성을 말합니다.

 위의 부분은 설계자가 반듯이 알아야 하는 내용을 간략하게 정리한 내용입니다. 불필요한 부분은 많이 생략되었습니다. 위의 내용을 완전하게 이해하려면 더 많은 부분을 공부해야 할 것입니다. 제가 정리했지만 부족한 부분이 많다고 생각됩니다. 자기가 부족하다고 생각되는 부분은 자기가 스스로 찾아서 연구하십시오. 이 부분은 너무 방대한 내용이라서 정리하는데 많은 시간이 걸렸습니다. 이 부분을 이렇게 뒤에 설명하는 이유는 VHDL을 처음 시작하는 사람에게는 너무 어려운 내용이라서 이렇게 뒷부분에서 정리하고 있습니다.

 산술 연산 회로에 대해서 알아봅시다. 이제부터는 예제 중심으로 설명을 하고 간단한 기능을 생략하고 새로운 Syntax가 나오면 그것에 대해서 구체적으로 서술하겠습니다.
 가장 보편적인 예제가 Full-Adder입니다.
 

ex1) 1-bit Full-Adder
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity fa is
port( a, b, cin : in std_logic;
      sum, cout : out std_logic);
end fa;

architecture rtl of fa is
signal s0, s1, s2 : std_logic;
begin
   s0 <= a xor b;
   s1 <= a and b;
   sum <= s0 xor cin;
   s2 <= s0 and cin;
   cout <= s1 or s2;
end rtl;

 signal s0, s1, s2가 사용된 이유는 out port의 sum과 cout이 feedback을 허용하지 않기 때문입니다. 내부 시그널이라고 설명 드렸지요. architecture 구문 안에서는 어느 정도의 Delay이 가지고 있지만 병렬적으로 수행됩니다. a xor b의 결과 값이 s0인데 이 값이 sum의 입
력으로 가기 위해서는 순차적으로 수행된 것이 아니냐는 질문은 하지 마십시오. 그러면 이 자체가 아무 의미가 없어집니다. 정교하게 a xor b의 결과 수행 시간이 있으므로 당연히 순차회로라고 생각하면 안 됩니다. 그 결과 수행 시간이 아주 작은 값이라면 이것은 순차적으
로 수행되는 것이 아니라 병렬적으로 수행됩니다. 논리 회로의 간단한 부분이므로 내용은 생략합니다. 모르시면 논리 회로 책을 참조하세요. architecture 부분을 이렇게 고쳐도 시스템은 별 영향을 받지 않을 것입니다.

  sum <= a xor b xor cin;
  cout <= (a and b) or ((a xor b) and cin);
 그렇지만 synthesis가 어떻게 합성이 되는가 하는 것이 문제입니다. 이런 간단한 예제 정도는 최적화될 것입니다. 그런 간단한 예제는 문제없지만 복잡한 회로라면 최적화되게 합성이 될지는 확신할 수 없습니다. 조금 좋은 툴이라면 가능하겠지만 확신할 수 없는부분입니다.위의 예제는 비약적으로 바꾸었지만 실제로 그렇게 될 지도 모릅니다.VHDL은 Truth table의 형태로도 코딩할 수 있습니다. 툴의 방법의 차이는 있지만 대부분의 툴이 지원하는 내용입니다. 심지어 상태도로도 코딩이 가능합니다. 위의 예제를 조금 바꾸어봅시다. 진리표의 형태로 구현해 봅시다.

ex2)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity fa1 is
port( a, b, cin : in std_logic;
      sum, cout : out std_logic);
end fa1;

architecture rtl of fa1 is
begin
   process(a,b,cin)
   variable temp : std_logic_vector(2 downto 0);
   begin
      temp := a & b & cin;
      case temp is
         when "000" => sum <= '0';
                      cout <= '0';
         when "001" | "010" | "100" => sum <= '1';
                      cout <= '0';
         when "011" | "101" | "110" => sum <= '0';
                      cout <= '1';
         when "111" => sum <= '1';
                      cout <= '1';
         when others => sum <= '0';
                      cout <= '0';            
      end case;
   end process;                                
end rtl;        
 
 위의 예제는 상당히 재미있는 구조를 하고 있습니다. 모든 경우를 Truth table의 형태로 나타냈습니다. Adder의 모든 경우가 다 포함되

어 있습니다. 그리고 ex1의 경우는 시그널을 사용한 반면 ex2는 variable을 선택해 사용했습니다. 여기서는 signal이나 variable을 써도
회로 설계에 큰 문제는 보이지 않습니다.  그럼 여기서 연산자에 대해서 살펴봅시다. 어느 것이 우선 순위가 높은지 알고 있어야 할
것입니다. 우선 순위를 잘못 정하면 자기 설계와 다른 형태로 바뀔 수 있습니다.우선 순위가 제일 높은 것은 기타연산자입니다. **, abs, not 가 있습니다. **는 지수 계산을 위한 연산자가 왼쪽 피연산자는 integer type이나 floating point type을 사용할 수 있지만 오른쪽 피연산자는 integer type만 가능합니다. 그 결과는 왼쪽 피연산자와 같은 type이 됩니다. abs는 절대값의 계산을 위하여 사용되며 모든 numeric 피연산자에 대해서 적용할 수 있습니다. not는 단항 연산자로서 피연산자의 논리값을 참이면 거짓으로, 거짓이면 참으로 바꾸는 역할을 합니다. 다음은 곱셈연산자입니다. *, /, mod, rem이 있습니다. 곱셈 연산자( * )와 나눗셈 연산자( / )는 왼쪽 및 오른쪽 피연산자는 같은 data type이어야 하며 integer type 또는 floating point type이 가능하고 그 결과도 피연산자와 같은 data type이 되어야 합니다. 나머지 계산( rem )과 모듈 계산( mod )의 경우에는 왼쪽 오른쪽 연산자 모두 integer type이어야 하고 그 결과도 integer type이고 그 결과도 integer type이 된다. A rem B는 A의 부호를 따르고 그 결과의 절대값은 B의 절대값을 따른다. 다음으로 우선 순위가 높은 것은 단항연산자가 있다. +/-의 보호를 나타내는 연산자이다. 그렇게 설명은 필요하지 않다고 본다. 다음은 덧셈연산자가 있다. 실제 연산을 수행하는 +/-와 &(접속 연산자)가 있다. 다음의 우선 순위가 있는 것은 관계연산자가 있다. =, /=. >, <, <= 등이 있다. 우선 순위가 가장 낮은 것은 논리연산자가 있다. or, and, nor, nand, xor, xnor 등이 있다.  우선 순위가 높다는 말은 중요한 말이다. 다음 예제에서 잠시 비교해 보자.  

s <= (a * b) * ( c * d)와  
r <= a * b * c * d이 서로 다른    
모양의 회로합성을 보여 주고 있다.  이 말은 signal의 결합 방법에 따라signal 전송 경로와 전파속도가 다르다.  즉 s <= (a * b) * ( c * d)이   r <= a * b * c * d 보다 신호의 전파경로가 짧고 평행을 이루어 좋은 회로 합성의 형태가 된다. 우선 순위에 따라 그 회로가 자기가 원하지 않는 형태로 변화될 수 있다는 것을 알고 있어야 한다.

 다음은 비트수를 확장해서 4비트 Adder를 설계해 보자.
ex3) 4bit Adder
library ieee;
use ieee.std_logic_1164.all;

entity adder4 is
port( cin : in std_logic;
      a, b : in std_logic_vector(3 downto 0);
      sum : out std_logic_vector(3 downto 0);
      cout : out std_logic);
end adder4;

architecture rtl of adder4 is
begin
   process(cin, a, b)
   variable carry : std_logic;
   begin
      carry := cin;
      for i in 0 to 3 loop
         sum(i) <= a(i) xor b(i) xor carry;
         carry  := (carry and (a(i) xor b(i))) or (a(i) and b(i));
      end loop;
      cout <= carry;
   end process;
end rtl;  

 이번 예제에서는 signal과 variable을 동시에 사용했습니다. 이런 식의 예제 구성이 실제적으로 많이 사용되고 있습니다. 앞에서도 for loop 구문을 사용한 적이 있습니다.

 그럼 Loop 문에 대해서 자세하게 알아봅시다. loop는 순차처리문이며 element를 반복적으로 처리하기 위한 구문이다. loop 문은 for loop 형식과 while loop 형식과 단순 loop 형식이 있다.

for 루프변수 in 범위시작 to 범위끝 loop
  순차저리문;
end loop;

while 조건 loop
  순차처리문;
end loop;

loop
   순차처리문;
end loop;

 for loop 문은 루프변수가 1씩 증가 또는 감소하면서 최종 값에 도달할 때까지 loop문에 둘러싸인 순차처리문을 반복 처리한다. 루프변수는 어떠한 객체로도 선언되지 않아야 되며 오직 for loop의 루프변수로만 사용되어야 한다. to가 사용되면 1씩 증가하면서 수행되고,  downto가 사용되면 1씩 감소하면서 수행한다.  while (조건) loop문은 조건이 참이면 loop에 둘러싸인 순차처리문을 반복 수행한다.while loop문의 조건은 반복회수가 명확히 결정되지 않으면 논리합성 할 수 없으므로 주의를 요한다.
 단순 loop 문은 무한히 반복되므로 loop를 빠져 나오기 위해서는 exit 문이 필요하며 while 문의 경우와 같이 반복회수가 정해지지 않을 경우에는 VHDL 논리합성이 될 수 없다. 대부분의 VHDL 합성기는 while loop 문과 단순 loop 문을 지원하지 않는다.

for i in 0 to 3 loop
   sum(i) <= a(i) xor b(i) xor carry;
   carry  := (carry and (a(i) xor b(i))) or (a(i) and b(i));
end loop;
 위의 예제를 while loop 바꾸어 보자.

while ( i <= 3) loop
   sum(i) <= a(i) xor b(i) xor carry;
   carry  := (carry and (a(i) xor b(i))) or (a(i) and b(i));
end loop;

ex4) 1bit 전가산기 설계
library ieee;
use ieee.std_logic_1164.all;

entity adder is
port ( a, b, c_in : in std_logic;
       s, c_out   : out std_logic);
end adder;

architecture rtl of adder is
begin
   s <= ((a xor b) xor c_in);
   c_out <= (a and b) or (a and c_in) or (b and c_in);
end rtl;      

ex5)
library ieee;
use ieee.std_logic_1164.all;

entity adder4 is
port ( a, b    : in std_logic_vector(3 downto 0);
      c_in    : in std_logic;
      sum    : out std_logic_vector(3 downto 0);
      cout    : out std_logic);
end adder4;

architecture rtl of adder4 is

signal temp1, temp2, temp3 : std_logic;

component adder
port( a, b, c_in : in std_logic;
      s, c_out   : out std_logic);
end component;

begin
   u1 : adder port map(a(0), b(0), c_in, s(0), temp1);
   u2 : adder port map(a(1), b(1), temp1, s(1), temp2);
   u3 : adder port map(a(2), b(2), temp2, s(2), temp3);
   u4 : adder port map(a(3), b(3), temp3, s(3), c_out);
end rtl;  
 우선 Adder의 component를 이용하였습니다. 우선 Adder.vhd 파일이 저장되어 있어야 합니다. 같은 디렉토리에 저장되어 있거나 user Library에 저장되어 있어야 합니다. 아니면 이것을 Package화 시켜서 이용할 수 도 있습니다.   adder 회로에서 입력이  a,  b,  c_in이고,  출력이 s, c_out입니다.
 
  u1 : adder port map ( a(0),  b(0),  c_in,  s(0),  temp1);
순서대로 연결되어 있는 것을 알 수 있습니까? 이처럼 component의 형식이름과 실제이름을 결합할 때 port signal이 나열된 위치 순서대로 연결시키는 방법을 위치결합(positional association mapping)이라고 합니다. 또 component의 형식 이름과 실제이름을 결합할 때 port signal이 나열된 위치에 상관없이 각각의 형식이름 => 실제이름으로 결합시키는 방법을 이름결합(named association mapping) 이라고 합니다. 직접 이름으로 연결되기 때문에 결합의 순서에는 상관없습니다.  port map을 조금 쉽게 말하면 schematic의 signal을 wire로 연결시키는 것으로 보시면 됩니다.  중요한 점은 component 이름은 반듯이 component 선언에서 선언된 이름이어야 합니다.
 
 다음으로 Pipelined adder 회로에 대해서 알아봅시다. 생각보다 어려운 회로는 아닙니다.
ex6) Pipelined adder
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity pipeadder is
port ( clk    : in std_logic;
       inbus  : in std_logic_vector(7 downto 0);
       outbus : out std_logic_vector(8 downto 0));
end pipeadder;

architecture rtl of pipeadder is
signal reg_a : std_logic_vector(7 downto 0);
signal reg_b : std_logic_vector(8 downto 0);
begin
  outbus <= reg_b;
  process(clk)
  begin
     if (clk='1' and clk'event) then
        reg_a <= inbus;
        reg_b <= ('0' & reg_a) + ('0' & inbus);
     end if;
  end process;      
end rtl;  
 signed package는 4칙 연산을 지원합니다. 입력이 8비트인데 비해 출력이 9비트입니다. 이유를 알겠습니까? 예를 들어 1비트 더하기 1비트를 하면 10이라는 2비트의 값을 가지는 것이 정상이죠. 이것을 다르게 표현한다면 결과 값은 8비트로 보내고 최상위 비트는 캐리로
보내는 것이 정상일 것입니다. ALU 회로 설계때는 플래그 레지스터에 결과를 저장하는 것을 확인할 수 있을 것입니다. 그렇게 표현하는 것이 당연합니다. 지금은 간단한 연습용 회로이지 실제적인 상용화될 수 있는 회로는 아닙니다.  덧셈과 뺄셈은 바늘 한 장의 차이입니다.    reg_b <= ('0' & reg_a) + ('0' & inbus);에서 ' + ' 대신에 ' - '를 사용하면 됩니다.그럼 여기서 덧셈과 뺄셈을 동시에 수행할 수 있는 회로를 설계해 봅시다.

ex7) Pipelined adder
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity pipeadder is
port ( clk, sel : in std_logic;
       inbus  : in std_logic_vector(7 downto 0);
       outbus : out std_logic_vector(8 downto 0));
end pipeadder;

architecture rtl of pipeadder is
signal reg_a : std_logic_vector(7 downto 0);
signal reg_b : std_logic_vector(8 downto 0);
begin
  outbus <= reg_b;
  process(clk)
  begin
     if (clk='1' and clk'event) then
        if (sel='1') then
           reg_a <= inbus;
           reg_b <= ('0' & reg_a) + ('0' & inbus);
        else
           reg_a <= inbus;
           reg_b <= ('0' & reg_a) - ('0' & inbus);
        end if;
     end if;
  end process;      
end rtl;      

 간단하게 sel이라는 입력 단자를 하나 추가함으로서 간단한 덧셈/뺄셈 회로를 설계할 수 있습니다. sel이 0이면 Adder의 기능을 수행하고 1이면 subtraction의 기능을 수행할 수 있습니다. VHDL을 어렵다고 생각하면 안 됩니다. 간단한 변환이 이렇게 다른 회로를 설계할 수 있습니다. 이것 말고도 다른 회로를 응용해 보시는 것은 VHDL에 좀더 가깝게 접근할 수 있을 것입니다.

 다음은 4bit BCD(Binary Coded Decimal) 덧셈기를 설계합시다. 지금은 간다하게 4비트의 Adder에서 계산된 값을 BCD로 변환시키는 회로를 설계해 봅시다. 여기서 사용되는 예제는 대부분 소스가 공개되어 있는 것입니다. 제가 조금씩 변형하는 경우도 있지만 대부분은 소스를 그대로 사용하고 있습니다. 제가 새롭게 소스를 설계한다면 너무 시간이 많이 걸립니다. 그 점은 여러분도 마찬가지일 것입니다.
 BCD 변환기에 대해서 한 번 생각해 봅시다. BCD 변환기의 특징은 무엇인가요?0에서 9까지의 계산은 일반적인 adder와 같습니다. 문제는 a(10), b(11), c(12), d(13), e(14), f(15)의 계산입니다. a를 어떻게 처리하면 되겠습니까? 간단합니다. a는 10을 나타냅니다. 10은 이진수로 1010입니다. 쉽게 10은 영의 자리숫자는 0이고 십의 자리는 1입니다. 십의 자리는 캐리를 말하면 됩니다. 그래서 a는"0000"으로 처리하고 캐리를 1로 정의하면 됩니다. b, c, d, e, f도 이런 식으로 정의하면 됩니다.   그렇게 어렵지는 않을 것입니다. 오늘은 여기까지입니다. 소스는 밑부분에 있습니다.


ex8)
library ieee;
use ieee.std_logic_1164.all;

entity bcdadder is
port ( s     : in std_logic_vector(3 downto 0);
       c_in  : in std_logic;
       s_out : out std_logic_vector(3 downto 0);
       c_out : out std_logic);
end bcdadder;

architecture rtl of bcdadder is
begin
  process(s, c_in)
  begin
     if (c_in='0') then
        if (s="1010") then
           s_out <= "0000";
           c_out <= '1';
        elsif (s="1011") then
           s_out <= "0001";
           c_out <= '1';
        elsif (s="1100") then
           s_out <= "0010";
           c_out <= '1';
        elsif (s="1101") then
           s_out <= "0011";
           c_out <= '1';
        elsif (s="1110") then
           s_out <= "0100";
           c_out <= '1';
        elsif (s="1111") then
           s_out <= "0101";
           c_out <= '1';
        else
           s_out <= s;
           c_out <= '0';
        end if;

     end if;
  end process;      
end rtl;      


ex1) 4×4 Multiplier
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity multi is
port ( a, b : in std_logic_vector(3 downto 0);
       prod : out std_logic_vector(7 downto 0));
end multi;

architecture rtl of multi is
signal p0,p1,p2,p3 : std_logic_vector(7 downto 0);
constant zero : std_logic_vector := "00000000";      
begin
   process(a,b)
   begin
      if (b(0)='1') then p0 <= ("0000" & a);
      else p0 <= zero;
      end if;
      if (b(1)='1') then p1 <= ("000" & a & '0');
      else p1 <= zero;
      end if;
      if (b(2)='1') then p2 <= ("00" & a & "00");
      else p2 <= zero;
      end if;
      if (b(3)='1') then p3 <= ('0' & a & "000");
      else p3 <= zero;
      end if;
      prod <= (p3 + p2) + (p1 + p0);
   end process;
end rtl;      

 일단 원리를 생각해봅시다.
예를 들어 설명하겠습니다.
                     1 1 0 1     -- 입력 a
               ×    1 0 1 1     -- 입력 b
                     1 1 0 1     -- b(0)가 0이 아니므로  -- p0
                   1 1 0 1       -- b(1)가 0이 아니므로  -- p1
                 0 0 0 0         -- b(2)가 0이므로       -- p2
               1 1 0 1           -- b(3)가 0이 아니므로  -- p3
             1 0 0 0 1 1 1 1
 결과는 무조건 8비트를 초과할 수 없습니다. 결과의 8비트를 맞추어주기 위해서는 비트 결합 & 연산자를 사용합니다. 비트수는 정확히 맞추어 주어야 합니다. 이런 4단계의 연산을 이용해서 p0, p1, p2, p3을 마지막으로 더해줍니다. 그런데 우선 순위를 생각해서 2단으로 구성되었습니다. 만약 괄호가 없다면 지연속도가 조금 많아질 것입니다. 그런 미세한 부분까지 설계해야 좋은 시스템을 만들 수있습니다.
 어려운 예제는 아니었다고 생각되지만 이런 최적화된 곱셈기라고 정의할 수는 없습니다. 만약 속도 문제만을 최우선으로 설계한다면 다른 모양의 설계가 가능합니다. 다만 Area가 증가하겠지요. 여러분도 어느 정도의 Know-how가 생긴다면 알파칩을 능가할 회로를 설계
해 보십시오. 최적화된 알고리즘을 이용하면 됩니다. 그 설계는 우리의 과제입니다. 제가 강의하고 있는 예제는 대부분 컴파일과정을 거쳐 에러를 모두 수정한 예제입니다. 시뮬레이션까지 해보는 회로도 있지만 해보지 않는 회로도 많습니다. 여러분은 시뮬레이션까
지 꼭 해보십시오. 모든 경우를 다해보지는 못하겠지만 할 수 있는 정도까지는 해보아야 합니다. 시작과 끝 그리고 상태가 변하는 부분은 세밀하게 검토하고 넘어가는 습관을 가지기를 바랍니다.  
 T flipflop은 입력 t가 '1'일 때 클럭의 상승에서 출력 q가 토글(toggle)되어 반전된다. 만약 이 때 입력 t가 '0'이면 출력 q는 변하지 않는다.  그렇게 많이 사용되지는 않습니다. 대부분의 회로는 면적 때문에 D flipflop을 많이 이용하고 있습니다. 기능상의 문제는 조금 떨어지는 면이 있지만 회로 최적화라는 문제 때문에 DFF을 사용합니다.


ex2) T Flipflop
library ieee;
use ieee.std_logic_1164.all;

entity t_ff is
port ( t, clk   : in std_logic;
          q   : buffer std_logic);
end t_ff;

architecture rtl of t_ff is
begin
   process(clk)
   begin
      if (clk='1' and clk'event) then
         if (t='1') then
            q <= not(q);
         else
            q <= q;  
         end if;
      end if;
   end process;
end rtl;

 포트에서 q를 buffer 모드로 설정했습니다. feedback을 허용하는 모드로 설정했습니다. q <= q; 자기 자신으로 assign 되기 위해서는 버퍼 모드로 설정되어야 합니다.   3상태 버퍼에 대해서 알아봅시다. 대부분의 게이트는 On이 되거나 Off가 되어 회로 연결 상태를 보여줍니다. Totem-pole의 경우 아래쪽 트랜지스터가 차단되면 High 상태의 전압을 가지고 반대로 위쪽 트랜지스터가 차단될 경우 Low 상태의 전압을 가진다. 그러나 특이한 경우로 양쪽 트랜지스터가 차단될 경우 제3의 상태 즉 개방회로를 가집니다. 즉 높은 임피던스 상태를 제공하여 공통선에 많은 출력을 직접 결선형으로 연결할 수 있게 합니다. 대부분의 3상태 게이트의 중요한 특징은 출력 인에이블 지연(output enable delay)이 출력 디스에이블 지연(output disable delay)보다 길다는 점입니다.
   
    A                 Y    C가 High이면  Y = A 이고
                            C가 Low이면   Y = High Impedance
    C    

 이론은 이 정도로 하고 어떻게 구현하는지 살펴봅시다.
예제는 2가지로 기술하겠습니다. 병렬적 처리와 순차적 처리로 정의하겠습니다.

ex3) Tri-state Buffer
library ieee;
use ieee.std_logic_1164.all;

entity tristate is
port ( e, a : in std_logic;
        y   : out std_logic);
end tristate;

architecture rtl of tristate is
begin
   process(e, a)
   begin
      if (e='1') then
         y <= a;
      else
         y <= 'Z';
      end if;
   end process;
end rtl;

 어느 정도의 기능만 알고 있다면 정의하기는 쉽습니다. 여기서 ' Z '는 nine values에서
High Impedance를 나타냅니다.
 
ex4) Tris-state Buffer
library ieee;
use ieee.std_logic_1164.all;

entity tristate1 is
port ( e, a : in std_logic;
        y   : out std_logic);
end tristate1;

architecture rtl of tristate1 is
begin
   y <= a when (e='1') else 'Z';
end rtl;

 어떤 때는 when - else 구문을 사용하면 회로가 간결하게 표현되는 장점이 있습니다.

 다음은 입출력 버퍼에 대해서 알아보겠습니다.
                e                          
    a                         y              e가 1이면 y <= a가 되고  
                                             e가 0이면 y는 high Impedance
                                             e가 1과 0이외에는 Unknown 상태
    b                                        (e는 std_logic의 nine value를 가지므로)

 y는 inout 모드로 설정되어야 한다. 그 이유는 회로의 원리를 자세히 보기를 바란다.

ex5) Bi-directional Buffer
library ieee;
use ieee.std_logic_1164.all;

entity bidir is
port (   y   : inout std_logic;
       e, a  : in std_logic;
         b   : out std_logic);
end bidir;

architecture rtl of bidir is
begin
   process(e, a)
   begin
      case e is
         when '1' => y <= a;
         when '0' => y <= 'Z';
         when others => y <= 'X';
      end case;
   end process;
   b <= y;      
end rtl;  

 일부 툴중에는 device의 영향으로 inout 모드 대신에 buffer 모드로 설정해야 하는 경우도 있습니다.

 마지막으로 shift counter와 레지스터의 설계에 대해서 잠시 알아보겠습니다.레지스터 부분은 메모리 회로 설계에서 다루어야 하지만 여기서 잠시 범용적으로 많이 쓰이는 8비트 레지스터에 대해서 알아보겠습니다. 레지스터는 데이터의 로드가 가능해야 합니다.



ex6) 8 bit Register
library ieee;
use ieee.std_logic_1164.all;

entity register1 is
port ( enable, load, clk : in std_logic;
       reset  : in std_logic;
       regin  : in std_logic_vector(7 downto 0);
       loaddata : in std_logic_vector(7 downto 0);
       regout : out std_logic_vector(7 downto 0));
end register1;

architecture rtl of register1 is
signal gatedclk : std_logic;
begin
   gatedclk <= enable and clk;
   process(gatedclk, load, reset, enable, clk)
   begin
      if (reset='1') then
         regout <= "00000000";
      elsif (gatedclk='1' and gatedclk'event) then
         if (load='1') then
            regout <= loaddata;
         else
            regout <= regin;
         end if;
      end if;          
   end process;
end rtl;  

 reset이 1이면 모든 회로는 초기 치로 set됩니다. 당연히 두 개가 되어야 합니다. 레지스터는 자기가 가지고 있는 입력이 있고, 새로운 값이 로드될 수 있는 기능을 수행해야 하므로 입력이 두 개로 되어 있습니다. 만약 Common bus를 가지고 있다면 입력이 하나로도 충분
히 가능하다고 생각됩니다. 그렇지만 여기서는 두 개의 입력을 가지고 있습니다. 로드 신호가 있느냐  없느냐에 따라서 레지스터 출력 값이 결정됩니다. 회로 원리만 이해하고 있어도 코딩은 별로 어렵지 않습니다. 조금 복잡한 시스템을 설계하다보면 가장 많이 사용되는 회로가 레지스터입니다.


ex7) Shift Register
library ieee;
use ieee.std_logic_1164.all;

entity shiftreg is
port ( enable, load, clk : in std_logic;
       din    : in std_logic;
       regin  : in std_logic_vector(7 downto 0);
       mode   : in std_logic;
       regout : out std_logic_vector(7 downto 0));
end shiftreg;

architecture rtl of shiftreg is
signal gatedclk : std_logic;
signal tmp : std_logic_vector(7 downto 0);
begin
   gatedclk <= enable and clk;
   regout <= tmp;
   process(gatedclk, din, load, mode, clk)
   begin
      if (gatedclk='1' and gatedclk'event) then
         if (load='1') then
            tmp <= regin;
         elsif (mode='0') then
            tmp <= tmp(6 downto 0) & din;
         else
            tmp <= din & tmp(7 downto 1);
         end if;
      end if;          
   end process;
end rtl;      

 위의 예제와 조금 다른 부분이 있다면 mode 부분일 것이다. mode 선택에 따라서 shift left와 shift right의 기능을 수행한다. 비트 결합 연산자 &를 사용하면 간단하게 shift register를 설계할 수 있다.

   tmp <= tmp(6 downto 0) & din;  -- shift left
   tmp <= din & tmp(7 downto 1);  -- shift right
 회로를 조금만 변형한다면 아주 재미있게 바꿀 수 있다. shift rotate의 기능을 수행하게 할 수도 있다.
   tmp <= tmp(6 downto 0) & tmp(7);  -- shift rotate left
   tmp <= tmp(0) & tmp(7 downto 1);  -- shift rotate right
 


 그럼 FSM(Finite State Machine)에 대해서 알아보겠습니다.


1. 디지털 하드웨어를 설계할 때 제어신호를 생성하는 제어기는 FSM을 규정되며 FSM의 동작표현은 state transition diagram 또는 state transition table 등으로 구현됩니다.2. FSM은 state 변수를 기억하는 레지스터 블록과 state 변수의 천이를 표현하는 함수와 출
력 값을 결정하는 조합논리 회로로 구성된다.   State Machine은 크게 Mealy Machine과 Moore Machine으로 구분됩니다. Mealy machine은 출력이 현재상태와 현재입력에 의존하는 State Machine이고, Moore Machine은 출력이 현재상태에만 의존하는 State Machine을 말한다. Mealy Machine은 순차회로의 출력이 현재의 상태(state)와 입력에 따라 결정되는 것을 말합니다.
                                               
                                                             Output    Output
  Input               State               State              Logic
                      Logic              Memory

                     Current State
 

Input        Next State           Current State                Output
                Logic       Next     Register                    Logic      Output
           (Combinatorial)  State  (Sequential)    Current (Combinatorial)
                                                      State

 장점은 Moore Machine에 비해 State 수가 작다는 점입니다. 개념은 이 정도로 이해하고 실제 예제로 이해해 봅시다.
 State Machine의 설계는 어떤 회로의 설계를 정하고 상태도나 상태표를 먼저 구현합니다.
                                                  X/Y
            1/0            1/0           1/0
      S0            S1     -     S2           S3
                     
                        1/0
                       

  State를 최소한으로 출이는 것은 당연한 것이겠죠. state 수를 줄이는 방법은 몇 가지가 있습니다. 그 방법은 여러분이 직접.  
 위의 상태표를 보고 직접 Coding 작업을 해야 합니다. 어렵다고 생각하시지 마시고 천천히 시작해 보십시오. State Machine은 처음이라서 조금 어렵겠지만 자기 스스로 한 번 설계해 보시고 아래의 코딩과 비교해 보시기를 바랍니다.


ex1) Mealy Machine1
library ieee;
use ieee.std_logic_1164.all;

entity fsm1 is
port ( x, clk : in std_logic;
        z    : out std_logic);
end fsm1;

architecture rtl of fsm1 is
type state is (s0, s1, s2, s3);
signal st : state;
begin
   process(clk)
   begin
      if (clk='1' and clk'event) then
         if (x='0') then z <= '0';
         else
            case st is
               when s0 => st <= s1;
                    z <= '0';
               when s1 => st <= s2;
                    z <= '0';
               when s2 => st <= s3;
                    z <= '0';
               when s3 => st <= s0;
                    z <= '1';
            end case;
         end if;
      end if;
   end process;
end rtl;

 자 이제 분석을 한 번 해봅시다.
type state is (s0, s1, s2, s3);
signal st : state;
 state를 새로운 data type으로 정의했습니다. s0, s1, s2, s3를 순서대로 정의해주어야 됩니다. 시뮬레이션 시에 초기화하기 위해서도 반드시 state 순서를 정의해 주어야 합니다. 이 부분이 state machine의 최적화에 큰 영향을 미칩니다. FF의 초기상태를 알기 위해 reset
단자를 추가해 initial state를 만들어 주어야 합니다. 반드시 초기화 회로를 만들어 주는 것이 좋습니다.when s0 => st <= s1; z <= '0';
 네 가지의 정의가 있지만 한 가지만 이해하면 다른 부분은 쉽게 이해가 될 것입니다. S0는 Current State를 나타내고 S1은 Next State를 나타냅니다. S0의 State를 S1의 State로 보내고 Z의 출력 값을 0으로 출력합니다. 여기서는 큰 변수가 없으므로 순차적인 진행을
나타냅니다. 다음의 결과를 봅시다.


when s3 => st <= s0; z <= '1';
이 상태에서 z의 값이 1로 변하는 것을 볼 수 있을 것입니다.

 위의 예제보다는 밑에 조금 변형되어 있는 회로 설계 방법이 조금 좋다고 생각합니다. FSM을 합성할 때 FSM에서의 설계의 동기회로 부분(Synchronous)을 조합회로 부분(Combinatorial)과 분리함으로써 순차회로와 조합회로의 설계를 용이하게 할 뿐 만 아니라
설계의 수정이나 오류 정정이 훨씬 간단하다는 장점을 가지고 있습니다.

ex2) Mealy Machine
library ieee;
use ieee.std_logic_1164.all;

entity fsm2 is
port ( x, clk : in std_logic;
         z    : out std_logic);
end fsm2;

architecture rtl of fsm2 is
type state is (s0, s1, s2, s3);
signal current_st, next_st : state;
begin
   comb : process(current_st, x)
   begin
      case current_st is
         when s0 =>
            if (x='0') then
               z <= '0';
               next_st <= s0;
            else
               z <= '0';
               next_st <= s1;
            end if;
         when s1 =>
            if (x='0') then
               z <= '0';
               next_st <= s1;
            else
               z <= '0';
               next_st <= s2;
            end if;
         when s2 =>
            if (x='0') then
               z <= '0';
               next_st <= s2;

            else
               z <= '0';
               next_st <= s3;
            end if;
         when s3 =>
            if (x='0') then
               z <= '0';
               next_st <= s3;
            else
               z <= '0';
               next_st <= s0;
            end if;
      end case;
   end process;

   Synch : process(clk)
   begin
      if (clk='1' and clk'event) then
         current_st <= next_st;
      end if;  
   end process;  
end rtl;
type state is (s0, s1, s2, s3);
signal current_st, next_st : state;

 새로운 data type s0, s1, s2, s3를 정의하고 이것에 대한 state를 두 개로 표시했습니다.위의 예제는 current state와 next state를 구분하기가 어려웠는데 지금은 현재의 상태를 훨씬 구분하기가 편하게 되어 있습니다. 그리고 process 구문을 한 개에서 두 개로 정의했습니다. 몇 개의 process를 쓰든 상관은 없습니다만 시스템 최적화를 위해서는 한 개의 process 보다는 두 개의 process로 state machine을 구현하는 것이 훨씬 좋다고 생각합니다. 너무 많은 프로세서 문을 사용하는 것은 좋지 않습니다. state machine의 설계에서는 2개내지 3개 정도가 적당하다고 생각합니다.(제 경험으로는) 그리고 이번에는 process 문에 라벨을 사용했습니다. process 문의 구분을 위한 것이므로 시스템에는 아무 영향을 주지 않습니다.
 Synch : process(clk)
         begin
            if (clk='1' and clk'ev

ent) then
               current_st <= next_st;
            end if;  
         end process;  
 전에도 잠깐 설명했습니다만 process(clk) 여기서 clk가 sensitivity list라고 설명했습니다. 이것을 사용하지 않는 방법도 있습니다. wait until 구문을 이용해서 sensitivity list를 대치하는 방법을 소개해 드리겠습니다. wait until 구문은 구문 다음에 오는 상황에 따라서 변합니다. 다음에 변하는 부분이 있을 때까지는 대기하고 있습니다.
Synch : process(clk)
        begin
           wait until (clk='1' and clk'event);
           current_st <= next_st;
        end process;
 위에서 보면 클럭의 변화가 있기 전까지는 기다리고 있습니다. 클럭의 변화가 있으면  current_st <= next_st;을 수행합니다.


 다음 예제는 reset을 가지고 있는 state machine입니다.
 상태도를 먼저 봅시다.
                     1/0          X/Z
        Reset           S0
                     
              0/1      0/0      0/1
                       
               S1      1/1       S2
                       1/0

ex3) State Machine -- Mealy Machine
library ieee;
use ieee.std_logic_1164.all;

entity fsm3 is
port ( reset, x, clk : in std_logic;
         z    : out std_logic);
end fsm3;

architecture rtl of fsm3 is
type state is (s0, s1, s2);
signal c_state, n_state : state;
begin
   Synch : process(clk, reset)
   begin
      if (reset='0') then
         c_state <= s0;
      elsif (clk='1' and clk'event) then
         c_state <= n_state;
      end if;  
   end process;
   
   comb : process(c_state, x)
   begin
      case c_state is
         when s0 => z <= '0';
            if (x='0') then
               n_state <= s0;
            else
               n_state <= s1;
            end if;
         when s1 => z <= '0';
            if (x='0') then
               n_state <= s0;
            else
               n_state <= s2;
         

   end if;
         when s2 =>
            if (x='0') then
               z <= '1';
               n_state <= s0;
            else
               z <= '1';
               n_state <= s1;
            end if;
      end case;
   end process;
end rtl;

 위의 예제와 비교해서 조금 다른 면을 볼 수 있을 것입니다. Reset 기능을 가지고 있습니다. 그리고 일방적인 state의 흐름이 아니라 양방향으로 변한다는 점입니다. 예제로서 좋다고 생각됩니다.

 이 예제는 조금 자세하게 분석하겠습니다.
comb : process(c_state, x)
 위 process 구문은 state 변수를 기억하는 레지스터에 대한 표현을 위해 사용되었다.
Synch : process(clk, reset)
 위 process 구문은 state 변수의 천이와 출력 값의 결정을 위한 함수의 표현을 위해 사용되었습니다.
 결과는 다음과 같습니다.
 

type state is (s0, s1, s2);
signal c_state, n_state : state; 우리는 State Machine의 개념을 도입하여 설계했습니다. 그냥 Binary Coding으로 설계한
다면 다음과 같습니다. 우선 type 선언문을 삭제하고 constant로 정의하면 됩니다.

constant s0 : std_logic_vector(1 downto 0) := "00";
constant s1 : std_logic_vector(1 downto 0) := "01";
constant s2 : std_logic_vector(1 downto 0) := "10";

signal c_state, n_state : std_logic_vector(1 downto 0);
 그렇지만 Binary coding으로 설계하는 것보다 state machine을 설계하는 것이 최적화의 도움을 줍니다. 시스템을 최적화시키는 알고리즘이 Binary coding보다는 state machine 쪽이 더 잘되어 있다고 합니다.


 다음은 Moore Machine에 대해서 알아보도록 하겠습니다.Moore Machine : 순차회로의 출력이 입력과 관계없이 현재의 상태의 함수로만 결정됩니다.

                 Input과 무관하므로 glitch가 덜 발생한다는 장점이 있습니다.
   
 Input          State            State              Output           Output
                Logic           Memory             Logic

                 Current State

조금 다른 개념으로 알아봅시다.

Input        Next State           Current State                Output
                Logic       Next     Register                    Logic      Output
           (Combinatorial)  State  (Sequential)            (Combinatorial)
                                                     
                      Current  State

 조금 어렵지 않습니까? 저도 state machine을 설계하다보면 이것이 Mealy Machine인지 아니며 Moore machine인지 알 수 없을 때가 있습니다. 너무 개념이 어렵다고 생각하시지 마시고 지금은 그냥 차이점 정도만 알아두시는 것이 좋을 것 같습니다.

 다음 예제를 Moore Machine으로 설계해 봅시다.
       
        Reset='1'
                         110
           010                        001
         

            111                       101

                         011

 state의 상태도의 순서가 조금 다릅니다. 이런 식의 설계도 가능합니다. 다만 순서의 영향
을 조금 받는다는 점입니다.


ex4) Moore Machine
library ieee;
use ieee.std_logic_1164.all;

entity fsm4 is
port ( reset, clk : in std_logic;
       ph1, ph2, ph3 : out std_logic);
end fsm4;

architecture rtl of fsm4 is
constant s0 : std_logic_vector(2 downto 0) := "110";
constant s1 : std_logic_vector(2 downto 0) := "010";
constant s2 : std_logic_vector(2 downto 0) := "111";
constant s3 : std_logic_vector(2 downto 0) := "011";
constant s4 : std_logic_vector(2 downto 0) := "101";
constant s5 : std_logic_vector(2 downto 0) := "001";
signal c_state, n_state : std_logic_vector(2 downto 0);
signal tmp_ph3 : std_logic;
signal ph : std_logic_vector(2 downto 0);
begin
   p1 : process(clk, reset)
   begin
      if (reset='1') then
         c_state <= s0;
      elsif (clk='1' and clk'event) then
         c_state <= n_state;
      end if;  
   end process;
   
   p2 : process(c_state)
   begin
      case

c_state is
         when s0 => ph <= s0;
               n_state <= s1;
         when s1 => ph <= s1;  
               n_state <= s2;
         when s2 => ph <= s2;
               n_state <= s3;
         when s3 => ph <= s3;
               n_state <= s4;
         when s4 => ph <= s4;
               n_state <= s5;
         when others => ph <= s5;
               n_state <= s0;      
      end case;
      ph1 <= ph(2);
      ph2 <= ph(1);
      tmp_ph3 <= ph(0);
   end process;

   p3 : process(clk)
   begin
      if (clk='0' and clk'event) then
         ph3 <= tmp_ph3;
      end if;
   end process;      
end rtl;

 여기에는 3가지의 process 구문이 사용되었습니다. 2개의 프로세서 구문을 이용하여 설계가 가능하지만 ph3은 하강 에지에서 동작하도록 설계되었습니다. 이처럼 상승 에지와 하강  에지를 동시에 이용하는 설계도 가능합니다.  다음 결과에서 보면 ph1과 ph2는 상승 에지에서 동작하는 것을 볼 수 있고, ph3은 하강 에지에서 동작하는 것을 알 수 있습니다.


 110 → 010 → 111 → 011 → 101 → 001
  6  →  2  →  7  →  3  →  5  →  1 로 변하는 것을 C_state의 변화로 알 수 있습니다. 결과는 정상적이라는 말입니다. 그러면 동작점을 살펴봅시다. ph1과 ph2가 상승 에지에서 변하는 지를 위 그림에서 확인해보세요.

 아직까지는 그렇게 차이점을 이해하기 힘들 것입니다. 그럼 같은 예제를 두 가지로 표현해 보겠습니다. 조금 복잡한 예제입니다. 그렇게 어렵지는 않습니다.

                                           
           00/0              00/0               x1/0
                   ST0                 ST1
           10/1               10/1                          
          0x/0    01/1                    0x/0      10/0
                                    11/1
         ST4                                         ST2
11/1
                x1/1                        1x/1
                             ST3          
                                  x0/1

 다음은 위의 상태도를 중심으로 설계한 예제를 보여줍니다.


ex) Mealy FSM
library ieee;
use ieee.std_logic_1164.all;

entity fsm5 is
port ( reset, clk : in std_logic;
       data_in : in std_logic_vector(1 downto 0);
       data_out : out std_logic);
end fsm5;

architecture rtl of fsm5 is
type state is (st0, st1, st2, st3, st4);
signal c_state, n_state : state;
begin
   statereg: process(clk, reset)
   begin
      if (reset='1') then
         c_state <= st0;
      elsif (clk='1' and clk'event) then
         c_state <= n_state;
      end if;  
   end process statereg;
   
   fsm : process(c_state, data_in)
   begin
      case c_state is
         when st0 =>
            case data_in is
               when "00" => n_state <= st0;
               when "01" => n_state <= st4;
               when "10" => n_state <= st1;
               when "11" => n_state <= st2;
               when others => n_state <= null;
            end case;  
         wh

en st1 =>
            case data_in is
               when "00" => n_state <= st0;
               when "10" => n_state <= st2;
               when others => n_state <= st1;
            end case;  
         when st2 =>
            case data_in is
               when "00" => n_state <= st1;
               when "01" => n_state <= st1;
               when "10" => n_state <= st3;
               when "11" => n_state <= st3;
               when others => n_state <= null;
            end case;
         when st3 =>
            case data_in is
               when "01" => n_state <= st4;
               when "11" => n_state <= st4;
               when others => n_state <= st3;
            end case;
         when st4 =>
         

   case data_in is
               when "11" => n_state <= st4;
               when others => n_state <= st0;
            end case;  
         when others => n_state <= st0;
      end case;
   end process fsm;
   
   output : process(c_state, data_in)
   begin
      case c_state is
         when st0 =>
            case data_in is
               when "00" => data_out <= '0';
               when others => data_out <= '1';
            end case;
         when st1 => data_out <= '0';
         when st2 =>
            case data_in is
               when "00" => data_out <= '0';
               when "01" => data_out <= '0';
               when others => data_out <= '1';
            end case;
         when

st3 => data_out <= '1';
         when st4 =>
            case data_in is
               when "10" => data_out <= '1';
               when "11" => data_out <= '1';
               when others => data_out <= '0';
            end case;
         when others => data_out <= '0';
      end case;
   end process output;                  
end rtl;

ex6) Moore FSM
library ieee;
use ieee.std_logic_1164.all;

entity fsm6 is
port ( reset, clk : in std_logic;
       data_in : in std_logic_vector(1 downto 0);
       data_out : out std_logic);
end fsm6;

architecture rtl of fsm6 is
type state is (st0, st1, st2, st3, st4);
signal c_state, n_state : state;
begin
   statereg: process(clk, reset)
   begin
      if (reset='1') then
         c_state <= st0;
      elsif (clk='1' and clk'event) then
         c_state <= n_state;
      end if;  
   end process statereg;
   
   fsm : process(c_state, data_in)
   begin
      case c_state is
         when st0 =>
            case data_in is
               when "00" => n_state <= st0;
               when "01" => n_state <= st4;
               when "10" => n_state <= st1;
               when "11" => n_state <= st2;
               when others => null;
            end case;  
         when st1 =>

            case data_in is
               when "00" => n_state <= st0;
               when "10" => n_state <= st2;
               when others => n_state <= st1;
            end case;  
         when st2 =>
            case data_in is
               when "00" => n_state <= st1;
               when "01" => n_state <= st1;
               when "10" => n_state <= st3;
               when "11" => n_state <= st3;
               when others => null;
            end case;
         when st3 =>
            case data_in is
               when "01" => n_state <= st4;
               when "11" => n_state <= st4;
               when others => n_state <= st3;
            end case;
         when st4 =>
            case data_in is
   

            when "11" => n_state <= st4;
               when others => n_state <= st0;
            end case;  
         when others => n_state <= st0;
      end case;
   end process fsm;
   
   output : process(c_state)
   begin
      case c_state is
         when st0 => data_out <= '1';
         when st1 => data_out <= '0';
         when st2 => data_out <= '1';
         when st3 => data_out <= '0';
         when st4 => data_out <= '1';
         when others => data_out <= '0';
      end case;
   end process output;                  
end rtl;



 

 그럼 이만 펑~~~~ 채택~~

<FORM style="DISPLAY: none" name=scrapFrm action=/post/scrap/scrapPop.jsp method=post>                       </FORM><FORM style="DISPLAY: none" name=scrapFrmCafe action=/ScrapToCafe.nhn method=post>                         </FORM>

의견 쓰기

질문자 선택

re: Xilinx의 VHDL질문

cjfdn741

답변채택률 7.7%

2007.11.05 20:20

 VHDL  (Very high speed integrated circuit Hardware Description Language)

 - HDL은 하드웨어를 기술하는 언어이다.

 VHDL 소개

  HDL이전의 하드웨어 설계에서는 주로 레이아웃 편집기(layout editor)나 스키메틱 편집기(schematic editor)를 이용해 작은 블록을 설계하고 이것을 이용해 큰 블록을 설계하는 상향식 설계(bottom-up)를 했다. 하지만 설계해야 할 회로의 규모가 커지고 복잡도 가 증가 함에 따라 이러한 방법은 한계에 도달하게 되었다. 따라서 알고리즘이나 기능레벨에서 설계가 가능하도록 하는 HDL이 출현하게 되었다. HDL을 통해 회로를 설계하는 방식을 하향식(top-down)설계 방식이라 한다.


집적회로 설계의 변천과정
 제 1 단계  (60년 ~ 70년대)
 제 2 단계  (80년대)
 제 3 단계  (90년대)
 
설계방법
 트랜지스터 레벨의 레이아웃 설계 (상향식 설계)
 게이트나 RTL 레벨의 논리설계.  알고리즘이나 기능 레벨의 설계 (하향식 설계)
 
설계도구
 레이아웃 편집기  스키메틱 편집기  HDL과 합성
 
설계범위
 SSI, MSI (103게이트 이하)
 LSI, VLSI (103 ~ 105게이트)
 VLSI, GSI (105 게이트 이상)
 
설계 예
 게이트, 카운터, 멀티플렉서, 가산기, 마이크로프로세서, 주변장치, 고성능 마이크로프로세서, 실시간 영상처리
 

  HDL은 상위수준의 하드웨어 기술언어이기에 보다 낮은 레벨로 바꾸는 과정이 반드시 필요하게 된다. 이러한 과정을 합성(synthesis)라 한다.  HDL로 기술된 회로의 기능을 시뮬레이션 할 때는 합성까지는 필요없으나 실제 지연이나 타겟 소자(PLD, ASIC...)등의 크기와 특성을 고려한 시뮬레이션 할 때는 합성의 과정을 해 주어야 한다.  PLD(Altera, xilinx, ...)등은 전용 시뮬레이터가 있어서 쉽게 합성할 수 있다.

 1986년 3월부터 VHDL을 IEEE표준으로 제정하기 위한 노력이 기울여져 1987년 12월에 IEEE-1076이라는 IEEE표준 VHDL이 탄생했다. 1991년에는 IEEE1076에 추가하여 설계자들로 하여금 VHDL 모델을 공유하는데 도움을 주고 또한 합성 기능의 강화를 위해 9개로 구성된 표준 논리 레벨 MVL9('U', 'X', '0', '1', 'Z', 'W', 'L', 'H')를 정의한 IEEE1164(std_logic_1164)를 발표하였다. 1992년에는 VHDL이 미국 정부지원 공인 HDL(FIPS Pub172)로 정해졌으며 미국 정부와 하드웨어 개발을 계약하거나 표현하는 경우에는 반드시 사용해야 하는 유일한 표준언어가 되었다. 아울러 VHDL의 기능을 개선하기 위한 노력이 기울어져 1993년에는 VHDL1076-1987에 대한 새로운 버전인 IEEE1076-1993을 내놓게 되었다.

 VHDL을 시뮬레이션하고 합성하는 Tool은 대표적으로 Synopsys, Cadence, Compass, Mentor Graphics,... 등이 있고 PLD에서 이용되는 전용 시뮬레이터에는 Altera MAX+, Xilinx,.....등이 있으며 이외에도 기능 시뮬레이션에서 쓰이는 ActiveVHDL, Model tech(V system)등이 있다.


VHDL 개요

 전자 산업은 곧 부품산업이라고 해도 무리가 없는듯하다. 그중에서도 반도체분야는부품산업의 꽃이라고 할수 있다. 그러나 가치가 있는 만큼 어려움이 따르는것은당연한 이치라고 생각한다. 종래의 반도체 설계는 주로 숙련된 엔지니어가 schematic capture를 이용하였으나, time-to-market과 설계의 복잡도 증가로 새로운 방법이나타나게 되었는데 그것이 바로 (V)HDL이다.

1. (V)HDL이란?

HDL은 Hardware Description Language의 이니셜 문자이고 하드웨어 기술(표현) 언어라고 한다.이것은 타겟 프로젝트의 동작 특성을 문법을 갖는 언어로 표현(기술) 한다는 것을 의미한다. 동작 특성이라고 하는것은 일반적으로 spec., datasheet, idea등이 될수 있다.

즉, 종래에는 어떤 기능블럭을 설계할때 AND,OR,MUX,F/F등을 이용하여 회로를 구성하였으나 지금은 일반적인 프로그래밍 개념을 접목한 HDL을 이용하는데 그 대표적인 것이 VHDL과 Verilog-HDL이다. HDL이란 이와 같이 동작특정을 정해진 문법과 키워드 그리고 사용자 정의 객체들을 가지고 기술(description)하는 것이다. 본강좌의 주제인VHDL은 회로의 연결 정보를 포함할 뿐만아니라 C와 같은 프로그래밍 언어의 성격도 가지고 있어서 매우 다양한 하드웨어 기술 방법을 제공한다. HDL이 C와같은 프로그래밍 언어와 다른점은 프로그래밍 언어는 전부 순차구문(sequential statements)으로 구성 되어 있지만 HDL은순차구문 이외에 병렬구문(concurrent statements)과 타이밍 개념이 있는것이 차이점이다.


2. HDL의 종류

1) Verilog-HDL : HILO-HDL(GenRAD사)을 기본으로 만들어진 HDL로서 RTL특성이 강하여하드웨어에 가까운 문법과 구조로 이루어져 있다. 초보자에게 다소 접근이 용이한 언어이다.

2) AHDL : '80년대에 IBM에서 교육용으로 사용되다가 Altera사의 Maxplus에 접목하여사용되고 있는 언어이다.

3) UDL/I : RTL위주로 되어 있으며, 일본에서 VHDL에 대응하기 위해 만들어낸언어이다.

4) 기타 CDL,DDL,ISP,PMS등 교육용과 회사 내부용으로 여러가지가 있다.


3. VHDL의 역사적 배경

보다 대형화 및 복잡화하는 소프트웨어를 설계하기 위해 초창기 어셈블리 언어에서 지금은FORTRAN,PASCAL,C,LISP와 같은 하이레벨 프로그래밍 언어를 사용하듯이, 하드웨어 설계에 있어서도전통적인 schematic capture방법 대신에 CAD TOOL상에서 VHDL과 같은 HDL을 이용하여 TOP-DOWN 설계 방식을적용하게 되었다. 이러한 방법은 설계기간을 단축할수 있을뿐만 아니라 설계 데이타의 관리, 교환, 재사용등에 훨씬 용이하게 되었다.

이러한 이유로 미국방성(DoD)에서 VHSIC(Very High Speed Integrated Circuit) 프로그램을 수행하는 과정에서 VHDL이 공식 논의되기 시작하였다.(1981년)1983년에 VHDL에 대한 제안요청은 미공군이 작성하였고, 같은해 IBM,TI,Intermetrics사가 주축이 되어 1985년에 VHDL 7.2 버전을 발표하게 되었다.

1987년 12월에 IEEE에서 IEEE Standard 1076-1987로 확정되었다. 이후 계속된 노력으로 1993년도에 std_logic_1164를 포함하는IEEE 1076-1993과 이어서 IEEE 1076-1997이 발표되어 현재에 이르렀다.

아래는 산하 연구 그룹으로 다음과 같다.

IEEE 1076.1 : VHDL Analog Extension

IEEE 1076.2 : Math Package

IEEE 1076.3 : Synthesis Package (std_logic_1164)

IEEE 1076.4 : Timing Methodology (VITAL)

IEEE 1076.5 : utility

IEEE P1165 : EDIF EIA-567-A : Component modeling and Interface


4. VHDL의 특징

1) 표준화된 HDL : 표준화라는 말은 누구나 어떠한 환경하에서도 정보를 공유할수 있다는 의미이다.

그러나 종래의 표준화되지 못한 HDL은 특정 사람과 환경에서만 사용할수 있기 때문에정보공유, 재사용등에 문제가 있었다. 이러한 문제는 표준화된 VHDL의 등장으로 모두 해결되었다. 즉, 타겟 라이브러리와 테크놀러지에 상관없이 사용할 수 있게 되었다. 설계의 초기 단계에서 사양서에 따른 동작 특성과 알고리즘 검증은 반도체 공급업체의 라이브러리와 상관없이 VHDL로 기술하여 시뮬레이션을 할수 있다. 이러한 방법론은 시스템 관점에서 또는 알고리즘 관점에서 동작 특성을검증하는 표준화된 VHDL의 특징이라고 할수 있다. 즉, 특정 CAD 소프트웨어와 라이브러리에상관없이 사용할 수 있으므로 보다 쉬운 정보교환 등으로 설계상의 오류 및 개발 기간을 단축할 수 있으므로 전체적인 설계 비용을 줄일 수 있다.

2) 이용의 확대 : IEEE 표준으로서 미국방성 공인 HDL이다. 이러한 상황은 사용자 층이 유럽과 아시아로 점점 확대 되고 있다.

3) 설계 기술 능력 : 실제 IEEE 1076 매뉴얼을 보면 모든 하드웨어를 표현할수 있도록 되어 있다.

디지탈은 물론 아날로그 표현, 다양한 타이밍 표현, 시스템 레벨에서 트랜지스터 레벨까지 다양한 레벨을 표현할수 있도록 하였다. 또한 물리적인 양의 표현, 병렬 신호 할당문, resoluton function등 여러가지 표현이 가능하다.

그러나 현재는 상용 CAD TOOL의 제한으로 그리고 사용자의 요구로 지금은 시뮬레이션과 합성을 주로 사용하고 있다.

4) 언어로서의 기능 : 기본적인 하이레벨 언어의 특성을 가지고 있을 뿐만 아니라 논리적인 연산자와함수, 문자, 사용자 정의 자료 형태, 속성등의 특징이 있다.


5. VHDL의 표현방법(Y 차트라고함 : 나중에 자세히 설명)

임의의 기능 블럭에 대해서 다양하게 기술할수 있다. 기술하는 방법론을 우리는 모델링이라고한다. 일반적으로 behavioral modeling, dataflow modeling, structural modeling등 세가지로분류한다. 물론 사용자에 따라 사양서의 특성에 따라 혼합해서 사용할수도 있다.

1) Behavioral modeling : 인간과 가장 가까운 추상적인 표현으로서 시스템이 내부적으로 어떠한 동작 특성을 가지고 있는 지에 상관없이 설계자가 원하는 것을 기능적 또는 수학적인 알고리듬을 사용해서 시스템의 기능(function)을 기술하는 것을 말한다. 즉 초기 설계 단계에서 알고리즘 검증을 위해서 많이 사용한다.

2) Dataflow modeling: 신호 및 제어의 흐름과 같은 데이타의 흐름을 나타낸다. 주로 부울대수, 함수, RTL 또는 연산자(AND, OR 등)를 사용하여 입력으로부터 출력까지의 경로 표현을 위주로 한다. Behavioral modeling 단계보다는 하드웨어에 가깝게 기술한다.

3) Structural modeling: 세가지 모델링 중에서 하드웨어에 가장 가까운 표현으로서모든 컴포넌트 뿐만 아니라 이들의 상호연결도를 나타낸다. 즉 레지스터와 버스뿐만 아니라 게이트 수준의 설계를 가능하게 한다.


6. 한국의 VHDL

국내에서는 80년대 말쯤에 CADENCE TOOL을 사용하는 몇몇 대기업에서 Verilog-HDL을 일부 사용하고있었으나 극히 제한적이었다. 이즈음 VHDL도 발표가 되어 연구소와 학계에서는 국내 HDL 표준화 문제가등장하게 되었다. 결국 Verilog-HDL과 VHDL 둘중의 하나를 선택하는 일이었다.

그당시 Verilog-HDL은 CADENCE라는 회사 전용 언어이고, VHDL은 IEEE에서 표준화된 언어이기때문에 쉽게 VHDL에 관심을 가지게 되었다. 그러한 배경으로 1988년도부터 ETRI,인천대,홍익대와공동으로 VHDL에 관한 연구(주로 TOOL개발)를 하게 되었다. 이때도 대기업들만이 관심을 갖고 있던 터라 ASIC이라는 말도 생소하거니와 VHDL은 더더욱 낯설은 단어였다.

90년대 들어서, 상업용툴이 등장하게 되었는데, 한마디로 놀라운 작품이었다.

시뮬레이터로는 Vantage(지금은 어느회사로 합병되어 있는지...), 그다음 합성기로는SYNOPSYS가 나오고, 이후 여러회사들이 발표하게 되었다.

지금이야 전자과 학생들은 웬만하면 VHDL을 다 접하고 있으니 놀라운 발전이라 할수 있다.

물론 시스템 업체를 포함한 대부분의 전자관련 업체에서도 지대한 관심을 가지고 있다 할수 있다.


7. VHDL의 접근 마인드

VHDL도 일종의 프로그래밍 언어임에는 틀림없다. 그러나 앞에서 언급한 몇가지 특성때문에실제로 적용할때는 몇가지 유념해야할 사항들이 있다. 대부분 VHDL을 접하는 초보자들은 기본적으로 C와 같은 언어에는 익숙해져 있는 상태이다. 그런 경험을 바탕으로 VHDL을 접하게 되면 하드웨어 구현에 초점을 맞추기 보다는프로그래밍 관점에 얽매이게 된다. 즉, 타이밍 개념, 저장 기능, 병렬처리같은 하드웨어에서는필수적인 기능들이 이해하기 힘든 상황으로 발전한다. 그래서 이러한 초보자들은 C와같은 프로그래밍 경험이 VHDL을 배우는데 도움이 되겠지만때로는 고정관념 때문에 방해가 되기도 한다. 단지 잇점이라고 할만한 것들은 언어의 감각뿐이다. 그리고 중요한 것은 디지탈 시스템에서 사용되는 기능블럭의 동작 특성을 얼마나 잘 이해를 하느냐 이다. 이해를 했다면 이를 어떻게 VHDL로 옮기느냐가 관건이다. 그러나 디지탈 시스템은 크게 조합논리회로와 순차회로로 분류할수 있는데,조합논리회로는 VHDL에서 MUX를 표현하는 방법만 알고 있어도 8-90%는 쉽게 접근할수 있다. 그러나 순차회로는 메모리 기능과 타이밍 개념이 있기 때문에 다소 어렵지만 그래도signal문과 process문을 이해한다면 이 또한 8-90%는 커버하리라 생각한다. 다시한번 강조하지만 먼저 타겟 프로젝트에 대한 기능블럭의 동작 특성을 이해하는 일이 매우 중요하다. 그런 다음에 VHDL로 기술하는 것은 그리 어렵지 않게 할수 있다. 물론 VHDL 관점에서도 이를 어떻게 기술하느냐에 따라 최적화가 달라질수 있지만, 무엇보다도시스템 관점이 매우 중요하다고 할수 있다. 결국 ASIC이건 VHDL이건 모두가 시스템 설계자의 몫이기 때문이다. ASIC을 만드는 일중에서 7-80%를 차지하는 부분이 바로 시스템 설계자가spec.을 정하고 이를 토대로 동작특성을 이해하여 VHDL로 옮기는 작업이다. VHDL로 옮긴후 그다음 작업은 CAD TOOL을 이용하기 때문에 한마디로 단순작업이라고 할수 있다. 여기서 ASIC 설계자라고하는 것은 그 단순작업을 수행하는 사람을 칭한다.


9. VHDL Simulation & Synthesis

VHDL을 사용하는 입장에서 고려해야할 중요한 사항중에 하나는 시뮬레이션과 합성단계이다. 시뮬레이션이라고하는 말은 실제 ASIC으로 구현하기 전에 모의실험을 하는 과정이라고 할수 있다. 그리고 합성이라고 하는 말은 VHDL로부터 논리 회로도를 추출하는 과정이다. 그러면 여러단계를 거치는 시뮬레이션을 살펴보면 다음과 같다.

요즘에는 VHDL 시뮬레이터가 너무 많기 때문에 특정툴에 기반을 두고 설명하기란 쉽지 않다. 그래서 여기서는 일반적인 사항들을 설명하고자 한다. 먼저 고려해야할사항은 PC 기반이든 Unix기반이든 기본적으로 공통된 라이브러리가 존재하게 된다. 즉, 특정 라이브러리(예를들어 LSI, 삼성등등)가 없어도 시물레이션을 할 수가 있다는 얘기다. 어디까지나 자체툴에서 제공하는 형태(어떤 툴에서는 intermediate format이라고도 한다)이기 때문에 타이밍(통상 Unit delay라고 한다)을 제외한 기능만 확인할 수 있게 된다.

특정 라이브러리가 정해지면(물론 특정툴에서 요구하는 환경을 갖춘다는 의미) VHDL 파일을 컴파일하게 된다. 여기서 컴파일이라고 하는 말은 광의의 말이다. 구체적으로 살펴보면 1단계로 parsing이라는 것을 거친다. parsing에는 VHDL 파일이 문법에 맞게 코딩을 하였는지 그리고 의미가 제대로 맞는지를 검사한다. 검사결과 에러나 워닝이 없으면 일단 툴이 받아들일 준비는 OK, 그다음에는 테스트 벡터(test bench file)를 만들어 running을 하게 되면 타이밍관계를 볼 수 있다. 물론 이렇게 쉽게 시뮬레이션을 할 수 있다면 다행이지만 실제는 그렇지가 않다. 일종의 반복작업을 수 없이 해야하기 때문이다. 즉, 컴파일 단계에서 몇 번에 걸쳐 no error and no warning 메시지를 얻었다고 하더라도 테스트 벡터를 가지고 시뮬레이션을 하면 쉽게 만족할 만한 결과를 얻을 수가 없다. 그래서 다시 VHDL 파일을 수정하여 컴파일하고 시뮬레이션하고 반복과정을 거친다.

9-1. VHDL coding model guide (계속)
초보자에서 전문가까지 도움되는 아주 중요한 얘기들......(소개)

1. ASIC(FPGA,EPLD)에서 VHDL의 의미?

   사실 VHDL, Verilog-HDL, Schematic Capture, 등등의 사용목적은 반도체칩을 만들기 위한 매체(수단)에 불과하다. 물론 그외에도 여러 가지 요소와 고려사항이 있겠지만, 여기서는 칩을 만들 때 가장 처음에 고려되는 Spec.으로부터 할 수 있는 것은 블록도 추출과 그에 대한 동작설명이다.  Spec.을 이해하고 이로부터 어떤 정형화된 형태를 추출한다는 것은 보통 어려운 일이 아니다. 즉, 피나는 훈련이 필요하다는 얘기다.

 VHDL 이라는 언어를 알아야하고 그런다음 하드웨어 시스템을 알아야하기 때문이다. 기본적으로 ASIC은 시스템 설계자가 접근하는 일이지 CAD개발자, S/W 개발자, Firmware개발자가 접근하는 것은 아니다. 일례로 VHDL 언어감각은 후자가 뛰어날지 몰라도 시스템을 이해하는 능력이 부족다면 의미가 없겠지요. 물론 가능은 하겠지만 정상적인 경우는 아니죠. 그래서 개인이건 회사건 ASIC을 하기전에 시스템을 먼저 접하는게 순서가 아닐까요?

  따라서 VHDL은 하나의 High Level Language(C와 같은)이자 하드웨어 개념을 표현할 수 있는 구조로 되어있다. 큰 차이점은 VHDL에는 타이밍 개념이 있다는 것이다. 이러한 원론적인 의미를 벗어나서 설계자가 ASIC을 할 때 방법론을 선택해야하는 문제에 직면한다. 어떤 개발환경을 구축할 것인가? 즉, Design Entry를 HDL로 할 것인가, 아니면 스키캐틱으로 할 것인가를 정하게 된다. 요즘에는 많이 HDL에 익숙해 있지만 아직도 중요한 블록들은 스키매틱으로하고 있답니다. 아마도 최적화 측면이겠지요. 각가 장단점은 있지만 VHDL을 사용하게 되면 장점이 많은 듯 합니다.

2. Spec.에서 VHDL을 추출하는 방법?

   통상 시스템 설계자가 Spec.(물론 기능 검증을 위해서 S/W개발자도 포함되겠지만, 일종의 지원팀이죠)을 정하는데, 대략 입출력 타이밍과 핀들의 정의 그리고 좀더 구체화 되었다면 내부 기능블럭들의 동작 설명정도이겠지요. 이정도라면 상당한 수준이지요. 이러한 데이터로부터 어떻게 VHDL을 추출하느냐? 정말이지 막막할겁니다. 그러나 몇가지 방법론이 있답니다. 디지털에서도 순차 와 조합논리 그리고 메모리, 이게 전부잖아요. 마찬가지로 이러한 개념을 어떻게 VHDL로 변환을 하느냐? 그야 간단하죠.

   우선 스펙이 어떤 형태로 제공하느냐가 관건이죠, 요즘에는 표준규격(ITU같은..)이 있어서 좀 나은편이지요. 표준규격이 있는 경우는 통상 먼저 규격을 C언어로 시뮬레이션을 해보죠. 알고리즘 검증차원에서요. 또한 여기서 VHDL에서 사용되는 테스트 벡터도 뽑아낸답니다. 그러나 표준규격이 없을 때에는 전적으로 설계자가 알아서 만들어 내야하는거죠. 여기서는 표준 규격, 데이터 쉬트등과 같은 정형화된 것으로부터 VHDL을 추출하는 방법을 소개할까 합니다.


3. CAD Tool 선정?

가장 민감한 문제이다. 회사입장에서는 바로 돈이기 때문이다. 최근에는 이러한 투자비가 많이들어가서 ASIC관련부서를 많이 줄이고 있는 실정이다. 돈얘기를 하는 이유는 제품 가격이 천차만별이기 때문이다. 작게는 $100이하부터 $100,000이상가는 것까지 광범위하다. 따라서 향후 계획이 서야 한다는 것이다. 처음에는 FPGA를 했다가 ASIC으로 가는 경우는 FPGA Tool은 바로 쓰레기통행이기 때문이다. 결국 예산과 프로젝트 성질에 달려 있다고 생각한다. 여기서는 그러한 계획을 세우는데 도움이 될 만한 몇가지를 설명하고자 합니다.

4. ASIC Vender 선정?

이것또한 돈과 관계가 있다. ASIC을 한번 하는 경우(NRE라고 하죠, 쉽게 말해서 ASIC 칩을 만드는 비용)수천만원에서 수억까지 비용이 들기 때문이다. 여기서는 Vender를 선정할 때 고려사항들을 말씀드리겠습니다.

5. 우리나라에서 사용되는 CAD TOOL & ASIC Vender 특징 및 비교

아주 민감한 부분이라 본란은 제한을 하겠습니다.

6. 주요 CAD TOOL의 사용 방법

7. 우리나라 VHDL 역사



VHDL의 자료형(data types)


VHDL에서 사용하는 자료형 (data type)과 객체들, 그리고 보고 합성 가능한 자료형에 대하여 살펴 보기로 한다.
VHDL 자료형 (Data Types)
VHDL의 자료형은 스칼라 형 (scalar type)과 복합 형(composite type)으로 나뉘어 진다.

VHDL에서 자료형 검사는 매우 엄격하며 정의된 자료형에 따라 사용할 수 있는 연산자 또한 각각 정의 되어야 한다. 합성기(synthesizer)에 따라 서로 지원하는 데이터형이 다를 경우 VHDL 소스 사이의 호환성에 심각한 문제를 일으키며 많은 자료형 변환 함수와 타입 캐스팅 방법이 존재하게 된다. 이러한 문제를 해결하기 위하여 87년 IEEE 1076 VHDL의 표준에 이어 1991년에 IEEE 1164로서 디지털 회로의 합성 가능한 자료형에 대한 표준이 제정되기에 이르렀다. IEEE 1164는 디지털 회로에 대하여 9 가지 값(standard 9-valued logic)을 갖는 데이터 형 "std_logic"을 정의하였고 이는 IEEE 1076 의 "bit" 형을 확장한 것이다. IEEE 1076에는 VHDL의 언어에 대한 표준과 아울러 데이터 타입 및 각종 연산에 대한 표준이 정해져 있다. IEEE 1076에는 디지털 회로의 비트(bit) 형과 정수 및 실수형 문자형 등이 있으며 이중 bit와 정수형이 합성 가능하다. IEEE 1164의 "std_logic"은 bit의 '1'과 '0'이외에 Pull-up, Pull-down에 해당하는 'H' (Weak-High), 'L' (Weak-Low)와 'Z'(high-impedance), 'U'(uninitialize), 'X' (unknown), '-'(Don't care)등을 정의해 놓음으로써 디지털 회로의 합성뿐만 아니라 시스템 인터페이스에 대한 배려를 해두었다.


1-1. 열거형 (Enumeration type )

 

기본적으로 VHDL에서 사용하는 대부분의 자료형은 대부분 열거형 (enumeration type) 이다. IEEE 1076의 stanandard package에 정의되어 있는 열거형의 예를 들면 다음과 같다.

type boolean is (false,true);
type bit is ('0', '1');

IEEE 1164에 std_ulogic은 다음과 같이 열거형으로 정의 되어 있다.

TYPE std_ulogic IS ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

'U'는 초기화 되지 않은 상태(Uninitialized)를 의미하며 'X'는 Unknown으로서 디지털 값의 충돌등과 같은 에러상태를 나타낸다. '0' 과 '1'은 디지털 값에 해당하며 'Z'은 High Impedance, 'W', 'L', 'H'는 각각 Weak Unknown, Weak 0, Weak 1로서 Pull-up혹은 Pull-down된 디지털 값을 나타낸다. 끝으로 '-'은 합성 시 논리 최적화에 Don't care로서 이용된다.

열거형을 이용하면 사용자는 언재든지 자료형의 정의가 가능하다. 또한 열거형으로 정의된 경우 인 코딩(encoding) 방법을 지정할 수 있다. 인 코딩 방법으로는 2진 코드에 의한 방법(binary)과 One-Hot Encoding이 있다. One-Hot encoding 방법은 유한상태 머신(FSM : Finite State Machine)에서 상태를 나타내는 경우에 많이 이용되는 방법이다. 다음과 같은 예를 살펴보자.

type state is (IDLC, RECEIVE, SEND);

예제에서와 같이 열거형 "state"는 3개의 요소를 가지므로 Binary encoding하면 2비트가 필요한 반면 On-Hot encoding하는 경우 각 요소마다 1개의 비트를 할당하여 3비트로 표현된다.

VHDL에서 형 검사(type checking)가 치밀한 이유 중 하나가 위와 같은 열거형을 주로 다루기 때문이라고 할 수 있다. 각종 연산자 혹은 할당(assignment)의 경우 기본적으로 열거형으로 이루어진 서로 다른 두 타입은 비트 폭에서부터 다르기 때문이다. 다음과 같이 bit 형과 std_logic형의 할당문의 경우 예를 살펴보자.

Type bit is ('0', '1');
Type std_logic is ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' );

와 같이 정의된 두개의 시그널,

Signal A : bit;
Signal B : std_logic;

을 사용한 할당문,

A <= B;

은 하드웨어적인 연결의 의미를 고려해 볼 때 할당문은 성립할 수 없는 것이 당연하다.

1-2 정수형 (Integer Type)

IEEE 1076에 정의된 정수형의 기본적인 비트 폭(bit-width)은 32비트로 되어 있다.

type integer is range -2147483648 to 2147483647;

정수형은 산술연산이 가능하며 2의 보수형태로 이루어진다. 또한 정수형은 합성이 가능하며 범위를 지정하지 않을 경우 32비트가 된다. 따라서 과도한 비트 폭을 갖는 연산기의 합성을 피하려면 정수의 범위를 지정해서 사용하도록 한다. 다음의 예는 4비트 시그널을 선언한 예이다.

Signal count : integer range 0 to 15;


1-3 실수형 (Real, Floating-Point Type)

실수형(real type)은 합성가능하지 않다. 시스템 모델링 이나 아날로그 회로의 모델링 등에 사용될 수 있다. IEEE 1076의 실수형의 정의는 다음과 같다.

type real is range -1.0E308 to 1.0E308;

다음은 실수형으로 아날로그 회로의 한예로서 A/D 변환기를 기술한 예이다.

  function ADC_8b_10v_bipolar ( analog_in : in real ) return byte is
constant max_digital_value : integer := 256;
constant max_analog_value : real := 5.0;
variable digitized_signal : integer;
variable digital_out : byte;
begin

if (analog_in < 0.0) then

digitized_signal := 0;

else

digitized_signal := integer(analog_in * ( real(max_digital_value) / max_analog_value) );

if (digitized_signal > (max_digital_value - 1)) then

digitized_signal := max_digital_value - 1;

end if;

end if;

digital_out := byte(to_std_logic_vector(digitized_signal,8));

return digital_out;

end
 

아날로그 입력 값을 실수형으로 입력 받은후 디지털 변환을 수행한다.

digitized_signal := integer(analog_in * ( real(max_digital_value) / max_analog_value) );

이때 계산된 값은 정수형 데이터이며 이를 디지털 시스템으로 인터페이스 하기 위하여 정수형을 "std_logic"형으로 변환하기위한 함수를 이용한다. 정수로부터 "std_logic_vector"로 형 변환 (type conversion)을 수행하기 위한 함수 "to_std_logic_vector"는 다음과 같다.

  function to_std_logic_vector ( a : integer; width : integer ) return std_logic_vector is
constant y_length : integer := width;
constant a_threshold : integer := 2 ** (width-1);
variable y_ref : integer;
variable y : integer;
variable y_std_logic_vector : std_logic_vector(y_length-1 downto 0);
begin

y := a;

if (a >= 0) then

y_ref := a_threshold;

for i in y_length-1 downto 0 loop

if (y < y_ref) then

y_std_logic_vector(i) := '0';

else

y := y - y_ref;

y_std_logic_vector(i) := '1';

end if;

y_ref := y_ref / 2;

end loop;

else

for i in y_length-1 downto 0 loop

y_std_logic_vector(i) := '0';

end loop;

end if;

return y_std_logic_vector;

end to_std_logic_vector;
 

 A/D변환 값을 반환하기 위하여 "byte" 형을 std_logic 형으로부터 정의하여 사용하였다.

type byte is array (7 downto 0) of std_logic;


1-4. Physical Type

물리량의 단위(unit)와 배수 관계를 정의한 것이며 합성 가능하지 않다. IEEE 1076에는 시간에 대한 정의가 있는데 다음과 같다.

  type time is range -2147483647 to 2147483647
units

fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
ms = 1000 us;
sec = 1000 ms;
min = 60 sec;
hr = 60 min;

end units;
 

위에서 볼 수 있듯이 VHDL의 최소시간 단위는 fs (femto second, 10E-15) 이다.


1-5 배열형 (Array Type)

VHDL에서 배열형을 사용할 수 있다. 일 차원 배열형의 경우 대부분 합성기에서 지원 하지만 2차원 배열을 지원하지 않는 합성기도 많다. 디지털 회로의 기본 데이터 단위는 "bit" 이다. 이를 버스형태로 정의하기 위해서 "bit_vector"형을 사용한다. 즉 버스를 정의하는 것은 "bit"의 일 차원 배열이다. 배열형을 정의 할 때 그 크기를 지정하는 경우가 있고 임의의 배열 크기를 지정할 수도 있다.

type byte is array ( 7 downto 0) of bit;

일 차원 배열로 8-비트 크기의 데이터 타입 "byte" 을 정의한 것이다.

TYPE std_logic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_logic;

"std_logic" 형으로 일 차원 배열형 "std_logic_vector"를 선언한 것이다. 이때 배열의 크기를 제한 시키지 않은 것으로서 시그널을 선언할 때 그 크기를 정하여 사용할 수 있다. 배열형의 선언한 예는 다음과 같다.

Signal byte_a : byte;
Signal count : std_logic_vector( 7 downto 0);

1-6 레코드 형(Record Type)

VHDL에서는 레코드형을 지원한다. 디지털 회로에서의 레코드형 사용 예는 기계어 명령의 비트맵 표현 등에 이용될 수 있다. 다음은 레코드 형의 사용 예이다.

  type month_name is (jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dev);

type date is
record

day : integer range 1 to 31;
month : month_name;
year : integer range 0 to 4000;

end record;

constant my_birthday : date := (21, nov, 1963);

SIGNAL my_birthday : date;


my_birthday.year <= 1963;
my_birthday.month <= nov;
my_birthday.day <= 21; -- 5-bit
-- my_birthday(0) : LSB
-- my_birthday(4) : MSB
 

파생형 (Subtype)과 형 변환(Type Conversion)
VHDL에서의 파생형(subtype)을 정의할 수 있으며 다음의 예는 정수로부터 일정한 크기를 갖는 파생 정수형을 정의한 예이다.

type big_integer is range 0 to 1023;
subtype small_integer is big_integer range 0 to 7;

 

"small_integer"는 "big_integer"의 파생형으로 정의되었다. 이 경우 파생형 "small_integer"의 의미는 10-비트 크기의 "big_integer"의 하위 4-비트를 차지하도록 정렬된다는 의미로서 두 데이터 형의 호환됨을 나타낸다. 다음의 예는 VHDL에서 자료형 검사(type checking)의 엄격함을 보여준다.

type big_integer is range 0 to 1000;
type small_integer is range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= intermediate * 5; -- type mismatch error

위의 예에서 "big_integer"와 "small_integer" 형은 비록 서로 정수형 이긴 하지만 서로 호환 돼지 않는다. 이러한 경우 "small_integer"를 파생형으로 정의 함으로서 형 불일치(type mismatch) 에러를 해결할 수 있다.

type big_integer is range 0 to 1000;
subtype small_integer is big_integer range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= intermediate * 5;

또 다른 방법으로 type casting을 이용할 수 있는데 이 경우는 기본적으로 두 형의 기본형이 같아야 한다.

type big_integer is range 0 to 1000;
type small_integer is big_integer range 0 to 7;

signal intermediate : small_integer;
signal final : big_integer;

final <= big_integer(intermediate * 5);

만일 정수형과 "std_logic_vector"형으로 변환하기 위해서는 두 데이터 타이의 기본형이 전혀 다르므로 형 변환 함수(type conversion function)를 사용하여야 한다. 형 변환 함수는 사용자가 임의로 만들어 쓸 수 있으나 IEEE 1164의 산술 패키지(numeric_std, numeric_bit)에는 정수와 "std_logic_vector", "bit" 사이의 형 변환을 위한 함수를 다수 가지고 있으므로 가급적 이를 이용하도록 권장한다. IEEE 1164 라이브러리의 산술연산과 형 변환 함수는 합성 가능한 산술 연산을 다루면서 자세히 살펴 보기로 한다. 다음의 예는 산술연산과 형 변환 함수의 이용에 대한 것이다.

  package my_type is

type big_integer is range 0 to 1023;
subtype small_integer is big_integer range 0 to 7;

end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.my_type.all;

entity subtype_test is

port (

a : in small_integer;
b : in small_integer;
c : out std_logic_vector(9 downto 0) );

end subtype_test;

architecture behave of subtype_test is
signal t_int : big_integer;
begin

t_int <= a + b;
c <= std_logic_vector(to_unsigned(natural(t_int), 10));

end;
 

위의 예는 정수 입력을 받아서 연산을 수행한 후 이를 10 비트 크기의 "std_logic_vector" 로 출력하는 경우이다. 입력된 2개의 정수형("small_integer") a,b를 계산하여 "big_integer"로 할당한다.

t_int <= a + b;

사용자 정의형 "big_integer"인 "t_int"로 부터 std_logic_vector"로 변환하는 과정은 약간 복잡하게 보이지만 이러한 변환과정이 시스템 설계와 서로 다른 모듈사이의 인터페이스 할 때 자주 직면하게 되는 문제이므로 잘 이해해둘 필요가 있다.

c <= std_logic_vector(to_unsigned(natural(t_int), 10));

Numeric_std package에 정수-unsigned 변환 함수가 to_unsigned()로 제공되고 있다. 이 함수의 argument가 natural이므로 사용자 정의형으로부터 정수형(natural)으로 type-casting 한다. Unsigned 형으로 변환할 것이므로 integer가 아닌 natural로 type-casting 한 것이다. 정수형을 std_logic_vector로 직접 변환하는 함수를 가지고 있지 않다. 따라서 to_unsigned() 함수를 사용하여 정수를 10비트 unsigned로 변환 한후 다시 type-casting 하여 "std_logic_vector"인 출력 포트에 연결한 것이다. unsigned는 IEEE 1164의 numeric_std에 다음과 같이 정의 되어 있으므로 type-casting이 가능하다.

type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;

이 변환 과정을 보면 알 수 있듯이 같은 기본형으로부터 파생된 자료형은 type-casting 할 수 있지만 기본형이 다른 경우 형 변환 함수를 써야 한다. 그러나 "t_int <= a + b;" 에서와 같이 기본형이 같은 파생형(subtype)의 경우에는 변환을 수행할 필요가 없다. 위의 예를 합성한 결과는 그림 4와 같다. 0~7까지의 범위를 갖는 두개의 "small-integer"형 입력이 4비트로 연산기로 합성된 후 10비트 출력의 하위 4비트로 출력 되는 것을 볼 수 있다.


                 VHDL의 출현 배경 및 변화 과정

  미국 정부의 VHSIC Program의 주요 목적은 설계, 공정 및 제조 기술 분야에 있어서 미국의 기술 수준을 향상시키는 데 있었다. 또한 미국 정부는 이 Program의 일부로써 VHDL의 개발 노력을 지원하고 있었다.  그  지원 목적은 VHDL의 개발로 좀더 빠른 생산과 회사들간의 연락 기능 강화 및 개발 과정을 능률적으로 처리함으로써 비용 절감 효과를 제공하는 것이었다. 이러한 목적들을 효과적으로 달성할 수 있는 방법을 논의하기 위하여 메사추세츠의 Woods Hole에서 개최된 학술 대회를 시발점으로 1981년부터 VHDL이 개발되기 시작하였다. Technology independent(기술 독립적)하며 표준 하드웨어 기술 언어의 개발을 목표로 한  Woods Hole 학술 대회에서 정부의 공식적인 제안 요구서를 위한 초안이 제출되었으며, 이것은 전자 공학 분야에 종사하는 전문가들에 의해서 검토되는 과정을 거쳐 1983년 초에 수정, 확정되었다. 1980년대 중반 이후부터 VHDL이 문서용이 아닌 Simulation용으로 검증되어져야 한다는 여론이 강해지면서 몇몇 VHDL Simulator가 등장하였으나 업체간에 표준화가 이루어지지 않은 관계로 호환성에 문제가 있었다. 이러한 문제를 해결하고 늘어가는 VHDL관련 CAD Tool 회사간의 표준 및 호환성을 위하여 IEEE에서 1987년에 IEEE-1076이라는 표준을 만들어 공포하였다.  
  이 시점에서  Synthesis(회로합성)는 아직 등장하지 않았으며  VHDL은 Simulation용으로 사용되었다.  1990년대에 들어서면서 VHDL 관련 Software 회사가 많이 등장하고 simulation뿐만 아니라 Synthesis의 기능을 갖춘 CAD Tool이 등장하면서 진정한 VHDL의
표준화가 요구되었고 1991년 IEEE-1164이 발표되면서 업체에서 공통으로 사용할 수 있는 VHDL이 탄생하였다

신고
블로그 이미지

꽃중년

불만있으면 떠나라...

Tag VHDL

티스토리 툴바