BLOG ARTICLE decode | 1 ARTICLE FOUND

  1. 2009/02/02 컴퓨터구조 설계 및 실험 - 16bit CPU (Instruction Fetch & Decode) (1)



다운/퍼 가실 때 댓글 부탁드려요. 그리고 받으신 자료 유료 레포트 사이트에 올리지 말아주세요.




1.

. 클럭마다 PC(Program Counter)에서 가리키는 rom_table instruction을 받아와서 디코드하여 instruction 가리키는 레지스터의 주소내의 데이터를 연산하여 결과값을 다시 레지스터에 기록하는 싱글 사이클 CPU 구현한다.

. PC 다른 조건없이 클럭마다 1 증가되며, 연산 명령은 구조를 단순화하기 위하여 adder만을 사용하고, wirte_address read_address1 주소를 같게 하여, 예를 들어 a, b 대한 연산 결과가 a 저장되는 형태를 취한다. (a = a+b)


2.
알고리즘

. Instruction Fetch

1) 클럭에 동기화 되어 PC값이 증가되면서 해당 rom_table 있는 instruction 읽어온다

2) pc 클럭마다 1 증가되고 새로운 instruction 받아오게 된다.(single_cycle 특성)

3) rom_table 수는 개인 64개를 사용한다.

. Decoder

1) 받아온 instruction 상위 6비트는 실질적인 명령어로 사용되고

2) 하위 10비트 각각 5비트씩은 read_address1, read_address2 사용된다.

3) 또한 클록에 동기화되어 write_address [9:5]비트의 데이터를 주소로 사용한다.

. Register & ALU

1) 이번 과제에서의 operand adder기능만을 수행함으로 6‘b000001 사용한다.

2) read_address1 read_address2 해당하는 주소의 데이터를 register에서 읽어와서 ALU에서 adder 연산을 수행한 clk posedge 때마다 해당 write_address 해당하는 register 연산 결과인 write_data 쓴다.

3) read_enable1, read_enable2 instruction write_enable값은 클럭에 동기화되어 1 할당되고 이는 클럭마다 2개의 data add 연산하여 레지스터에 쓰는 구조를 갖게됨을 의미한다.


3.

module cpu(clk, pc, rst, write_data, read_address1, read_address2, read_enable1, read_enable2);

 

input clk, rst;

 

output [7:0] write_data;

output [5:0] pc;

output [4:0] read_address1, read_address2;

output read_enable1, read_enable2;

 

reg [4:0] read_address1, read_address2, write_address;

reg [5:0] pc;

reg [7:0] read_data1, read_data2;

reg [15:0] inst_out;

reg read_enable1, read_enable2, write_enable;

 

// rom_table 모듈 시행

m_rom_table rom_table(clk, pc, rst, inst_out);

 

// instruction decoder 모듈 시행

m_inst_decoder inst_decoder(clk, inst_out, read_address1, read_address2, write_address, read_enable1, read_enable2, write_enable);

 

// register 모듈 시행

m_register register(clk, rst, read_enable1, read_enable2, write_enable, read_address1, read_address2, write_address, read_data1, read_data2, write_data);

 

// alu 모듈 시행 func_sel result_sel 값은 adder기능을 수행하도록 0 2'b00을 대입

m_alu alu(read_data1, read_data2, 0, 2'b00, write_data);

 

always@(posedge clk) // 클럭마다 pc값을 1 증가

begin

pc = pc + 1'b1;

end

 

endmodule

 

 

 

module m_rom_table(clk, pc, rst, inst_out);

 

input [5:0] pc;

input clk, rst;

 

output [15:0] inst_out;

 

reg [15:0] inst_out;

reg [15:0] rom_data[0:63];

 

always@(posedge clk or negedge rst)

begin

if(rst == 1'b0) // rst 0이면 rom_data 테이블 초기화

begin

rom_data[0] = 16'b0000010000000001;

rom_data[1] = 16'b0000010000000001;

rom_data[2] = 16'b0000010000000001;

rom_data[3] = 16'b0000010000000001;

 

rom_data[4] = 16'b0000010000000001;

rom_data[5] = 16'b0000010000000001;

rom_data[6] = 16'b0000010000000001;

rom_data[7] = 16'b0000010000000001;

rom_data[8] = 16'b0000010000000001;

rom_data[9] = 16'b0000010000000001;

rom_data[10] = 16'b0000010000000001;

rom_data[11] = 16'b0000010000000001;

rom_data[12] = 16'b0000010000000001;

rom_data[13] = 16'b0000010000000001;

rom_data[14] = 16'b0000010000000001;

rom_data[15] = 16'b0000010000000001;

rom_data[16] = 16'b0000010000000001;

rom_data[17] = 16'b0000010000000001;

rom_data[18] = 16'b0000010000000001;

rom_data[19] = 16'b0000010000000001;

rom_data[20] = 16'b0000010000000001;

rom_data[21] = 16'b0000010000000001;

rom_data[22] = 16'b0000010000000001;

rom_data[23] = 16'b0000010000000001;

rom_data[24] = 16'b0000010000000001;

rom_data[25] = 16'b0000010000000001;

rom_data[26] = 16'b0000010000000001;

rom_data[27] = 16'b0000010000000001;

rom_data[28] = 16'b0000010000000001;

rom_data[29] = 16'b0000010000000001;

rom_data[30] = 16'b0000010000000001;

rom_data[31] = 16'b0000010000000001;

rom_data[32] = 16'b0000010000000001;

rom_data[33] = 16'b0000010000000001;

rom_data[34] = 16'b0000010000000001;

rom_data[35] = 16'b0000010000000001;

rom_data[36] = 16'b0000010000000001;

rom_data[37] = 16'b0000010000000001;

rom_data[38] = 16'b0000010000000001;

rom_data[39] = 16'b0000010000000001;

rom_data[40] = 16'b0000010000000001;

rom_data[41] = 16'b0000010000000001;

rom_data[42] = 16'b0000010000000001;

rom_data[43] = 16'b0000010000000001;

rom_data[44] = 16'b0000010000000001;

rom_data[45] = 16'b0000010000000001;

rom_data[46] = 16'b0000010000000001;

rom_data[47] = 16'b0000010000000001;

rom_data[48] = 16'b0000010000000001;

rom_data[49] = 16'b0000010000000001;

rom_data[50] = 16'b0000010000000001;

rom_data[51] = 16'b0000010000000001;

rom_data[52] = 16'b0000010000000001;

rom_data[53] = 16'b0000010000000001;

rom_data[54] = 16'b0000010000000001;

rom_data[55] = 16'b0000010000000001;

rom_data[56] = 16'b0000010000000001;

rom_data[57] = 16'b0000010000000001;

rom_data[58] = 16'b0000010000000001;

rom_data[59] = 16'b0000010000000001;

rom_data[60] = 16'b0000010000000001;

rom_data[61] = 16'b0000010000000001;

rom_data[62] = 16'b0000010000000001;

rom_data[63] = 16'b0000010000000001;

 

end

end

 

always@(posedge clk) // 클럭마다 pc에 해당하는 rom_data의 값 inst_out에 읽어옴

begin

inst_out = rom_data[pc];

end

 

endmodule

 

module m_inst_decoder(clk, inst_in, read_address1, read_address2, write_address, read_enable1, read_enable2, write_enable);

 

input clk;

input [15:0] inst_in;

 

output [4:0] read_address1, read_address2, write_address;

output read_enable1, read_enable2, write_enable;

 

reg [4:0] read_address1, read_address2, write_address;

reg read_enable1, read_enable2, write_enable;

 

always@(inst_in) // instruction을 받을 때마다 read_address1,2를 저장

begin

read_address1 = inst_in[9:5];

read_address2 = inst_in[4:0];

read_enable1 = 1;

read_enable2 = 1;

end

 

always@(posedge clk) // 매 클럭마다 5~9비트 데이터를 write_address로 사용

begin

write_address = inst_in[9:5];

write_enable = 1;

end

 

endmodule

 

 

 

module m_register(clk, rst, read_enable1, read_enable2, write_enable, read_address1, read_address2, write_address, read_data1, read_data2, write_data);

 

input clk, rst, read_enable1, read_enable2, write_enable;

input [4:0] read_address1, read_address2, write_address;

input [7:0] write_data;

 

output [7:0] read_data1, read_data2;

 

reg [7:0] read_data1, read_data2;

reg [7:0] rom_table[0:31];

 

always@(posedge clk or negedge rst)

begin

if(rst == 1'b0) // rst 0이면 rom_table 초기화

begin

rom_table[0] = 8'b00000000;

rom_table[1] = 8'b00000001;

rom_table[2] = 8'b00000010;

rom_table[3] = 8'b00000011;

rom_table[4] = 8'b00000100;

rom_table[5] = 8'b00000101;

rom_table[6] = 8'b00000110;

rom_table[7] = 8'b00000111;

rom_table[8] = 8'b00001000;

rom_table[9] = 8'b00001001;

rom_table[10] = 8'b00001010;

rom_table[11] = 8'b00001011;

rom_table[12] = 8'b00001100;

 

rom_table[13] = 8'b00001101;

rom_table[14] = 8'b00001110;

rom_table[15] = 8'b00001111;

rom_table[16] = 8'b00010000;

rom_table[17] = 8'b00010001;

rom_table[18] = 8'b00010010;

rom_table[19] = 8'b00010011;

rom_table[20] = 8'b00010100;

rom_table[21] = 8'b00010101;

rom_table[22] = 8'b00010110;

rom_table[23] = 8'b00010111;

rom_table[24] = 8'b00011000;

rom_table[25] = 8'b00011001;

rom_table[26] = 8'b00011010;

rom_table[27] = 8'b00011011;

rom_table[28] = 8'b00011100;

rom_table[29] = 8'b00011101;

rom_table[30] = 8'b00011110;

rom_table[31] = 8'b00011111;

end

else if(write_enable == 1'b1) // write_enable 1이면 레지스터에 데이터 쓰기

rom_table[write_address] = write_data;

end

 

always@(read_address1)

begin

if(read_enable1 == 1'b1) // read_enable1 1이면 레지스터에서 데이터 읽음

read_data1 = rom_table[read_address1];

end

 

always@(read_address2)

begin

if(read_enable2 == 1'b1) // read_enable2 1이면 레지스터에서 데이터 읽음

read_data2 = rom_table[read_address2];

end

 

endmodule

 

 

 

module m_alu(a, b, func_sel, result_sel, result); // 이 이하부터는 ALU 연산

 

input [7:0] a, b;

input func_sel;

input [1:0] result_sel;

 

output [7:0] result;

 

reg [7:0] result;

reg [7:0] adder_result;

reg [7:0] and_result;

reg [7:0] or_result;

 

m_adder adder1(a, b, adder_result, func_sel);

m_and and1(a, b, and_result);

m_or or1(a, b, or_result);

 

always@(result or adder_result or and_result or or_result or result_sel)

case(result_sel)

2'b00 : result = adder_result;

2'b01 :

begin

if(adder_result >= 0)

result = 8'b00000000;

else

result = 8'b00000001;

end

 

2'b10 : result = and_result;

2'b11 : result = or_result;

endcase

 

endmodule

 

 

 

module m_adder(a, b, adder_result, func_sel);

 

input [7:0] a, b;

input func_sel;

 

output [7:0] adder_result;

 

wire [7:0] c;

wire [7:0] b1;

 

m_complement com1(b, b1, func_sel);

 

m_half_adder ha(a[0], b1[0], c[0], adder_result[0]);

m_full_adder fa1(a[1], b1[1], c[0], c[1], adder_result[1]);

m_full_adder fa2(a[2], b1[2], c[1], c[2], adder_result[2]);

m_full_adder fa3(a[3], b1[3], c[2], c[3], adder_result[3]);

m_full_adder fa4(a[4], b1[4], c[3], c[4], adder_result[4]);

m_full_adder fa5(a[5], b1[5], c[4], c[5], adder_result[5]);

m_full_adder fa6(a[6], b1[6], c[5], c[6], adder_result[6]);

m_full_adder fa7(a[7], b1[7], c[6], c[7], adder_result[7]);

 

endmodule

 

 

 

module m_full_adder(a, b, cin, cout, adder_result);

 

input a, b, cin;

output cout, adder_result;

 

wire c1, c2, s1;

 

m_half_adder ha1(b, cin, c1, s1);

m_half_adder ha2(a, s1, c2, adder_result);

 

assign cout = c1 | c2;

 

endmodule

 

 

 

module m_half_adder(a, b, c, adder_result);

 

input a, b;

output c, adder_result;

 

assign adder_result = a ^ b;

assign c = a & b;

 

endmodule

 

module m_complement(b, b1, func_sel);

 

input [7:0] b;

input func_sel;

output [7:0] b1;

 

reg [7:0] tmp;

 

always@(b or tmp or func_sel)

case(func_sel)

1'b0 : tmp = b;

1'b1 : tmp = ~b + 1;

endcase

 

assign b1 = tmp;

 

endmodule

 

 

 

module m_and(a, b, and_result);

 

input [7:0] a, b;

output [7:0] and_result;

 

assign and_result = a & b;

 

endmodule

 

 

 

module m_or(a, b, or_result);

 

input [7:0] a, b;

output [7:0] or_result;

 

assign or_result = a | b;

 

endmodule


4.
파형 분석

. 파형에서 rst 0으로 시작하여 일단 rom_data rom_table 각각 초기화 시켰다.

. 위 연산은 read_address1의 데이터와 read_address2의 데이터를 더하여 다시 read_address1 저장하는 것이며, write_data read_address1 저장된 데이터 값을 출력한다.

. (1)에서 pc값이 1 증가되면서 해당 instruction rom_data에서 빼오는데 rom_data 64 모두 0000010000000001 값이 저장되어 있다. 00000번과 00001번지의 데이터를 000001(add) 연산하라는 뜻인데, 결과 rst 의해서 초기화되어 있었던 rom_table 00000번과 00001번의 데이터 0 1 더해져서 다시 00000번지 레지스터에 쓰여지고 연산결과인 1 wirte_data 출력됨을 있다.

. 그 후에는 매번 00001번의 데이터 값인 1이 추가해서 더해짐으로 (2)번과 같이 write_data pc마다 1 증가함을 있다.

. 파형은 00001번지 레지스터의 값을 단순히 2 바꾸어놓은 것이다. pc마다 00001번지의 2 값이 계속 더해짐으로 write_data 2만큼 계속 늘어나가는 것을 있다.


참고 문헌

. HDL Chip Design(Doone Publications / Douglas J Smith )


저작자 표시 비영리 변경 금지
크리에이티브 커먼즈 라이선스
Creative Commons License