Harman 세미콘 아카데미/SoC를 위한 Peripheral 설계

2024.11.11 [SoC를 위한 Peripheral 설계]10 - cpu의 구조와 동작원리4(Control_Block instance 진행하기)

U_Pong 2024. 11. 11. 14:51

2024.11.11 수업날


< Control_Block instance >

이번에는 저번에 만들었던 Control_Block에 대해서 마저 만들어본다.

아래의 그림의 Control_Block을 만드는 것이다.

CPU 동작 원리

 

 

12 bit ring counter source code
/////////////////////////////////////////////// 2024.11.11
module ring_counter_clk12(
      input clk, reset_p,
      output reg [11:0] t);
      
      always @(posedge clk or posedge reset_p) begin
            if(reset_p) t = 12'b0000_0000_0000;
            else begin
                  if(t == 0) t = 12'b0000_0000_0001;
                  else if(t == 12'b1000_0000_0000) t = 12'b0000_0000_0001;
                  else t = {t[10:0], 1'b0};
            end
      end
      
endmodule

 

 

ring_counter_clk12 모듈은 12 bit ring counter를 사용하여 Control_Block에 인스턴스 하기 위한 것이다.

ring counter의 0 bit에 따라 1이면 pc_oen에 1을 출력하고, 0이면 pc_oen에 0을 출력한다.

 

 

instr_decoder source code
//////////////////////////////////////////////////
module instr_decoder(
      input [7:0] ir_data,
      output reg nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
                        shr, load, jz, jmp, jge, div_s, mul_s, 
                        mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
                        mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
                        mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr);

      always @(ir_data) begin
            {nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
            shr, load, jz, jmp, jge, div_s, mul_s, 
            mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
            mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
            mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr} = 0;
            case(ir_data) 
                  8'h00 : nop = 1;
                  8'h0B : outb = 1;
                  8'h07 : outs = 1;
                  8'h50 : add_s = 1;
                  8'h52 : sub_s = 1;
                  8'h54 : and_s = 1;
                  8'h55 : div_s = 1;
                  8'h51 : mul_s = 1;
                  
                  8'h15 : shl = 1;
                  8'h10 : clr_s = 1;
                  8'h14 : psah = 1;
                  8'h16 : shr = 1;
                  8'hD6 : load = 1;
                  8'hD0 : jz = 1;
                  8'hD4 : jmp = 1;
                  8'hD2 : jge = 1;
                  
                  8'h83 : mov_ah_cr = 1;
                  8'h84 : mov_ah_dr = 1;
                  8'h88 : mov_tmp_ah = 1;
                  8'h8A : mov_tmp_br = 1;
                  8'h8B : mov_tmp_cr = 1;
                  8'h8C : mov_tmp_dr = 1;
                  8'h8D : mov_tmp_rr = 1;
                  8'h98 : mov_cr_ah = 1;
                  8'h9A : mov_cr_br = 1;
                  8'hA0 : mov_dr_ah = 1;
                  8'hA1 : mov_dr_tmp = 1;
                  8'hA2 : mov_dr_br = 1;
                  8'hA8 : mov_rr_ah = 1;
                  8'hB0 : mov_key_ah = 1;
                  8'hB9 : mov_inr_tmp = 1;
                  8'hBD : mov_inr_rr = 1;
                  default : nop = 1;  
            endcase
      end

endmodule

 

 

instr_decoder 모듈은 아래의 표를 보고 만들었다.

아래의 표에서 Hexa Code는 기계어로 변환하는 것이다.

C언어에서 의도한대로 코드를 작성하고 Build를 하는 것과 같은 방식인데, 이때 Build를 하면 기계어로 변환되는 것이다.

- NOP: IDLE 상태

- SHL: SHIFT LEFT
- PSAH: Perrel shift accumulator high
- SHR : SHIFT RIGHT
- JZ: JUMP ZERO
- JMP: JUMP
- JGE: JUMP GRATE EQUAL

 

 

다음으로, 각 output이 어떤 t에 속해있는지를 구분하여 코드를 작성해야한다.

아래의 표들을 보고 참고하여 작성하면 된다.

 

곱셈, 나눗셈의 경우

 

 

 

control_signal source code
///////////////////////////////////////////////////
module control_signal(
      input [11:0] t,
      input nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
            shr, load, jz, jmp, jge, div_s, mul_s, 
            mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
            mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
            mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr,
      input zero_flag, sign_flag, 
      output mar_inen, mdr_inen, mdr_oen, ir_inen, pc_inc, load_pc, pc_oen, breg_inen,
      output [1:0] acc_high_reset_p, acc_oen, acc_in_select,
      output [1:0] acc_high_select_in, acc_low_select,
      output op_add, op_sub, op_mul, op_div, op_and,
      output tmpreg_inen, tmpreg_oen, creg_inen, creg_oen, 
      output dreg_inen, dreg_oen, rreg_inen, rreg_oen, 
      output outreg_inen, keychreg_oen, inreg_oen, keyout_inen, rom_en);
      
      assign pc_oen = t[0] | (t[3] & (load | jz | jmp | jge));
      assign mar_inen = t[0] | (t[3] & (load | jz | jmp | jge));
      assign pc_inc = t[1] | (t[4] & (load | jz | jmp | jge));
      
      ////////////////////
      assign rom_en = ~(t[1] | (t[4] & (load | jz | jmp | jge)));
      assign mdr_inen = t[1] | (t[4] & (load | jz | jmp | jge));
      assign mdr_oen = t[2] | (t[5] & (load | (jz & zero_flag) | jmp | (jge & ~sign_flag)));
      assign load_pc = t[5] & ((zero_flag & jz) | (~sign_flag & jge) | jmp);
      assign ir_inen = t[2];
      
      assign tmpreg_oen = t[3] & (outb | mov_tmp_ah | mov_tmp_br | mov_tmp_cr | mov_tmp_dr | mov_tmp_rr);
      assign keyout_inen = t[3] & outb;
      assign acc_oen = t[3] & (outs | mov_ah_cr | mov_ah_dr);
      assign outreg_inen = t[3] & outs;
      
      assign op_add = t[3] & add_s;
      assign acc_high_select_in[0] = (t[3] & (add_s | sub_s | and_s | mul_s | shr | mov_tmp_ah | mov_cr_ah | mov_rr_ah | mov_key_ah | mov_dr_ah)) | (t[4] & (add_s | div_s | mul_s)) | (mul_s & (t[5] | t[6] | t[7] | t[8] | t[9] | t[10])) | (div_s & (t[6] | t[8] | t[10]));
      assign acc_high_select_in[1] = (t[3] & (add_s | sub_s | and_s | div_s | mul_s | shl | mov_tmp_ah | mov_cr_ah | mov_rr_ah | mov_key_ah | mov_dr_ah)) | (mul_s & (t[5] | t[7] | t[9])) | (div_s & (t[4] | t[5] | t[6] | t[7] | t[8] | t[9] | t[10]));
      assign op_sub = t[3] & sub_s;
      assign op_and = t[3] & and_s;
      assign acc_low_select[0] = (t[3] & (psah | shr)) | (t[4] & (add_s|mul_s)) | (t[6] & mul_s) | (t[8] & mul_s) | (t[10] & mul_s);
      assign acc_low_select[1] = (t[3] & (shl | psah | div_s)) | (t[5] & div_s) | (t[7] & div_s) | (t[9] & div_s) | (t[11] & div_s);
      assign acc_high_reset_p = t[3] & clr_s;
      
      assign op_div = (t[4] & div_s) | (t[6] & div_s) | (t[8] & div_s) | (t[10] & div_s);
      assign op_mul = (t[3] & mul_s) | (t[5] & mul_s) | (t[7] & mul_s) | (t[9] & mul_s);
      
      assign creg_inen = t[3] & (mov_ah_cr | mov_tmp_cr);
      assign dreg_inen = t[3] & (mov_ah_dr | mov_tmp_dr );
      assign acc_in_select = t[3] & (mov_tmp_ah | mov_cr_ah | mov_dr_ah | mov_rr_ah | mov_key_ah);
      assign breg_inen = t[3] & (mov_tmp_br | mov_cr_br | mov_dr_br);
      assign rreg_inen = t[3] & (mov_tmp_rr | mov_inr_rr);
      
      assign creg_oen = t[3] & (mov_cr_ah | mov_cr_br);
      assign dreg_oen = t[3] & (mov_dr_ah | mov_dr_tmp | mov_dr_br);
      assign tmpreg_inen = (t[5] & load) | t[3] & (mov_dr_tmp | mov_inr_tmp);
      assign rreg_oen = t[3] & mov_rr_ah;
      assign keychreg_oen = t[3] & mov_key_ah;
      assign inreg_oen = t[3] & (mov_inr_tmp | mov_inr_rr);
      
endmodule

 

 

이제 위에서 만들었던 코드들을 Control_Block에 인스턴스 한다.

Control_Block source code
//////////////////////////////////// 2024.11.11 -> 인스턴스 진행
module Control_Block(
      input clk, reset_p,
      input [7:0] ir_data,
      input zero_flag, sign_flag,
      output mar_inen, mdr_inen, mdr_oen, ir_inen, pc_inc, load_pc, pc_oen, breg_inen,
      output [1:0] acc_high_reset_p, acc_oen, acc_in_select,
      output [1:0] acc_high_select_in, acc_low_select,
      output op_add, op_sub, op_mul, op_div, op_and,
      output tmpreg_inen, tmpreg_oen, creg_inen, creg_oen, 
      output dreg_inen, dreg_oen, rreg_inen, rreg_oen, 
      output outreg_inen, keychreg_oen, inreg_oen, keyout_inen, rom_en);
      
      wire [11:0] t;
      ring_counter_clk12 rcount(.clk(clk), .reset_p(reset_p), .t(t));
      
      wire nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
            shr, load, jz, jmp, jge, div_s, mul_s, 
            mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
            mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
            mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr;
      instr_decoder i_decoder(
            ir_data,
            nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
            shr, load, jz, jmp, jge, div_s, mul_s, 
            mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
            mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
            mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr);
      
      control_signal cs(
            t,
            nop, outb, outs, add_s, sub_s, and_s, shl, clr_s, psah, 
            shr, load, jz, jmp, jge, div_s, mul_s, 
            mov_ah_cr, mov_ah_dr, mov_tmp_ah, mov_tmp_br, mov_tmp_cr,
            mov_tmp_dr, mov_tmp_rr, mov_cr_ah, mov_cr_br, mov_dr_ah, mov_dr_tmp, 
            mov_dr_br, mov_rr_ah, mov_key_ah, mov_inr_tmp, mov_inr_rr,
            zero_flag, sign_flag, 
            mar_inen, mdr_inen, mdr_oen, ir_inen, pc_inc, load_pc, pc_oen, breg_inen,
            acc_high_reset_p, acc_oen, acc_in_select,
            acc_high_select_in, acc_low_select,
            op_add, op_sub, op_mul, op_div, op_and,
            tmpreg_inen, tmpreg_oen, creg_inen, creg_oen, 
            dreg_inen, dreg_oen, rreg_inen, rreg_oen, 
            outreg_inen, keychreg_oen, inreg_oen, keyout_inen, rom_en);
      
endmodule

cpu의 구조와 동작원리4(Control_Block instance 진행하기) 끝!