반도체 Study/디지털 설계

Verilog - SPI (Master, Slave, FSM) (2) FSM, MASTER, SLAVE & SLVAE 활용

잇(IT) 2024. 6. 2. 12:25
728x90

https://insoobaik.tistory.com/594

이전에 간단한 FSM 구조와 SLAVE 구조에 대해 알아보았다.

이번에는 FSM을 통한 MASTER, SLAVE 구조를 구성하고

MASTER에서 8bit 데이터를 보내게 되면 각 bit가 의미하는 정보를 기반으로 Register에 값을 Read, Write 하는 코드를 작성할 것이다.

MASTER 코드 및 코드 분석

SLAVE 코드 및 코드 분석

SLAVE 활용 코드 및 코드 분석


MASTER

 

master는 사용자로부터 데이터를 받아서 해당 데이터를 spi의 sclk 주기에 맞게 slave에게 데이터를 전송하고 받는다.

아래 코드는 사용자로부터 데이터를 받아 8비트동안 slave에게 데이터를 전송하고 그 다음 8번의 sclk 주기 동안 slave로부터 데이터를 받는 과정을 반복한다.

 

module spi_m #(
    parameter sample = 0, send = 1, waitt = 2,
    parameter idle_o = 0, wait_o = 1, collect_o = 2) (
    input clk, miso, newd,
    input [7:0] din,
    output reg mosi, cs,
    output sclk,
    output [7:0] dout
    );
    
    reg [7:0] dout_o = 0;
    reg [1:0] scount = 0;
    reg sclk_t = 0;
    
    always @(posedge clk)
    begin
        if(scount < 3)
        begin
            scount <= scount + 1;
        end
        else
        begin
            scount <= 0;
            sclk_t <= ~sclk_t;
        end
    end
    
    reg [7:0] data_in = 0;
    reg [3:0] count = 0;
    reg [1:0] state = sample;
    reg [7:0] din_t = 0;
    
    always @(posedge sclk)
    begin
        case(state)
            sample :
            begin
                if(newd == 1'b1)
                begin
                    din_t <= din;
                    state <= send;
                    count <= 1;
                    cs <= 1'b0;
                    mosi <= din[0];
                end
                else
                begin
                    state <= sample;
                    cs <= 1'b1;
                end
            end
            
            send :
            begin
                if(count <= 7)
                begin
                    mosi <= din_t[count];
                    count <= count + 1;
                end
                else
                begin
                    count <= 0;
                    state <= waitt;
                    cs <= 1'b0;
                end
            end
            
            waitt :
            begin
                if(count <= 7)
                begin
                    count <= count + 1;
                end
                else
                begin
                    count <= 0;
                    state <= sample;
                    cs <= 1'b1;
                end
            end
        endcase
    end
    
    reg [3:0] count_o = 0;
    reg [1:0] state_o = idle_o;
    
    always @(posedge sclk)
    begin
        case(state_o)
            idle_o :
            begin
                if(newd == 1'b1)
                state_o <= wait_o;
                else
                state_o <= idle_o;
            end
            
            wait_o :
            begin
                if(count_o <= 7)
                begin
                    count_o <= count_o + 1;
                    state_o <= wait_o;
                end
                else
                begin
                    state_o <= collect_o;
                    count_o <= 0;
                end
            end
            
            collect_o :
            begin
                if(count_o <= 7)
                begin
                    dout_o[count_o] <= miso;
                    count_o <= count_o + 1;
                    state_o <= collect_o;
                end
                else
                begin
                    count_o <= 0;
                    state_o <= idle_o;
                end
            end
            
            default ;
        endcase
    end
    
    assign sclk = sclk_t;
    assign dout = ((count == 8) && (state == waitt)) ? dout_o : 8'h00;
    
endmodule

 

위 코드에서 FSM을 통해 상태를 정의한다.

 

sample, send, waitt는 master가 slave에게 데이터를 전달하는 단계에 사용된다.

1. sample

sample 단계는 사용자로부터 전달 받은 데이터를 임시 레지스터(din_t)에 저장하여 sclk에 맞게 데이터를 전송하기 위한 단계이다.

newd = 1 즉, 데이터가 들어오게 되면 동작을 하게 되고, 데이터가 들어옴과 동시에 데이터를 전달하기 위해 cs = 0, spi의 8번 주기를 카운팅 할 count <= 1 해 줌과 동시에 mosi를 통해 LSB(din[0])를 전달한다.

마지막으로 state를 send(전송) 상태로 변경한다.

2. send

send는 mosi를 통해 들어온 데이터를 전달하기 위한 동작이다.

8비트의 데이터를 sclk의 8번 주기에 맞게 전달하기 위해 count를 증가 시킴과 동시에 사용자 데이터가 복사된 레지스터(din_t)의 데이터를 한칸씩 이동하며 mosi 데이터로 전달한다.

count가 7이 되는 순간 8비트의 데이터를 전부 전달하게 되고, 8이 되는 순가 count <=0으로 변경하고 slave가 전달하는 데이터를 전달 받기 위해 send 상태는 waitt 상태로 전환한다.

전송이 끝났어도 master와 slave가 데이터를 주고 받기 위해서는 cs가 0을 유지해야 한다.

3. waitt

master가 slave와 데이터를 받는 동안 전송하는 단계는 잠시 대기하는 상태를 의미한다.

spi의 모든 주기는 sclk에 의해 정해지고, 송수신 되는 데이터 전부 8비트이기 때문에 8번의 카운트 동안 유지된다.

카운팅이 8번 끝나고 나면 state는 다시 sample 상태로 돌아가고, cs = 1 즉, master와 slave가 데이터를 주고 받지 않는 상태로 돌아간다.

 

idle_o, wait_o, collect_o는 master가 slave로부터 데이터를 전달받는 단계에 사용된다.

1. idle_o

idle_o 단계는 초기 상태로 만약 newd = 1 즉, 데이터가 들어온 것을 확인하게 되면, state_o를 wait_o로 변경하고 newd = 0인 경우 데이터가 없는 상태이기 때문에 idle_o을 유지한다.

2. wait_o

wati_o의 경우 master는 slave에게 데이터를 전달하는 8번의 sclk 주기 동안 대기해야 하기 때문에 대기 상태로 먼저 전환된다.

master가 slave에게 데이터를 전달하는 8번의 sclk동안 대기한 뒤 8번이 지나면 state를 collect_o로 전환한다.

3. collect_o

collect_o단계는 slave로부터 데이터를 수집하는 단계로 master가 slave로 데이터를 전달한 뒤 slave가 master에게 데이터를 전달하는 상태에 해당한다.

slave의 데이터는 miso를 통해 master로 전달되고, miso의 데이터가 dout_o 레지스터에 sclk 주기에 맞게 한비트씩 들어와 저장된다.

마찬가지로 8비트의 데이터이기 때문에 8비트의 데이터가 전부들어오게 되면 state를 다시 idle_o 상태로 변경한다.

 

마지막

count = 8 && state == waitt 둘의 상태를 충족할 때 dout을 통해 전달되는 값은 dout_o를 통해 전달된다.


SLAVE

 

slave의 경우 idle, collect 상태와 idle_o, send_o 상태가 존재한다.

idle, collect의 경우 master로부터 전달되는 mosi 데이터를 수집하는 상태에 해당하고, idle_o, send_o는 slave에서 master로 보내는 상태에 해당한다.

module spi_s #(
    parameter idle = 0, collect = 1,
    parameter idle_o = 0, send_o = 1) (
    input sclk, mosi, cs,
    output reg miso
    );
    
    reg [7:0] data_in = 0;
    reg [3:0] count = 0;
    reg newd = 0;
    reg [7:0] dout_t = 0;
    reg [1:0] state = idle;
    
    always @(negedge sclk)
    begin
        case(state)
            idle : 
            begin
                newd <= 1'b0;
                if(cs == 1'b0)
                begin
                    data_in[7:0] <= {mosi, data_in[7:1]};
                    count <= 1;
                    state <= collect;
                end
                else
                begin
                    state <= idle;
                end
            end
            
            collect :
            begin
                if(count <= 7)
                begin
                    data_in[7:0] <= {mosi, data_in[7:1]};
                    state <= collect;
                    count <= count + 1;
                end
                else
                begin
                    state <= idle;
                    count <= 0;
                    newd <= 1'b1;
                    dout_t <= data_in;
                end
            end
            
            default : state <= idle;
        endcase
    end
    
    reg [3:0] count_o = 0;
    reg [1:0] state_o = idle_o;
    
    always @(negedge sclk)
    begin
        case(state_o)
            idle_o :
            begin
                if(newd == 1'b1 && cs == 1'b0)
                begin
                    state_o <= send_o;
                    count_o <= 1;
                    miso <= dout_t[0];
                end
                else
                begin
                    state <= idle_o;
                end
            end
            
            send_o :
            begin
                if(count_o <= 7)
                begin
                    miso <= dout_t[count];
                    count_o <= count_o + 1;
                    state_o <= send_o;
                end
                else
                begin
                    count_o <= 0;
                    state_o <= idle_o;
                end
            end
            
            default : ;
        endcase
    end
    
endmodule

 

slave는 별도의 clk을 분주기 하지 않고 master로부터 전달 받은 sclk를 통해 통신 주기를 설정한다. 또한 master의 경우 posedge에서 동작했지만 slave의 경우 negedge에서 동작하도록 설정하였다. posedge 다음 negedge가 오기 때문에 master에서 데이터를 보내고 다음 반주기에서 slave에서 master에게 데이터를 보내는 구조를 만들기 위함이다.

 

첫번째로 master의 mosi를 통해 데이터를 전달 받을 때 idle, collect 상태가 있다.

1. idle

초기상태로 master에서 mosi를 통해 전달된 데이터를 받는 상태이기 때문에 newd = 0이고, cs = 0 master와 slave가 데이터를 주고 받을 수 있는 상태가 되면 상태 변경과 동시에 데이터를 받아오기 위해 mosi 데이터를 임시 데이터 저장소 data_in에 넣고 state를 collect로 변경한다.

2. collect

mosi 데이터를 저장하는 상태로 mosi의 8bit 데이트를 받아온다. 

새로운 데이터를 임시 데이터 장소의 MSB에 계속해서 추가하면서 데이터를 저장한다.

전달되는 데이터를 사용자 임의로 추후에 사용할 수 있다. (ex 처음 1bit는 r/w 다음 3bit는 address 등...)

data_in에 8비트가 전부 저장되면 해당 8비트의 데이터를 dout_t 저장소에 복사한다. (dout_t의 데이터는 miso로 전달될 데이터에 사용될 것이다.)

 

두번째로 slave에서 miso를 통해 master로 데이터를 전달할 때 idle_o, send_o 상태가 존재한다.

1. idle_o

miso의 초기 상태로 아직 miso를 통해 데이터를 전달하지 않는 상태이다.

newd = 1, cs = 0 위 상태를 통해 mosi 데이터가 전달되고, cs 상태가 0일 때 miso를 통해 master로 데이터를 전달한다.

상태 변경과 동시에 master로 데이터를 전달하기 위해 miso <= dout_t[0] LSB 데이터를 전달한다.

2. send_o

miso를 통해 master로 데이터를 전달하는 상태로 count_o를 통해 8비트 데이터 dout_t를 miso를 통해 전달한다.

master로 8bit 데이터를 전부 전달한 뒤 count_o = 0 및 상태를 idle_o로 변경하게 되면 master와 slave의 통신이 종료된다.


SLAVE 활용

 

위 Master Slave 구조를 기반으로 Master에서 8bit 신호를 보내게 되면 아래와 같이 8bit의 각 bit가 가지는 의미를 가지고 memory와 같이 동작할 수 있다. 

R/W Address Data
0 1 2 3 4 5 6 7

 

0bit : R/W를 구분하는 bit로 register에 데이터를 Read 할 것인지, Write 할 것인지 정한다.

1~2bit : Address를 나타내는 bit로 4개의 8비트 레지스터의 주소를 나타낸다.

3~7bit : Data를 나타내는 bit로 0bit의 값이 Write일 경우 해당 Data bit의 값을 레지스터에 저장한다.

 

Master 코드는 동일하며 Slave의 코드를 조건에 맞게 수정해준다.

 

Slave의 전체 코드는 아래와 같다.

 

SLAVE CODE

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/05/15 18:04:22
// Design Name: 
// Module Name: spi_s
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module spi_s #(
    parameter idle = 0, collect = 1, read = 2, write = 3,
    parameter idle_o = 0, send_o = 1) (
    input sclk, sdi, cs,
    output reg sdo,
    input rst
    );
    
    reg [4:0] slave_register[0:3];
    reg [4:0] tmp_register = 0;
    reg rw = 0;
    reg [1:0] address = 0;

    // receive data serially  
    reg [7:0] data_in = 0;
    reg [3:0] count = 0;

    reg newd = 0;
    reg [7:0] dout_t = 0;
    reg [1:0] state = idle;
    reg [1:0] state_rw = 0;
     
    always@(negedge sclk or posedge rst)
    begin
        if(rst)
        begin
            slave_register[0] = 5'b00000;
            slave_register[1] = 5'b00000;
            slave_register[2] = 5'b00000;
            slave_register[3] = 5'b00000;
        end
        case(state)
            idle: 
            begin
                newd <= 1'b0;
                if(cs == 1'b0)
                begin
                    rw <= sdi;
                    data_in <= {sdi, data_in[7:1]};
                    count <= 1;
                    state <= collect;
                end
                else 
                begin
                    state <= idle;
                end
            end
 
            collect: 
            begin
                if(count <= 7)
                begin
                    
                    data_in <= {sdi, data_in[7:1]};
                    if(count == 7)
                    begin
                        if(rw == 0)
                        begin
                            address <= data_in[2:1];
                            tmp_register <= slave_register[data_in[2:1]];
                            state_rw <= read;
                        end
                        else if(rw == 1)
                        begin
                            address <= data_in[2:1];
                            tmp_register <= data_in[7:3];
                            state_rw <= write;
                        end
                    end
                    state <= collect;
                    count <= count + 1;
                end
                else
                begin
                    state <= idle;
                    count <= 0;
                    newd <= 1'b1;
                    dout_t <= data_in;
                end
            end
            
            default: state <= idle;
        endcase
    end 
    
    always @(posedge sclk)
    begin
        case(state_rw)
            0:
            begin
            end
            read:
            begin
                if(count == 8)
                begin
                    data_in <= {tmp_register, address, rw};
                end
            end
            
            write:
            begin
                if(count == 8)
                begin
                    slave_register[address] <= tmp_register;
                    data_in <= {5'b00000, address, rw};
                    
                end
            end
            
            default: state <= 0;
        endcase
     end
 
    reg [3:0] count_o = 0;  
    reg [1:0] state_o = idle_o;

    always@(negedge sclk)
    begin
        case(state_o)
            idle_o: 
            begin
                if(newd == 1'b1 && cs == 1'b0)
                begin 
                    state_o <= send_o;
                    count_o <= 1;
                    sdo <= dout_t[0];
                end
                else
                begin
                    state_o <= idle_o;  
                end
            end  
 
            send_o: 
            begin
                if(count_o <= 7)
                begin
                    sdo <= dout_t[count_o];
                    count_o <= count_o + 1; 
                end 
                else
                begin
                    count_o <= 0;
                    state_o <= idle_o;
                end
            end
 
            default: ;
        endcase
    end
endmodule

코드 상세 분석

module spi_s #(
    parameter idle = 0, collect = 1, read = 2, write = 3,
    parameter idle_o = 0, send_o = 1) (
    input sclk, sdi, cs,
    output reg sdo,
    input rst
    );

 

paramter를 통해 mosi로 전달된 데이터를 사용하는 FSM - idle, collect, read, write를 지정하고, miso로 데이터를 전달할 FSM idle_o, send_o를 지정한다.

그 외 master에서 전달하는 sclk, sdi(mosi), cs(ss)와 master로 전달하는 sdo(miso) 값을 선언한다.

 

reg [4:0] slave_register[0:3];
    reg [4:0] tmp_register = 0;
    reg rw = 0;
    reg [1:0] address = 0;
    
    reg [7:0] data_in = 0;
    reg [3:0] count = 0;

    reg newd = 0;
    reg [7:0] dout_t = 0;
    reg [1:0] state = idle;
    reg [1:0] state_rw = 0;

 

slave_register : 8bit의 크기를 가진 4개의 레지스터를 생성한다. slave 내부의 저장공간이 된다.

tmp_register : slave_register에 값을 넣거나 뺄 때 임시로 저장할 공간이 된다.

rw : Read / Write 값이 결정되면 해당 값을 저장할 공간이 된다.

address : slave_register에 접근하기 위한 주소를 저장할 공간이 된다.

data_in : mosi를 통해 들어오는 데이터를 저장할 공간이 된다.

count : sclk를 통해 통신 주기가 맞춰지고 해당 주기의 몇 비트씩 신호를 사용할 것인지 지정하기 위한 count에 해당한다.

newd : slave에서 master로 데이터를 전달할 준비가 완료되었다는 신호를 보내기 위한 변수이다.

dout_t : slave에서 master로 전달할 데이터가 저장될 공간이다.

state : slave의 전체 구조를 동작 시키기 위한 FSM의 상태를 지정할 변수이다.

state_rw : slave의 구조에서 slave_register에 데이터를 Read / Write하기 위한 동작을 위한 FSM의 상태를 지정할 변수이다.


첫번째 always

always@(negedge sclk or posedge rst)
    begin
        if(rst)
        begin
            slave_register[0] = 5'b00000;
            slave_register[1] = 5'b00000;
            slave_register[2] = 5'b00000;
            slave_register[3] = 5'b00000;
        end
        case(state)
            idle: 
            begin
                newd <= 1'b0;
                if(cs == 1'b0)
                begin
                    rw <= sdi;
                    data_in <= {sdi, data_in[7:1]};
                    count <= 1;
                    state <= collect;
                end
                else 
                begin
                    state <= idle;
                end
            end
 
            collect: 
            begin
                if(count <= 7)
                begin
                    
                    data_in <= {sdi, data_in[7:1]};
                    if(count == 7)
                    begin
                        if(rw == 0)
                        begin
                            address <= data_in[2:1];
                            tmp_register <= slave_register[data_in[2:1]];
                            state_rw <= read;
                        end
                        else if(rw == 1)
                        begin
                            address <= data_in[2:1];
                            tmp_register <= data_in[7:3];
                            state_rw <= write;
                        end
                    end
                    state <= collect;
                    count <= count + 1;
                end
                else
                begin
                    state <= idle;
                    count <= 0;
                    newd <= 1'b1;
                    dout_t <= data_in;
                end
            end
            
            default: state <= idle;
        endcase
    end

첫번째 always@(negedge sclk or posedge rst)를 통해 반복되는 코드들은 mosi 데이터를 전달 받아 각 비트의 데이터가 의미하는 바에 맞게 동작하는 코드에 해당한다.

 

먼저 rst이 High 신호를 전달 받는 순간 slave_register를 전부 0으로 초기화 시킨다.

idle은 초기화 상태를 뜻하며, 아무런 데이터가 전달되지 않은 무의 상태를 의미한다.

 

1. idle

newd는 0으로 초기화 시키고 cs == 1'b0 일 때 즉, ss를 선택되어 master와 slave가 데이터를 주고 받을 수 상태가 되면, sdi(mosi)를 통해 들어오는 첫번째 비트를 data_in에 저장하고, 첫번째 비트는 r/w Read/Write 값을 구분하는 비트이기 때문에 해당 값을 rw 변수에 저장하며 state를 collect로 변경한다.

 

2. collect

state가 collect일때 sdi(mosi)를 통해 데이터를 수집하는 상태를 의미한다.

sdi을 통해 들어오는 데이터를 우측 시프트 레지스터를 이용하여 기존 data_in에 값을 저장한다.

count == 7일 때 8비트 데이터를 전부 전달한 것과 동일하기 때문에 지금까지 들어온 데이터를 해석하게 된다.

  2.1. mosi로 전달된 첫번째 비트가 0(read)일 때 1, 2번째 비트는 slave_register의 address를 뜻하기 때문에 address 변수에 해당 값을 저장하며, Read일 경우 slave_register에 저장된 값을 불러와 master로 전달하는 것이기 때문에

tmp_register <= slave_register[data_in[2:1]];

 

코드를 통해 해당 주소에 있는 데이터를 임시 데이터 저장소인 tmp_register 변수에 저장한다. 또한 read 상태일 때 동작하기 위한 state_rw 상태를 read로 변경한다.

  2.2. mosi로 전달된 첫번째 비트가 1(write)일 때 1, 2번째 비트는 동일하게 address를 의미하고, Write일 경우 slave_register에 데이터를 저장해야 하기 때문에 mosi로 전달된 data_in의 [7:3]의 값을 임시 데이터 저장소인 tmp_register에 저장한다. 또한 write 상태일 때 동작하기 위한 state_rw 상태를 write로 변경한다.

 

3. collect의 count가 8일 경우 else 구문이 실행되며, state를 다시 idle 초기화 상태로 되돌리며, miso를 통해 master로 데이터를 전달하기 위해 새로운 데이터가 들어왔다는 의미인 newd <= 1'b1로, mosi에 실질적으로 데이터를 전달할 dout_t 변수에 data_in 데이터를 전달한다.


두번째 always

always @(posedge sclk)
    begin
        case(state_rw)
            0:
            begin
            end
            read:
            begin
                if(count == 8)
                begin
                    data_in <= {tmp_register, address, rw};
                end
            end
            
            write:
            begin
                if(count == 8)
                begin
                    slave_register[address] <= tmp_register;
                    data_in <= {5'b00000, address, rw};
                    
                end
            end
            
            default: state <= 0;
        endcase
     end

두번째 always의 경우 state_rw 상태에 해당하며 해당 상태는 read와 write 상태일 때 동작할 상태를 정의하고 있다.

 

1. read

state_rw가 read일 경우 count == 8일 때 (count는 7까지만 mosi로부터 데이터를 수집하고 count가 8인 sclk 한 주기의 시간 동안 miso로 master로 데이터를 전달할 준비를 한다.) sclk의 반주기에 해당하는 rising edge 일 때

data_in <= {tmp_register, address, rw};

 

miso로 전달할 데이터를 수집하는 data_in 변수에 collect 상태에서 수집한 slave_register[address]에 해당하는 데이터를 임시 저장하고 있는 tmp_register를 포함하여 8비트의 데이트를 data_in에 저장하여 miso 데이터로 전달한다.

 

2. write

state_rw가 write일 경우 count == 8일 때 

slave_register[address] <= tmp_register;
data_in <= {5'b00000, address, rw};

mosi로부터 전달받은 data_in의 5비트 데이터를 slave_register에 저장하고 data_in 변수에 5'b00000을 포함하여 데이터를 저장한다. 여기서 5'b00000을 전달하는 이유는 write일 경우 별도의 데이터를 master로 전달하지 않아도 되기 때문이다. (시나리오에 따라 입력할 데이터가 달라질 수 있다.) 


세번째 always

reg [3:0] count_o = 0;  
    reg [1:0] state_o = idle_o;

    always@(negedge sclk)
    begin
        case(state_o)
            idle_o: 
            begin
                if(newd == 1'b1 && cs == 1'b0)
                begin 
                    state_o <= send_o;
                    count_o <= 1;
                    sdo <= dout_t[0];
                end
                else
                begin
                    state_o <= idle_o;  
                end
            end  
 
            send_o: 
            begin
                if(count_o <= 7)
                begin
                    sdo <= dout_t[count_o];
                    count_o <= count_o + 1; 
                end 
                else
                begin
                    count_o <= 0;
                    state_o <= idle_o;
                end
            end
 
            default: ;
        endcase
    end

세번째 always는 sdo(miso)를 통해 slave에서 master로 데이터를 전달하는 코드에 해당한다.

count_o와 같이 뒤에 o를 붙인 이유는 output을 위한 변수임을 구분하기 위함이다.

 

1. idle_o

idle_o 상태는 초기화 상태로 newd == 1'b1 && cs == 1'b0일 때 (mosi로부터 데이터가 전달되어 miso로 데이터가 전달될 준비가 되었다는 상태 && ss == 0을 통해 master slave가 통신할 준비가 되었을 때)

state_o를 send_o의 상태로 변경하고 sdo(miso)를 통해 위 collect 상태를 통해 수집한 dout_t (dout_t <= data_in )를 한비트씩 master로 전달한다.

2. send_o

send_o 상태는 dout_t에 저장된 데이터를 count_o에 맞춰 한 비트씩 전달하는 단계에 해당한다.

8비트의 데이터가 전달되기 때문에 count_o가 8일 경우 다시 idle_o 초기화 상태로 변환한다.

Slave쪽 Test bench를 보게되면 cs가 0이고 sclk가 negedge일 때 mosi 데이터를 전달 받아 data_in을 통해 data가 저장되는 것을 확인 할 수 있고, mosi 데이터의 첫번째가 1이기 때문에 rw에 1이 저장되는 것을 확인할 수 있다.

count가 8일 경우 state_rw 상태에 맞게 동작하며 첫번째 비트가 1 (Write)였기 때문에 tmp_register = 5'b10011 의 값이 slave_register에 저장되는 것을 확인할 수 있다.

miso 데이터를 통해 master에 최종적으로 전달되는 데이터는 Write일 경우 {5'b00000,address,rw}에 해당하는 00000111의 값이 dout을 통해 전달되는 것을 확인할 수 있다.

728x90