일단

wishbone.v에서 보이는 data는 다음과 같다.

i_portx_wdata

이고 이것은


mem.v에서 o_wb_write_data로 연결된다.

이것은 알다시피 32bit로 filtering된 i_write_data를 4번 연속해서 쓴 것일 뿐이다.

그럼 이 i_write_data는 어디서 왔냐 보면


execute.v에서 o_write_data와 연결되어 있다.

o_write_data            <= write_data_update              ? write_data_nxt               : o_write_data;

이므로, 봐야 할 것은 write_data_nxt이다.(32bits)

assign write_data_nxt = i_byte_enable_sel == 2'd0 ?   rd   :    {4{rd[ 7:0]}} ;

이렇게 되어있는데, i_byte_enable_sel == 0이면 rd를 그대로 내고 아니면 rd의 8bit를 4번 반복해서 낸다는 것이다.

여기서 rd를 살펴보면(32bits)

assign rd = i_rd_use_read && i_rs_sel == load_rd_c[3:0] && status_bits_mode == load_rd_c[5:4] ? read_data_filtered_c : reg_bank_rd; 이렇게 나온다.

앞에 것들은 모두 조건들이고 뒤에는 결국

read_data_filtered_c 혹은 reg_bank_rd가 write 할 32bits짜리 data가 된다.

1. 그렇다면 일단 read_data_filtered_c부터 살펴보면

assign read_data_filtered_c = i_wb_read_data_valid ? read_data_filtered : read_data_filtered_r;

이렇게 된다. 이것은 read_data가 valid하다면 read_data_filtered가 들어오고 아니면 r이 들어간다.

1-1. read_data_filtered는 다음과 같다.

assign read_data_filtered  = i_wb_load_rd[4] ? {24'd0, read_data_filtered1[7:0]} : read_data_filtered1 ;

여기서 filter read data는 다음과 같은 condition에 따른다.

// mem_load_rd[10:9]-> shift ROR bytes
// mem_load_rd[8]   -> load flags with PC
// mem_load_rd[7]   -> load status bits with PC
// mem_load_rd[6:5] -> Write into this Mode registers
// mem_load_rd[4]   -> zero_extend byte
// mem_load_rd[3:0] -> Destination Register

그러므로, 위의 것에서 read_data_filtered는 i_wb_load_rd[4]가 1이면 zero_extend byte가 1이기에 앞에 24bits에 0을 넣어주는 것이다.


그리고 read_data_filtered1은 다음과 같다.

 assign read_data_filtered1 =

i_wb_load_rd[10:9] == 2'd0 ? i_wb_read_data                                :

i_wb_load_rd[10:9] == 2'd1 ? {i_wb_read_data[7:0],  i_wb_read_data[31:8]}  :

i_wb_load_rd[10:9] == 2'd2 ? {i_wb_read_data[15:0], i_wb_read_data[31:16]} :

{i_wb_read_data[23:0], i_wb_read_data[31:24]} ;

위에서 말했듯이 저 [10:9]는 shift ROR bytes이다.


그럼 여기서 결국 들어가는 data는 rotate 되었거나 혹은 zero extend가 된 i_wb_read_data이다.

(32bits 짜리 데이터가 rotate된 것이기에 다른 96 bits는 아무런 상관이 없다.)

이것은 write_back.v의 o_wb_read_data와 연결되어 있는데, 이것은

내부에서 mem_read_data_r 에 assign 되어 있다. 이것은 i_mem_read_data와 연결되어 있는데, 이것은 또 mem.v의 o_mem_read_data와 연결되어 있다. 그 내부에서는

assign o_mem_read_data          = use_mem_reg ? mem_read_data_r       : mem_read_data_c;

이렇게 연결이 되어 있는데, mem_read_data_r은 결국 mem_read_data_c와 연결이 되어 있고,

mem_read_data_c는 다음과 같다.

assign mem_read_data_c          = sel_cache                     ? cache_read_data :
                                                uncached_data_access  ? wb_rdata32      :
                                                                                      32'h76543210    ;

cache와 연괸이 있다면 cache_read_data이고 uncached data access라면 wb_rdata32이다.

1-1-1. cache_read_data는 dcache.v에 o_read_data와 연결되어 있다.

그 내부에서 o_read_data는 다음과 같이 연결되어 있다.

assign o_read_data  =

                      i_address[WORD_SEL_MSB:WORD_SEL_LSB] == 2'd0 ? read_data128 [31:0]   :
                      i_address[WORD_SEL_MSB:WORD_SEL_LSB] == 2'd1 ? read_data128 [63:32]  :
                      i_address[WORD_SEL_MSB:WORD_SEL_LSB] == 2'd2 ? read_data128 [95:64]  :
                                                                                                     read_data128 [127:96] ;

read_data128은 wb_hit ? i_wb_cached_rdata : hit_rdata; 로 되어있고

i_wb_cached_rdata는 core쪽에서는 dcache_wb_cached_rdata로 들어온다.

hit_rdata는 data_rdata_way[i]로 data_rdata_way[i]가 cache와 연결이 되어 있는 것 같다.


1-1-2. wb_rdata32는 바로 mem.v의 내부에서 보인다.

assign wb_rdata32               = i_daddress[3:2] == 2'd0 ? i_wb_uncached_rdata[ 31: 0] :
                                            i_daddress[3:2] == 2'd1 ? i_wb_uncached_rdata[ 63:32] :
                                            i_daddress[3:2] == 2'd2 ? i_wb_uncached_rdata[ 95:64] :
                                                                                i_wb_uncached_rdata[127:96] ;


1-2-1. execute.v에서 read_data_filtered_r에 대해서 알아보면 다음과 같다.

always@( posedge i_clk )
    if ( i_wb_read_data_valid )
        begin
        read_data_filtered_r <= read_data_filtered;
        load_rd_r            <= {i_wb_load_rd[6:5], i_wb_load_rd[3:0]};
        end

그러므로, read_data_filtered와 같다고 보면 된다.


2. execute.v에서 reg_bank_rd가 뭔지 살펴보면 register_bank.v에 o_rd와 연결되어 있다.

내부에서 보면

always @*
    case ( i_rs_sel )
       4'd0  :  o_rd = r0_out  ;
       4'd1  :  o_rd = r1_out  ;
       4'd2  :  o_rd = r2_out  ;
       4'd3  :  o_rd = r3_out  ;
       4'd4  :  o_rd = r4_out  ;
       4'd5  :  o_rd = r5_out  ;
       4'd6  :  o_rd = r6_out  ;
       4'd7  :  o_rd = r7_out  ;
       4'd8  :  o_rd = r8_rds  ;
       4'd9  :  o_rd = r9_rds  ;
       4'd10 :  o_rd = r10_rds ;
       4'd11 :  o_rd = r11_rds ;
       4'd12 :  o_rd = r12_rds ;
       4'd13 :  o_rd = r13_rds ;
       4'd14 :  o_rd = r14_rds ;
       default: o_rd = r15_out_rm_nxt ;
    endcase

이런 것을 볼 수 있는데, 이것들은 다음과 같이 assign 되어있다.

assign r0_out = r0;
assign r1_out = r1;
assign r2_out = r2;
assign r3_out = r3;
assign r4_out = r4;
assign r5_out = r5;
assign r6_out = r6;
assign r7_out = r7;

assign r8_out  = firq_exec ? r8_firq  : r8;
assign r9_out  = firq_exec ? r9_firq  : r9;
assign r10_out = firq_exec ? r10_firq : r10;
assign r11_out = firq_exec ? r11_firq : r11;
assign r12_out = firq_exec ? r12_firq : r12;

assign r13_out = usr_exec ? r13      :
                 svc_exec ? r13_svc  :
                 irq_exec ? r13_irq  :
                          r13_firq ;
                      
assign r14_out = usr_exec ? r14      :
                 svc_exec ? r14_svc  :
                 irq_exec ? r14_irq  :
                          r14_firq ;


그러면 r0, r1, r2, r3 등등은 모두 32bits reg인데,

어떻게 해서 결정되는지를 보려면 다음과 같다.

always @ ( posedge i_clk )
    begin
    // these registers are used in all modes
    r0       <= reg_bank_wen_c[0 ]               ? i_reg : read_data_wen[0 ]                      ? i_wb_read_data       : r0; 
    r1       <= reg_bank_wen_c[1 ]               ? i_reg : read_data_wen[1 ]                      ? i_wb_read_data       : r1; 
    r2       <= reg_bank_wen_c[2 ]               ? i_reg : read_data_wen[2 ]                      ? i_wb_read_data       : r2; 
    r3       <= reg_bank_wen_c[3 ]               ? i_reg : read_data_wen[3 ]                      ? i_wb_read_data       : r3; 
    r4       <= reg_bank_wen_c[4 ]               ? i_reg : read_data_wen[4 ]                      ? i_wb_read_data       : r4; 
    r5       <= reg_bank_wen_c[5 ]               ? i_reg : read_data_wen[5 ]                      ? i_wb_read_data       : r5; 
    r6       <= reg_bank_wen_c[6 ]               ? i_reg : read_data_wen[6 ]                      ? i_wb_read_data       : r6; 
    r7       <= reg_bank_wen_c[7 ]               ? i_reg : read_data_wen[7 ]                      ? i_wb_read_data       : r7; 
   
    // these registers are used in all modes, except fast irq
    r8       <= reg_bank_wen_c[8 ] && !firq_idec ? i_reg : read_data_wen[8 ] && i_wb_mode != FIRQ ? i_wb_read_data       : r8; 
    r9       <= reg_bank_wen_c[9 ] && !firq_idec ? i_reg : read_data_wen[9 ] && i_wb_mode != FIRQ ? i_wb_read_data       : r9; 
    r10      <= reg_bank_wen_c[10] && !firq_idec ? i_reg : read_data_wen[10] && i_wb_mode != FIRQ ? i_wb_read_data       : r10;
    r11      <= reg_bank_wen_c[11] && !firq_idec ? i_reg : read_data_wen[11] && i_wb_mode != FIRQ ? i_wb_read_data       : r11;
    r12      <= reg_bank_wen_c[12] && !firq_idec ? i_reg : read_data_wen[12] && i_wb_mode != FIRQ ? i_wb_read_data       : r12;
   
    // these registers are used in fast irq mode
    r8_firq  <= reg_bank_wen_c[8 ] &&  firq_idec ? i_reg : read_data_wen[8 ] && i_wb_mode == FIRQ ? i_wb_read_data       : r8_firq;
    r9_firq  <= reg_bank_wen_c[9 ] &&  firq_idec ? i_reg : read_data_wen[9 ] && i_wb_mode == FIRQ ? i_wb_read_data       : r9_firq;
    r10_firq <= reg_bank_wen_c[10] &&  firq_idec ? i_reg : read_data_wen[10] && i_wb_mode == FIRQ ? i_wb_read_data       : r10_firq;
    r11_firq <= reg_bank_wen_c[11] &&  firq_idec ? i_reg : read_data_wen[11] && i_wb_mode == FIRQ ? i_wb_read_data       : r11_firq;
    r12_firq <= reg_bank_wen_c[12] &&  firq_idec ? i_reg : read_data_wen[12] && i_wb_mode == FIRQ ? i_wb_read_data       : r12_firq;

    // these registers are used in user mode
    r13      <= reg_bank_wen_c[13] &&  usr_idec  ? i_reg : read_data_wen[13] && i_wb_mode == USR ? i_wb_read_data        : r13;        
    r14      <= reg_bank_wen_c[14] &&  usr_idec  ? i_reg : read_data_wen[14] && i_wb_mode == USR ? i_wb_read_data        : r14;        
 

그러면 이것들은 condition에 따라서, i_reg가 저장이 되거나 혹은 i_wb_read_data가 저장이 되거나 혹은 변화가 없게 될 것이다.

이것들은 둘다 밖에서 온 것들이다.


2-1. i_wb_read_data는 execute.v에서, read_data_filtered와 동일하다.


2-2. i_reg는 execute.v에서 reg_write_nxt라는 wire로 있는데 그것은 다음과 같다.

assign reg_write_nxt = i_reg_write_sel == 3'd0 ? alu_out               :
                               // save pc to lr on an interrupt
                               i_reg_write_sel == 3'd1 ? save_int_pc_m4        :
                               // to update Rd at the end of Multiplication
                               i_reg_write_sel == 3'd2 ? multiply_out          :
                               i_reg_write_sel == 3'd3 ? o_status_bits         :
                               i_reg_write_sel == 3'd5 ? i_copro_read_data     :  // mrc
                               i_reg_write_sel == 3'd6 ? base_address          :
                                                                  save_int_pc           ;



+ Recent posts