티스토리 뷰
IDEC 강의 영상을 보고 정리한 내용입니다.
https://www.idec.or.kr/vod/apply/view/?pay=&search_val=CPU&no=273
저번까지 설계한 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을 만들어야한다.
'프로젝트 > 4bit CPU' 카테고리의 다른 글
[4bit CPU #5] Control unit(1) (Decoder / Ring counter) - 18EE (0) | 2023.07.17 |
---|---|
[4bit CPU #4] ALU+ACC (feat.MUL/DIV) - 18EE (0) | 2023.07.16 |
[4bit CPU #3] ALU - 18EE (0) | 2023.07.15 |
[4bit CPU #2] ACC(Universal shift register) - 18EE (0) | 2023.07.12 |
[4bit CPU #1] Register, Program Counter(PC) - 18EE (0) | 2023.07.12 |
- Total
- Today
- Yesterday
- vlsi
- VTCMOS
- 굿노트 mp3파일 추출
- mp3파일 추출
- CMOS power
- VLSI dynamic power consumption
- clock gating
- Stack effect
- 굿노트 녹음파일
- 4bit
- MTCMOS
- Control Unit
- power gating
- switching power
- 굿노트 내보내기
- 4bit CPU
- VLSI 전력소모
- level shifter
- dynamic power
- Verilog
- CPU
- DVFS
- 굿노트 mp3 내보내기
- data gating
- leakage
- ALU
- acc
- delay
- VLSI power
- static power
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |