하시설 보고서 - sangmoon/snu GitHub Wiki

  1. Shifter IP verilog

    IP structure ip 구조는 axi partuser logic part로 나눌 수 있다. axi part에서는 interface를 구현하여 bram과 통신이 가능하게 한다. user logic part에서는 shifter를 위한 logic을 구현 한다.

    IP interface user interface와 axi interface로 나눌 수 있다.

    • user interface
    output wire [BRAM_ADDR_WIDTH-1:0] BRAM_ADDR,//READ,WRITE를 할 BRAM 주소
    output wire BRAM_CLK,//BRAM clock
    output wire [BRAM_DATA_WIDTH-1:0] BRAM_WRDATA,//WRITE 할 data
    input wire [BRAM_DATA_WIDTH-1:0] BRAM_RDDATA, // READ 해온 data
    output wire BRAM_EN, // BRAM enable
    output wire BRAM_RST, //BRAM reset
    output wire [BRAM_WE_WIDTH-1:0] BRAM_WE, //write enable
    
    • axi interface AXI protocol에 맞는 interface이다. AXI4-LITE 형태이다. AXI4-LITE는 simple, low-throughput memory-mapped communication 을 위한 간단한 protocol이다. read addr, read data, write addr, write data, write response가 있다.
    input wire  S_AXI_ACLK,     // Global Clock Signal
    input wire  S_AXI_ARESETN,	// Global Reset Signal. This Signal is Active LOW
    
    /* WRITE 관련 wire 들 */
    input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, // Write address .
    input wire [2 : 0] S_AXI_AWPROT, // Write channel Protection type.
    input wire  S_AXI_AWVALID,// Write address valid.
    output wire  S_AXI_AWREADY, // Write address ready.
    
    
    input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, // Write data .
    input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,// Write strobes.
    input wire  S_AXI_WVALID,// Write valid.
    output wire  S_AXI_WREADY,//Write ready.
     
    
    output wire [1 : 0] S_AXI_BRESP, // Write response.
    output wire  S_AXI_BVALID,// Write response valid. 
    input wire  S_AXI_BREADY,// Response ready.
     
    /* READ 관련 wire 들 */
    
    input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, // Read address
    input wire [2 : 0] S_AXI_ARPROT, // Protection type.
     
    input wire  S_AXI_ARVALID, // Read address valid.
    output wire  S_AXI_ARREADY, // Read address ready.
    
    output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, // Read data
    output wire [1 : 0] S_AXI_RRESP, // Read response.
    output wire  S_AXI_RVALID, // Read valid.
    input wire  S_AXI_RREADY   // Read ready.
    

    IP core

    • 우선 읽어온 값을 2배로 하는 부분은 아래 부분이다. bitwise shift연산을 사용한다.
    assign BRAM_WRDATA = BRAM_RDDATA << 1; 
    // 읽어온 READ_RDDATA를 2배해서 BRAM_WRDATA에 할당.
    
    • IP init을 담당하는 magic_code 이다. c code에서 h5555를 할당하면, logic이 시작한다.
    wire magic_code = (slv_reg0 == 32'h5555);
    
    • STATE 관리 영역이다. IDLE -> repeat {READ->WAIT->WRITE} -> IDLE 로 표현할 수 있다.
     always @( posedge S_AXI_ACLK )
     begin
       if ( S_AXI_ARESETN == 1'b0 )
         bram_state <= BRAM_IDLE;
       else
         case (bram_state)
           BRAM_IDLE: bram_state <= (magic_code)? BRAM_READ : BRAM_IDLE;
           BRAM_READ: bram_state <= BRAM_WAIT;
           BRAM_WAIT: bram_state <= BRAM_WRITE;
           BRAM_WRITE: bram_state <= (run_complete)? BRAM_IDLE: BRAM_READ;
           default  : bram_state <= BRAM_IDLE;
         endcase
     end
    
    • counting 하는 부분이다. up-counting 으로, BRAM_WRITE state일 때 1씩 더해줘서 3이 되면 run_complete flag를 1로 바꿔서 state를 바꾼다.
     always @( posedge S_AXI_ACLK )
     begin
       if ( bram_counter_reset )
         bram_counter <= 2'd0;
       else
         begin
           if (bram_counter_enable)
             bram_counter <= bram_counter + 2'd1; 
           else
             bram_counter <= bram_counter;
         end
     end
     
     assign run_complete = (bram_counter == 2'h3);
     // User logic ends
    

  1. OS, application 설명
    1. Makefile
    all: main.c
        gcc main.c && sudo ./a.out
    # main.c 라는 dependency를 갖고 실행한다.
    # gcc main.c 와 sudo ./a.out를 이어서 실행한다.
    # main.c 를 컴파일해서 a.out이라는 default 실행 파일을 만든 후 
    #이를 sudo 권한으로 실행한다
    
    1. main.c

      main.c 는 메모리 맵핑, 메모리 초기화, ip 구동 크게 3부분으로 나뉜다. 메모리 맵핑 부분은 다음과 같다.

    int foo = open("/dev/mem", O_RDWR); 
    // device의 system memory를 연다
    int *fpga_bram = mmap(NULL, SIZE * sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, foo, 0x40000000); 
    int *fpga_ip   = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, foo, 0x43C00000);
    // bram 과 ip에 대한 virtual addr 와 physical addr를 mapping 한다
    
    
    mmap이라는 system call을 사용한다. 이 함수는 virtual addr와 실제 addr를 연결한다.
    void *mmap(void *addr, size_t len, int prot, 
               int flags, int fd, off_t offset)
    /* return val: 맵핑되는 실제 메모리 주소 
     * addr:       어디에 mapping해야 좋은지 제안값
     * size:       맵핑시킬 메모리 영역의 길이 
     * prot:       맵핑에 원하는 메모미 보호 정책
     * flag:       맵핑 유형과 동작 구성 요소
     * fd:         file descriptor
     * offset:     맵핑할 때 len의 시작점
     */
    
    ip의 시작 주소에 0x5555 값을 할당하면 ip가 작동한다.
    *(fpga_ip) = 0x5555;
    while (*fpga_ip == 0x5555);
    
    1. SD card file && booting process
    • SD card file SD card는 2부분으로 파티션 되어있다. 첫 부분은 zed board를 위한 부분으로

      1. BOOT.BIN
      2. u-boot.img
      3. zynq.bit
      4. devicetree.dtb
      5. uImage

      로 구성되어 있다. 두 번째 부분은 linux file sytem으로 구성되어 있다.

    • booting process linux booting 은 BIOS -> boot loader -> kernel -> init 순으로 이루어진다. zynq linux booting은 크게 4부분으로 나뉜다.

      1. Boot ROM
      2. FSBL (BOOT.bin)
      3. SSBL (u-boot.img)
      4. Linux kernel

      우선 Boot ROM 에서 uImage를 확인하고, chip memory로 BOOT.bin을 load 한다. 그리고 zynq.bit file이 있는지 체크한 후, programmable logic으로 zynq.bit를 복사해 실행한다.