티스토리 뷰

 IDEC 강의 영상을 보고 정리한 내용입니다.

https://www.idec.or.kr/vod/apply/view/?pay=&search_val=CPU&no=273 

 

반도체설계교육센터

강의제목 CPU 설계 및 응용 구분 부산대 / 설계강좌 / 초급/중급 / 이론+실습 강의시간 13시간 열람기간 16일 이용료(일반) 무료 이용료(학생) 무료 강의개요 SoC 설계를 위해서 CPU를 설계하고 응용할

www.idec.or.kr

저번까지 설계한 CPU의 구조이다.

이번엔 control block을 만들겠다.

 

Control signal 생성

 

명령어를 실행하기위한 control signal을 타이밍별로 정리한 것이다. 위의 표를 토대로 다음과 같이 조합회로를 짜야한다.

후에 RISC-V processor도 만들것이기때문에 위의 표를 토대로 verilog code를 짜는 python프로그램을 짰다.

위의 표를 excel로 만든 후 파이썬 코드를 작성한 것이다.

from openpyxl import load_workbook
# load excel sheet
load_wb = load_workbook("파일 경로")

load_ws = load_wb['Sheet1']

# make signal list
sig_list = ["pc_oen", "mar_inen", "rom_en", "mdr_inen", "pc_inc", "mdr_oen", "ir_inen", "tmp_inen", "tmp_oen", "creg_inen"
    ,"creg_oen", "dreg_inen", "dreg_oen", "rreg_inen", "rreg_oen", "breg_inen", "inreg_oen", "keych_oen", "outreg_inen", "keyout_inen",
            "load_pc", "acc_oen", "ah_inen", "ah_reset", "hs[1]", "hs[0]", "ls[1]","ls[0]","adds", "subs", "ands", "divs", "muls"]

# make command list
com_list = []

for cell in load_ws['A']:
    com_list.append(cell.value)

for cell in com_list:
    print(cell,end = ', ')
print('\n')
for cell in sig_list:
    print(cell,end=', ')
print('\n')

for cell in sig_list:
    print("$monitor($time,\""+cell+"%b\","+cell+");")
# print(com_list)

com_index = -1
sig_index = 0

# make str list
str_list = []

while sig_index != len(sig_list):
    # print('\n')
    # print(sig_list[sig_index])
    str_list.append(sig_list[sig_index])
    for column in load_ws.columns:
        #print(column)

        temp_list = []

        for cell in column:
            com_index = com_index + 1
            if com_index == len(com_list):
                break
            #print(cell.value)
            one_cell_str = str(cell.value)
            one_cell_str.split(", ")
            #print(one_cell_str.split(", "))

            if sig_list[sig_index] in one_cell_str:
                temp_list.append(com_list[com_index])

        com_index = -1

        if len(temp_list) != 0:
            if temp_list == com_list[1:]:
                temp_list.clear()
                temp_list.append(column[0].value)
                str_list.append(temp_list)
            else:
                #print(temp_list)
                temp_list.insert(0, column[0].value)
                str_list.append(temp_list)
        else:
            continue

    # print(str_list)

    sig_index = sig_index + 1

    # make string
    str_list_ = []
    str_index = 0
    for temp in str_list:
        if type(temp) == list:
            if len(temp) != 1:
                for temp_index in range(1, len(temp)):
                    if temp_index == 1:
                        temp.insert(temp_index, "& (")
                    else:
                        temp.insert(temp_index*2-1, "|")
            else:
                str_list_.append(temp)
                continue
            temp.append(')')
            temp.insert(0, '(')
            temp.append(')')
            str_list_.append(temp)


        else:
            str_list_.append(temp)
            continue

    str_list_.insert(1, '=')
    for temp_index in range(2,len(str_list_)-1):
        str_list_.insert(temp_index*2-1, '|')

    # print(str_list_)
    str_list.clear()

    str_real = "assign "
    for temp in str_list_:
        if type(temp) != list:
            str_real += temp + " "
        else:
            str_temp = ""
            for s in temp:
                str_temp += s + " "
            str_real += str_temp
    str_real = str_real + ';'
    print(str_real)

파이썬 코드를 실행시키면 다음과 같이 signal 신호를 verilog code로 바꿀 수 있다. MUL연산이나 DIV연산등은 결합법칙으로 수정을 해줘야한다. 또한 z_flag와 s_flag를 포함하지 않았기때문에 이와 관련된 control신호를 바꿔줘야한다.

조금 수정을 거친 verilog코드는 다음과 같다.

`timescale 1ns / 1ps

module control_signal(t,s_flag,z_flag,nop, outb, outs, add_s, sub_s, and_s, shl,
 clr_s, psah, shr, load, jz, jmp, jge, 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, div_s, mul_s,
 pc_oen, mar_inen, rom_en, mdr_inen, pc_inc, mdr_oen, ir_inen, 
 tmp_inen, tmp_oen, creg_inen, creg_oen, dreg_inen, dreg_oen, 
 rreg_inen, rreg_oen, breg_inen, inreg_oen, keych_oen, outreg_inen, 
 keyout_inen, load_pc, acc_oen, ah_inen, ah_reset, hs,ls, adds, subs, ands, divs, muls
);
input [11:0] t;
input s_flag,z_flag,nop, outb, outs, add_s, sub_s, and_s, shl,
 clr_s, psah, shr, load, jz, jmp, jge, 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, div_s, mul_s;
 output pc_oen, mar_inen, rom_en, mdr_inen, pc_inc, mdr_oen, ir_inen, 
 tmp_inen, tmp_oen, creg_inen, creg_oen, dreg_inen, dreg_oen, 
 rreg_inen, rreg_oen, breg_inen, inreg_oen, keych_oen, outreg_inen, 
 keyout_inen, load_pc, acc_oen, ah_inen, ah_reset,adds, subs, ands, divs, muls;
 output [1:0] hs;
 output [1:0] ls;
assign pc_oen = t[0] | ( t[3] & ( load | jz | jmp | jge ) ) ;
assign mar_inen = t[0] | ( t[3] & ( load | jz | jmp | jge ) ) ;
assign rom_en = ~(t[1]|((load|jz|jmp|jge)&t[4]));
assign mdr_inen = t[1] | ( t[4] & ( load | jz | jmp | jge ) ) ;
assign pc_inc = t[1] | ( t[4] & ( load | jz | jmp | jge ) ) ;
assign mdr_oen = t[2] | ( t[5] & ( load | jz | jmp | jge ) ) ;
assign ir_inen = t[2] ;
assign tmp_inen = ( t[3] & ( mov_dr_tmp | mov_inr_tmp ) ) | ( t[5] & ( load ) ) ;
assign tmp_oen = ( t[3] & ( outb | mov_tmp_ah | mov_tmp_br | mov_tmp_cr | mov_tmp_dr | mov_tmp_rr ) ) ;
assign creg_inen = ( t[3] & ( mov_ah_cr | mov_tmp_cr ) ) ;
assign creg_oen = ( t[3] & ( mov_cr_ah | mov_cr_br ) ) ;
assign dreg_inen = ( t[3] & ( mov_ah_dr | mov_tmp_dr ) ) ;
assign dreg_oen = ( t[3] & ( mov_dr_ah | mov_dr_tmp | mov_dr_br ) ) ;
assign rreg_inen = ( t[3] & ( mov_tmp_rr | mov_inr_rr ) ) ;
assign rreg_oen = ( t[3] & ( mov_rr_ah ) ) ;
assign breg_inen = ( t[3] & ( mov_tmp_br | mov_cr_br | mov_dr_br ) ) ;
assign inreg_oen = ( t[3] & ( mov_inr_tmp | mov_inr_rr ) ) ;
assign keych_oen = ( t[3] & ( mov_key_ah ) ) ;
assign outreg_inen = ( t[3] & ( outs ) ) ;
assign keyout_inen = ( t[3] & ( outb ) ) ;
assign load_pc = ( t[5] & ( jz | jmp | jge ) ) ;
assign acc_oen = ( t[3] & ( outs | mov_ah_cr | mov_ah_dr ) ) ;
assign ah_inen = ( t[3] & ( mov_tmp_ah | mov_cr_ah | mov_dr_ah | mov_rr_ah | mov_key_ah ) ) ;
assign ah_reset = ( t[3] & ( clr_s ) ) ;
assign hs[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 hs[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 ls[1] = (t[3]&(div_s|psah|shl))|(div_s&(t[5]|t[7]|t[9]|t[11]));
assign ls[0] = (t[3]&(psah|shr))|(t[4]&(add_s|mul_s))|(mul_s&(t[6]|t[8]|t[10]));
assign adds = ( t[3] & ( add_s ) ) ;
assign subs = ( t[3] & ( sub_s ) ) ;
assign ands = ( t[3] & ( and_s ) ) ;
assign divs = div_s&(t[4]|t[6]|t[8]|t[10]);
assign muls = mul_s&(t[3]|t[5]|t[7]|t[9]); 
endmodule

 

Control block

위에서 만든 signal을 생성하는 module과 앞서 설계한 ring counter, decoder를 사용하여 control block을 만들 수 있다.

 

module control_block(z_f,s_f,clk,clr,opcode,pc_oen,mar_inen,rom_en,mdr_inen, 
pc_inc,mdr_oen,ir_inen,tmp_inen,tmp_oen,creg_inen,creg_oen, 
dreg_inen, dreg_oen,rreg_inen,rreg_oen,breg_inen,inreg_oen,keych_oen,
outreg_inen, keyout_inen, load_pc,acc_oen,ah_inen,ah_reset,adds,subs, 
ands,divs,muls,hs,ls);
input [7:0] opcode; 
input z_f,s_f,clk,clr;
output pc_oen,mar_inen,rom_en,mdr_inen,pc_inc,mdr_oen,ir_inen,tmp_inen,
tmp_oen,creg_inen,creg_oen,dreg_inen,dreg_oen,rreg_inen, rreg_oen, 
breg_inen,inreg_oen,keych_oen,outreg_inen,keyout_inen,
load_pc,acc_oen,ah_inen,ah_reset,adds,subs,ands,divs,muls;
output [1:0] hs,ls; 
wire [11:0] t; 
//decoder.v의 출력과 ctrl_signal.v 입력의 연결선
wire nop,outb,outs,add_s,sub_s,and_s, 
div_s,mul_s,shl,clr_s,psah,shr,load, 
jz,jmp,jge, 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; 
ringCounter u0(.clk(clk), .clr(clr), .t(t)); 
decoder u1(.ir_in(opcode),
.nop(nop),
.outb(outb),
.outs(outs),
.add_s(add_s),
.sub_s(sub_s),
.and_s(and_s),
.div_s(div_s),
.mul_s(mul_s),
.shl(shl),
.clr_s(clr_s),
.psah(psah),
.shr(shr),
.load(load),
.jz(jz),
.jmp(jmp),
.jge(jge),
.mov_ah_cr(mov_ah_cr),
.mov_ah_dr(mov_ah_dr),
.mov_tmp_ah(mov_tmp_ah),
.mov_tmp_br(mov_tmp_br),
.mov_tmp_cr(mov_tmp_cr),
.mov_tmp_dr(mov_tmp_dr),
.mov_tmp_rr(mov_tmp_rr),
.mov_cr_ah(mov_cr_ah),
.mov_cr_br(mov_cr_br),
.mov_dr_ah(mov_dr_ah),
.mov_dr_tmp(mov_dr_tmp),
.mov_dr_br(mov_dr_br),
.mov_rr_ah(mov_rr_ah),
.mov_key_ah(mov_key_ah),
.mov_inr_tmp(mov_inr_tmp),
.mov_inr_rr(mov_inr_rr)
);
control_signal u2(.t(t),
.s_flag(s_f),
.z_flag(z_f),
.nop(nop),
.outb(outb),
.outs(outs),
.add_s(add_s),
.sub_s(sub_s),
.and_s(and_s),
.div_s(div_s),
.mul_s(mul_s),
.shl(shl),
.clr_s(clr_s),
.psah(psah),
.shr(shr),
.load(load),
.jz(jz),
.jmp(jmp),
.jge(jge),
.mov_ah_cr(mov_ah_cr),
.mov_ah_dr(mov_ah_dr),
.mov_tmp_ah(mov_tmp_ah),
.mov_tmp_br(mov_tmp_br),
.mov_tmp_cr(mov_tmp_cr),
.mov_tmp_dr(mov_tmp_dr),
.mov_tmp_rr(mov_tmp_rr),
.mov_cr_ah(mov_cr_ah),
.mov_cr_br(mov_cr_br),
.mov_dr_ah(mov_dr_ah),
.mov_dr_tmp(mov_dr_tmp),
.mov_dr_br(mov_dr_br),
.mov_rr_ah(mov_rr_ah),
.mov_key_ah(mov_key_ah),
.mov_inr_tmp(mov_inr_tmp),
.mov_inr_rr(mov_inr_rr),
.pc_oen(pc_oen),
.mar_inen(mar_inen),
.rom_en(rom_en),
.mdr_inen(mdr_inen),
.pc_inc(pc_inc),
.mdr_oen(mdr_oen),
.ir_inen(ir_inen),
.tmp_inen(tmp_inen),
.tmp_oen(tmp_oen),
.creg_inen(creg_inen),
.creg_oen(creg_oen),
.dreg_inen(dreg_inen),
.dreg_oen(dreg_oen),
.rreg_inen(rreg_inen),
.rreg_oen(rreg_oen),
.breg_inen(breg_inen),
.inreg_oen(inreg_oen),
.keych_oen(keych_oen),
.outreg_inen(outreg_inen),
.keyout_inen(keyout_inen),
.load_pc(load_pc),
.acc_oen(acc_oen),
.ah_inen(ah_inen),
.ah_reset(ah_reset),
.adds(adds),
.subs(subs),
.ands(ands),.divs(divs),
.muls(muls), .hs(hs),
.ls(ls) );
endmodule
`timescale 1ns / 1ps
module tb_control_block;
reg [7:0] opcode;
reg z_f,s_f,clk,clr; 
wire pc_oen,mar_inen,rom_en,mdr_inen, 
pc_inc,mdr_oen,ir_inen,tmp_inen, 
tmp_oen,creg_inen,creg_oen,dreg_inen, 
dreg_oen,rreg_inen, rreg_oen, 
breg_inen,inreg_oen,keych_oen,outreg_inen,keyout_inen,load_pc,acc_oen, 
ah_inen,ah_reset,adds,subs,ands,divs,muls;
wire [1:0] hs,ls; 
control_block UUT(z_f,s_f,clk,clr,opcode, 
pc_oen,mar_inen,rom_en,mdr_inen, 
pc_inc,mdr_oen,ir_inen,tmp_inen,tmp_oen,creg_inen,creg_oen, dreg_inen, 
dreg_oen,rreg_inen,rreg_oen,breg_inen,inreg_oen,keych_oen, outreg_inen, 
keyout_inen,load_pc,acc_oen,ah_inen,ah_reset,adds,subs, ands,divs, muls,hs,ls);
always #50 clk = ~clk;
initial begin
$monitor($time,"[t = %b]",UUT.t);
$monitor($time,"pc_oen%b",pc_oen);
$monitor($time,"mar_inen%b",mar_inen);
$monitor($time,"rom_en%b",rom_en);
$monitor($time,"mdr_inen%b",mdr_inen);
$monitor($time,"pc_inc%b",pc_inc);
$monitor($time,"mdr_oen%b",mdr_oen);
$monitor($time,"ir_inen%b",ir_inen);
$monitor($time,"tmp_inen%b",tmp_inen);
$monitor($time,"tmp_oen%b",tmp_oen);
$monitor($time,"creg_inen%b",creg_inen);
$monitor($time,"creg_oen%b",creg_oen);
$monitor($time,"dreg_inen%b",dreg_inen);
$monitor($time,"dreg_oen%b",dreg_oen);
$monitor($time,"rreg_inen%b",rreg_inen);
$monitor($time,"rreg_oen%b",rreg_oen);
$monitor($time,"breg_inen%b",breg_inen);
$monitor($time,"inreg_oen%b",inreg_oen);
$monitor($time,"keych_oen%b",keych_oen);
$monitor($time,"outreg_inen%b",outreg_inen);
$monitor($time,"keyout_inen%b",keyout_inen);
$monitor($time,"load_pc%b",load_pc);
$monitor($time,"acc_oen%b",acc_oen);
$monitor($time,"ah_inen%b",ah_inen);
$monitor($time,"ah_reset%b",ah_reset);
$monitor($time,"hs%b",hs);
$monitor($time,"ls%b",ls);
$monitor($time,"adds%b",adds);
$monitor($time,"subs%b",subs);
$monitor($time,"ands%b",ands);
$monitor($time,"divs%b",divs);
$monitor($time,"muls%b",muls);
// Initialize Inputs
s_f = 0; z_f = 0;
clk = 0; clr = 1;
opcode = 0;
#100; clr = 0; opcode = 8'h00;
#1200; opcode = 8'h0B;
#1200; opcode = 8'h07;
#1200; opcode = 8'h50;
#1200; opcode = 8'h52;
#1200; opcode = 8'h54;
#1200; opcode = 8'h15;
#1200; opcode = 8'h10;
#1200; opcode = 8'h14;
#1200; opcode = 8'h16;
#1200; opcode = 8'hD6;
#1200; opcode = 8'hD0;
#1200; opcode = 8'hD4;
#1200; opcode = 8'hD2;
#1200; opcode = 8'h83;
#1200; opcode = 8'h84;
#1200; opcode = 8'h88;
#1200; opcode = 8'h8A;
#1200; opcode = 8'h8B;
#1200; opcode = 8'h8C;
#1200; opcode = 8'h8D;
#1200; opcode = 8'h98;
#1200; opcode = 8'h9A;
#1200; opcode = 8'hA0;
#1200; opcode = 8'hA2;
#1200; opcode = 8'hA1;
#1200; opcode = 8'hA8;
#1200; opcode = 8'hB0;
#1200; opcode = 8'hB9;
#1200; opcode = 8'hBD;
#100;
end 
endmodule

이런식으로 control 신호가 만들어진 것을 볼 수 있다.

하지만 이를 검증하는 것은 매우 귀찮아서 다시 결과를 보기위해 python을 사용했다.

 

Control block 검증

control signal이 많기 때문에 monitor구문을 사용하기로했다. 

앞선 파이썬 코드에 위 구문이 포함되어있고 결과는 다음과 같다.

이것을 testbench에 복붙하고 simulation을 실행하면 tcl창에 다음과 같이 나타난다.

monitor는 변화가 생길 때마다 값을 출력해준다. 하지만 0->1로 변하는 것을 보려했기때문에 한번 더 처리가 필요했다. 이를 다시 excel로 복붙하고 파이썬 코드를 사용해 처리를 해주었다.

from openpyxl import load_workbook

load_wb = load_workbook("파일경로")

load_ws = load_wb['Sheet1']

time_list = []
for cell in load_ws['A']:
    time_list.append(cell.value)

for time_index in range(len(time_list)):
    if time_list[time_index].strip()[-1] == '0':
        if time_list[time_index].find("hs") != -1 or \
                time_list[time_index].find("ls") != -1 or \
                time_list[time_index].find("rom_en") != -1:
            continue
        else:
            time_list.insert(time_index,'removed')
            del time_list[time_index+1]
    else:
        continue

time_list_updated = [value for value in time_list if value != "removed"]

for time_val in time_list_updated:
    print(time_val)

위의 파이썬 코드를 실행시키면 다음과 같이 나타난다.

이 코드를 사용해 다시 엑셀파일로 만들어 비교할 수 있으나 텍스트 파일을 보고 검증했다. 검증결과 문제는 없었다.

 

결론

control block을 만들었다. 다음은 ROM을 만들어야한다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함