ETRI 0.5um CMOS DK 예제: FIR8 / [3] 칩 테스트 장치
"내 칩 서비스" MPW 2024-2차 칩이 28핀 SSOP 패키지로 배포 되었다. 디지털 회로의 경우 비록 28핀 밖에 않되는 칩이지만 테스트 하려면 테스트 벡터 제네레이터, 로직 아날라이져 같은 장비를 필요로 한다. 여러 클럭에 걸쳐 일련의 테스트 벡터를 주어 기능을 확인해야 하므로 입출력 신호 검사 장비는 프로그래머블 해야함은 물론이다. 비록 이런 장비를 갖췄더라도 장비 사용법은 쉽지 않다. 고가의 테스트 장비에 복잡한 사용법으로 인해 테스트 할 엄두가 나지 않는다면 직접 만들어 보자.
칩 테스트 장치는 기본적으로 SCE-MI 에 준하여 구성되었다.
SCE-MI(Standard Co-Emulation Modeling Interface), https://www.accellera.org/downloads/standards/sce-mi
SystemC 로 작성한 테스트 벤치를 통해 테스트 벡터 생성하고 출력을 검출한다. 동작 모드는 클럭 상세(Cycle Accurate)다. 아듀이노 메가보드를 활용하여 DUT(하드웨어)와 SystemC 테스트 벤치(소프트웨어) 사이의 모델 인터페이스 한다.
테스트 대상 칩은 아래와 같다.
설계명: FIR_PE/DB-19
설계자: 지하은/경희대학교
설계내용: 어레이 FIR 필터 용 프로세싱 엘리먼트(PE)
입출력 핀 수: 입력 17개, 출력: 8개
패키지 핀맵:테스트 장치 제작
준비물
Arduino MEGA/Modeling Interface
회로도: https://content.arduino.cc/assets/MEGA2560_Rev3e_sch.pdf
디지털 핀: https://docs.arduino.cc/resources/pinouts/A000067-full-pinout.pdf
Filenale: fir8_test.ino
FIR8 with SystemC Co-Emulation
Chip Test at Cycle Accurate Level
MyChip MPW 2024-2
*/
//----------------------// SOIC-28 Package
#define PIN_Xin_3 22 // 1
#define PIN_Xin_2 23 // 2
#define PIN_Xin_1 24 // 3
#define PIN_Xin_0 25 // 4
// VDD // 5
#define PIN_Yin_3 26 // 6
#define PIN_Yin_2 27 // 7
#define PIN_Yin_1 28 // 8
#define PIN_Yin_0 29 // 9
#define PIN_RDY_i 30 // 10
#define PIN_CLK_i 31 // 11
#define PIN_Cin_0 32 // 12
#define PIN_Cin_1 33 // 13
#define PIN_Cin_2 34 // 14
#define PIN_Cin_3 35 // 15
#define PIN_Cin_4 36 // 16
#define PIN_Cin_5 37 // 17
#define PIN_Cin_6 38 // 18
#define PIN_VLD_o 39 // 19
#define PIN_Yout_0 40 // 20
#define PIN_Yout_1 41 // 21
#define PIN_Yout_2 42 // 22
#define PIN_Yout_3 43 // 23
// VSS // 24
#define PIN_Xout_0 44 // 25
#define PIN_Xout_1 45 // 26
#define PIN_Xout_2 46 // 27
#define PIN_Xout_3 47 // 28
//-------------------------------------------------------------------
class Port_Xin {
uint8_t _val;
public:
Port_Xin(uint8_t val) // Constructor
{
// Set digital pins to output connecting DUT's INPUT
pinMode(PIN_Xin_3, OUTPUT);
pinMode(PIN_Xin_2, OUTPUT);
pinMode(PIN_Xin_1, OUTPUT);
pinMode(PIN_Xin_0, OUTPUT);
write(val);
}
uint8_t read()
{
return _val;
}
void write(uint8_t val)
{
digitalWrite(PIN_Xin_3, val & 0x08);
digitalWrite(PIN_Xin_2, val & 0x04);
digitalWrite(PIN_Xin_1, val & 0x02);
digitalWrite(PIN_Xin_0, val & 0x01);
_val = val;
}
};
//-------------------------------------------------------------------
class Port_Yin {
uint8_t _val;
public:
Port_Yin(uint8_t val)
{
// Set digital pins to output connecting DUT's INPUT
pinMode(PIN_Yin_3, OUTPUT);
pinMode(PIN_Yin_2, OUTPUT);
pinMode(PIN_Yin_1, OUTPUT);
pinMode(PIN_Yin_0, OUTPUT);
write(val);
}
uint8_t read()
{
return _val;
}
void write(uint8_t val)
{
digitalWrite(PIN_Yin_3, val & 0x08);
digitalWrite(PIN_Yin_2, val & 0x04);
digitalWrite(PIN_Yin_1, val & 0x02);
digitalWrite(PIN_Yin_0, val & 0x01);
_val = val;
}
};
//-------------------------------------------------------------------
class Port_Cin {
uint8_t _val;
public:
Port_Cin(uint8_t val)
{
// Set digital pins to output connecting DUT's INPUT
pinMode(PIN_Cin_6, OUTPUT);
pinMode(PIN_Cin_5, OUTPUT);
pinMode(PIN_Cin_4, OUTPUT);
pinMode(PIN_Cin_3, OUTPUT);
pinMode(PIN_Cin_2, OUTPUT);
pinMode(PIN_Cin_1, OUTPUT);
pinMode(PIN_Cin_0, OUTPUT);
write(val);
}
uint8_t read()
{
return _val;
}
void write(uint8_t val)
{
digitalWrite(PIN_Cin_6, val & 0x40);
digitalWrite(PIN_Cin_5, val & 0x20);
digitalWrite(PIN_Cin_4, val & 0x10);
digitalWrite(PIN_Cin_3, val & 0x08);
digitalWrite(PIN_Cin_2, val & 0x04);
digitalWrite(PIN_Cin_1, val & 0x02);
digitalWrite(PIN_Cin_0, val & 0x01);
_val = val;
}
};
//-------------------------------------------------------------------
class Port_RDY_i {
bool _val;
public:
Port_RDY_i(bool val)
{
// Set digital pins to output connecting DUT's INPUT
pinMode(PIN_RDY_i, OUTPUT);
write(val);
}
bool read()
{
return _val;
}
void write(bool val)
{
digitalWrite(PIN_RDY_i, val);
_val = val;
}
};
//-------------------------------------------------------------------
class Port_Xout {
uint8_t _val;
public:
Port_Xout(uint8_t val) // Constructor
{
// Set digital pins to input connecting DUT's OUTPUT
pinMode(PIN_Xout_3, INPUT);
pinMode(PIN_Xout_2, INPUT);
pinMode(PIN_Xout_1, INPUT);
pinMode(PIN_Xout_0, INPUT);
write(val);
}
uint8_t read()
{
_val = ((digitalRead(PIN_Xout_3)? 0x08:0x00) |
(digitalRead(PIN_Xout_2)? 0x04:0x00) |
(digitalRead(PIN_Xout_1)? 0x02:0x00) |
(digitalRead(PIN_Xout_0)? 0x01:0x00));
return _val;
}
void write(uint8_t val)
{
_val = val;
}
};
//-------------------------------------------------------------------
class Port_Yout {
uint8_t _val;
public:
Port_Yout(uint8_t val) // Constructor
{
// Set digital pins to input connecting DUT's OUTPUT
pinMode(PIN_Yout_3, INPUT);
pinMode(PIN_Yout_2, INPUT);
pinMode(PIN_Yout_1, INPUT);
pinMode(PIN_Yout_0, INPUT);
write(val);
}
uint8_t read()
{
_val = ((digitalRead(PIN_Yout_3)? 0x08:0x00) |
(digitalRead(PIN_Yout_2)? 0x04:0x00) |
(digitalRead(PIN_Yout_1)? 0x02:0x00) |
(digitalRead(PIN_Yout_0)? 0x01:0x00));
return _val;
}
void write(uint8_t val)
{
_val = val;
}
};
//-------------------------------------------------------------------
class Port_VLD_o {
bool _val;
public:
Port_VLD_o(bool val) // Constructor
{
// Set digital pins to input connecting DUT's OUTPUT
pinMode(PIN_VLD_o, INPUT);
write(val);
}
bool read()
{
_val = digitalRead(PIN_VLD_o);
return _val;
}
void write(uint8_t val)
{
_val = val;
}
};
//-------------------------------------------------------------------
class Port_CLK {
bool _val;
public:
Port_CLK(bool val)
{
pinMode(PIN_CLK_i, OUTPUT);
write(val);
}
void write(bool val)
{
digitalWrite(PIN_CLK_i, val);
_val = val;
}
bool read()
{
return _val;
}
void posedge()
{
digitalWrite(PIN_CLK_i, false);
digitalWrite(PIN_CLK_i, true);
_val = true;
}
void negedge()
{
digitalWrite(PIN_CLK_i, true);
digitalWrite(PIN_CLK_i, false);
_val = false;
}
bool cycle()
{
if (_val)
{
negedge();
posedge();
}
else
{
posedge();
negedge();
}
return _val;
}
};
//-------------------------------------------------------------------
void establishContact()
{
while (Serial.available() <= 0)
{
Serial.print('A'); // send a capital A
delay(300);
if (Serial.read()==(int)'A')
break;
}
}
//-------------------------------------------------------------------
void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
while (!Serial)
{
; // wait for serial port to connect.
}
establishContact(); // send a byte to establish contact until receiver responds
// Monitoring LED
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
}
#define N_RX 3 // [0]={Xin[7:4]|Yin[3:0]}
// [1]={-|Cin[6:0]};
// [2]={-[7:2]|Clk|RDY};
#define N_TX 2 // [0]={Xout[7:4]|Yout[3:0]}
// [1]={-[7:1]|VLD[0]}
uint8_t rxBuf[N_RX], txBuf[N_TX];
// Instantiate DUT Ports
Port_Xin Xin(0x00);
Port_Yin Yin(0x00);
Port_Cin Cin(0x00);
Port_Xout Xout(0);
Port_Yout Yout(0);
Port_RDY_i RDY_i(false);
Port_VLD_o VLD_o(false);
Port_CLK CLK(false);
void RxPacket()
{
int rxByte;
while(true)
{
if (Serial.available() >= N_RX)
{
for(int i=0; i<N_RX; i++)
{
rxByte = Serial.read();
rxBuf[i] = (uint8_t)rxByte;
}
//rxBuf[0]={Xin[7:4]|Yin[3:0]}
Xin.write((rxBuf[0] & 0xF0) >> 4);
Yin.write((rxBuf[0] & 0x0F));
//rxBuf[1]={-|Cin[6:0]};
Cin.write((rxBuf[1] & 0x7F));
//rxBuf[2]={-[7:2]|Clk|RDY};
RDY_i.write((rxBuf[2] & 0x01));
CLK.write((rxBuf[2] & 0x02));
return;
}
}
}
void TxPacket()
{
int txByte;
while(1)
{
if (Serial.availableForWrite() >= N_TX)
{
// [0]={Xout[7:4]|Yout[3:0]}
txBuf[0] = (((uint8_t)Xout.read() << 4) | ((uint8_t)Yout.read() & 0x0F));
// [1]={-[7:1]|VLD[0]}
txBuf[1] = ((uint8_t)VLD_o.read() & 0x01);
for(int i=0; i<N_TX; i++)
{
txByte = (int)txBuf[i];
Serial.write(txByte);
}
return;
}
}
}
uint8_t counter;
void loop()
{
counter += 1;
digitalWrite(LED_BUILTIN, (counter & 0x10)? HIGH:LOW);
RxPacket();
TxPacket();
}
SystemC Testbench
1. DUT Wrapper
Filename: sc_fir_pe.h
Purpose : Test wrapper
Chip Test of FIR PE (MyChip 2024-2)
Author : goodkook@gmail.com
History : Jan. 2025, First release
********************************************************************/
#ifndef _SC_FIR_PE_H_
#define _SC_FIR_PE_H_
#include <systemc.h>
// Includes for accessing Arduino via serial port
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
{
sc_in<bool> clk;
sc_in<bool> Rdy;
sc_out<bool> Vld;
sc_in<sc_uint<8> > Cin;
sc_in<sc_uint<4> > Xin;
sc_out<sc_uint<4> > Xout;
sc_in<sc_uint<4> > Yin;
sc_out<sc_uint<4> > Yout;
#define N_TX 3
#define N_RX 2
void transact(void)
{
uint8_t x, y, txPacket[N_TX], rxPacket[N_RX];
txPacket[0] = ((uint8_t)Xin.read()<<4) \
txPacket[1] = ((uint8_t)(Cin.read()) & 0x7F);
txPacket[2] = (((uint8_t)Rdy.read())? 0x01:0x00) \
// Send to Emulator
for (int i=0; i<N_TX; i++)
{
x = txPacket[i];
while(write(fd, &x, 1)<=0) usleep(1);
}
// Receive from Emulator
for (int i=0; i<N_RX; i++)
{
while(read(fd, &y, 1)<=0) usleep(1);
rxPacket[i] = y;
}
Xout.write((sc_uint<4>)(rxPacket[0]>>4));
Yout.write((sc_uint<4>)(rxPacket[0] & 0x0F));
Vld.write(rxPacket[1]? true:false);
}
void pe_thread(void)
{
while(true)
{
wait(clk.posedge_event());
transact();
wait(clk.negedge_event());
transact();
}
}
// Arduino Serial IF
int fd; // Serial port file descriptor
struct termios options; // Serial port setting
SC_CTOR(sc_fir_pe):
clk("clk"),
Cin("Cin"), Xin("Xin"), Xout("Xout"),
Yin("Yin"), Yout("Yout")
{
SC_THREAD(pe_thread);
sensitive << clk;
// Arduino DUT
//fd = open("/dev/ttyACM0", O_RDWR | O_NDELAY | O_NOCTTY);
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (fd < 0)
{
perror("Error opening serial port");
return;
}
// Set up serial port
options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
// Apply the settings
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &options);
// Establish Contact
int len = 0;
char rx;
while(!len)
len = read(fd, &rx, 1);
if (rx=='A')
write(fd, &rx, 1);
printf("Connection established...\n");
}
~sc_fir_pe(void)
{
}
};
#endif
2. Testbench
3. Main
Filename: sc_main.cpp
Purpose : Chip Test of FIR PE (MyChip 2024-2)
Author : goodkook@gmail.com
History : Jan. 2025, First release
********************************************************************/
#include "sc_fir_pe_tb.h"
int sc_main(int argc, char** argv)
{
sc_fir_pe_tb u_sc_fir_pe_tb("u_sc_fir_pe_tb");
//sc_start(990, SC_US);
sc_start();
return 0;
}
4. Makefile
테스트 실행
-----------------------
[이전] [2] 아듀이노 보드 에뮬레이터
[참고]
1. "내 칩 제작 서비스" 2025년 1차 MPW 대비 오픈-소스 도구 설치 [바로가기]
2. ETRI 0.5um CMOS DK 예제: counter8/16, 디지털 회로 칩 테스트 방법 [바로가기]
댓글 없음:
댓글 쓰기