10월 17일
IP Intelectual Property
설계된 걸 사와서 내 설계에 접목해보자.
비어있는 포트들이 설정이 안 돼서 나타나는 오류
다시 create HDL Wrapper를 진행하니 정상적으로 완료됐다.
/* 2022.10.19
이걸 가져와서 썼을 때 제대로 동작하지 않고 timing loop가 발견됐다면서 에러가 나왔는데 IP가 아니라 다른 모듈에서 always 내부에 posedge i_clk가 아니라 그냥 i_clk로 써서 그랬던 거였다.
*/
-------
non-blocking / blocking
non-blocking 비동기식
always@(*) begin
...
r_value <= x; ...1
r_counter <= x2; ...2
end
순차회로에서 주로 쓰임.
1과 2를 동시에 대입.(1의 우항을 연산. 아래 줄로 넘어감. 2의 우항을 연산. 아래 줄로 넘어감. 연산할 게 없으니 대입 진행)
blocking 동기식
always@(*) begin
...
r_value <= y; ...1
r_counter <= y2; ...2
end
조합회로에서 주로 쓰임.
1과 2를 순서대로 대입.(1의 우항을 연산. 대입. 아래 줄로 넘어감. 2의 우항을 연산. 대입. 아래 줄로 넘어감.)
주의할 점은 반드시!! always 내에서 비동기식 혹은 동기식으로 통일해야 한다. 섞어써서는 안 된다!!
-----------
두 개의 always 구문이 있다고 하자.
always @(*) begin
...
r_value <= x;
end
always @(*) begin
...
r_value <= y;
end
이 경우, r_value에는 x와 y가 계속하여 대입된다. 이러한 동시 대입 상황을 race condition이라고 한다. 에러가 발생하는 부분이고 설사 컴파일이 돼더라도 제대로 작동하지 않는다.
따라서 이를 해결하기 위해서는 여러 개의 레지스터를 선언해서 각각의 always 구문에서 사용해야 한다.
-----
SRAM
module singleRAM(
input i_clk, i_ce, i_we,
input [5:0] i_addr,
input [7:0] i_data,
output [7:0] o_data
);
reg [7:0] mem[0:63];
reg [5:0] r_addr;
assign o_data = mem[r_addr];
always @(posedge i_clk) begin
if(i_ce) begin
if(i_we) begin
mem[i_addr] <= i_data;
end
else begin
r_addr <= i_addr;
end
end
else begin
end
end
endmodule
module tb_SRAM();
reg i_clk = 0, i_ce, i_we;
reg [5:0] i_addr;
reg [7:0] i_data;
wire [7:0] o_data;
singleRAM dut(
.i_clk(i_clk),
.i_ce(i_ce),
.i_we(i_we),
.i_addr(i_addr),
.i_data(i_data),
.o_data(o_data)
);
always #5 i_clk = ~i_clk;
initial begin
i_clk = 0;
i_ce = 0;
i_we = 0;
i_addr = 0;
// #20 i_ce = 1; i_we = 1; i_addr = 0; i_data = 10;
// #20 i_ce = 1; i_we = 1; i_addr = 1; i_data = 20;
// #20 i_ce = 1; i_we = 1; i_addr = 3; i_data = 30;
// #20 i_ce = 1; i_we = 1; i_addr = 4; i_data = 40;
// #20 i_ce = 1; i_we = 1; i_addr = 5; i_data = 50;
// #20 i_ce = 1; i_we = 1; i_addr = 10; i_data = 100;
// #20 i_ce = 1; i_we = 1; i_addr = 20; i_data = 200;
// #20 i_ce = 1; i_we = 1; i_addr = 25; i_data = 250;
#20 i_ce = 1; i_we = 1;
for(integer i = 0; i<64; i= i+1) begin
#20 i_addr = i; i_data = (i*10) + 1;
end
for(integer i = 0; i < 64; i = i+1) begin
#20 i_we = 0; i_addr = i;
end
#20 $finish;
end
endmodule
assign io_data = (i_rw == 1) ? mem[r_addr] : {8{z}};
high impedance라는 건 chip 입장에서 read를 하겠다는 의미(입력되는 전압값을 읽는 것). -> 내 입장에서 write을 하겠다는 의미.
module tb_staticRAM();
reg i_clk = 0, i_ce, i_rw;
reg [5:0] i_addr;
reg [7:0] i_data;
wire [7:0] io_data;
staticRAM dut(
.i_clk(i_clk),
.i_ce(i_ce),
.i_rw(i_rw),
.i_addr(i_addr),
.io_data(io_data),
.o_data(o_data)
);
always #5 i_clk = ~i_clk;
initial begin
i_clk = 0;
i_ce = 0;
i_rw = 0;
i_addr = 0;
io_data = 0;
#20 i_ce = 1; i_rw = 0;
for(integer i = 0; i<64; i= i+1) begin
#20 i_addr = i; i_data = i + 1;
end
#20 i_rw = 1;
for(integer i = 0; i < 64; i = i+1) begin
#20 i_addr = i;
end
#20 $finish;
end
endmodule
에러나서 수정 필요.
--------
Xilinx에서 무료로 제공하는 Soft core가 있음.
: Micor Blaze (ARM과 비슷함) 32bit. BUS, AXI, peripheral 주변장치
MicroBlaze는 간단하게 생각하면 MCU임.
Led를 켜기 위해 수정하자.
custom일 경우 GPIO Width를 통해 비트수 조절 가능. All Inputs이나 All Outputs를 선택 안 하면 코드를 통해 I/O 선택 가능.
block을 생성한 뒤, create HDL Wrapper까지 진행한다.
이제 아래에 맞춰 constraints를 수정한다.
uart는 자동으로 설정해줘서 건드릴 필요가 없다.
이제 bitstream을 만든다.(하드웨어에 올리지는 말고)
완성된 후
이제 소프트웨어로 넘어간다.
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xgpio.h"
#define CHANNEL_1 1
#define OUTPUT 0
//c, not verilog
XGpio GPIO_LED;
int main()
{
init_platform();
print("Hello World\n\r");
print("Successfully ran Hello World application");
XGpio_Initialize(&GPIO_LED, XPAR_AXI_GPIO_0_DEVICE_ID);
XGpio_SetDataDirection(&GPIO_LED, CHANNEL_1, OUTPUT);
while(1)
{
XGpio_DiscreteWrite(&GPIO_LED, CHANNEL_1, 0x00);
usleep(200000);
XGpio_DiscreteWrite(&GPIO_LED, CHANNEL_1, 0xff);
usleep(200000);
}
cleanup_platform();
return 0;
}
징크칩?