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




1.

. 기존에 구현한 Single Cycle CPU branch jump를 할 수 있는 BEQ J instruction 명령을 추가하고 데이터패스를 구현한다.

. Branch Jump 다음 클럭에 들어오는 PC값에 영향을 주므로 PC 값으로 기존의 PC 더불러 Branch Jump 받아들일 PC 선택할 있는 MUX 구현한다.


2.
알고리즘

. BEQ(Branch) / J(Jump) Instructions

                   BEQ(Branch) Instruction

                      J(Jump) Instruction

1) Branch 명령의 경우 OP코드 값은 1이고, rs rt 입력된 데이터의 address 표현하며, Imm 입력된 데이터가 같을 경우 PC값에 더하는 값이다.

2) Jump 명령의 경우 OP코드 값은 01이며, 중간의 9bits 사용하지 않는다. 마지막 addr 다음에 저장될 PC값이 된다.

. Datapath

1) 위 그림에서 Branch 명령이 들어오면 rs rt ALU 연산(subtract)을 통하여 값이 같은지 비교하고 만약 같다면, 기존의 PC 값과 Imm의 값을 더한 값이 다음 클럭에 새로운 PC 값이 된다.

2) Jump 명령이 들어오면 바로 addr값이 다음 클럭에 새로운 PC 값으로 된다.

3) PC 3가지의 경우로 인하여 3×1 MUX 사용하며 클럭마다 명령어에 따른 PC값이 저장되어 해당 PC address 저장되어 있는 instruction decode된다.


3.

module cpu4(clk, pc, rst, write_data, read_address1, read_address2, read_enable1,

read_enable2,mem_write_address, mem_read_address, mux_sel, mem_write_enable, mux_data,

mem_data, pc_sel, jump_address, branch_address);

 

input clk, rst;

 

output [7:0] write_data;

output [5:0] pc;

output [4:0] read_address1, read_address2;

output read_enable1, read_enable2;

output [5:0] mem_write_address, mem_read_address;

output mux_sel, mem_write_enable;

output [7:0] mux_data;

output [7:0] mem_data;

output [1:0] pc_sel;

output [5:0] jump_address;

output [4:0] branch_address;

 

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

reg [5:0] pc;

reg [7:0] read_data1, read_data2, imm_data;

reg [15:0] inst_out;

reg read_enable1, read_enable2, write_enable, mux_sel;

reg [5:0] mem_write_address, mem_read_address;

reg mux_sel, mem_write_enable;

reg [7:0] mux_data;

reg [7:0] mem_data;

reg [1:0] pc_sel;

reg alu_sel;

reg func_sel;

reg [1:0] result_sel;

reg [5:0] jump_address;

reg [4:0] branch_address;

 

// 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, imm_data, mem_write_address,

mem_read_address, mux_sel, mem_write_enable, pc_sel, alu_sel, jump_address,

branch_address);

 

// register 모듈 시행

m_register register(clk, rst, read_enable1, read_enable2, write_enable, read_address1,

read_address2, write_address, read_data1, read_data2, mux_data, imm_data);

 

// alu 모듈 시행

m_alu alu(read_data1, read_data2, func_sel, result_sel, write_data, alu_sel);

 

// memory 모듈 시행

mem memory(read_data1, mem_write_address, mem_read_address, mem_write_enable, clk, mem_data);

 

// mux 모듈 시행

m_mux mux(write_data, mem_data, mux_data, mux_sel);

 

always@(posedge clk)

begin

case(pc_sel)

2'b00 : pc = pc + 1'b1; // 기본적인 pc값 증가

2'b01 : pc = jump_address; // jump일 때

2'b10 : pc = pc + branch_address; // branch일 때

endcase

end

 

endmodule

 

module m_mux(write_data, mem_data, mux_data, mux_sel);

 

input [7:0] write_data, mem_data;

input mux_sel;

 

output [7:0] mux_data;

reg [7:0] mux_data;

 

always@(mux_sel)

begin

case(mux_sel)

1'b 0 : mux_data=write_data;

1'b 1 : mux_data=mem_data;

endcase

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)

begin

rom_data[0] = 16'b0000010000000001; // R-Type(1번 주소 위치에 1 저장)

rom_data[1] = 16'b0000100000000001; // R-Type(2번 주소 위치에 1 저장)

rom_data[2] = 16'b0100000000000101; // jump(5)

rom_data[3] = 16'b0000010000000001;

rom_data[4] = 16'b0000010000000001;

// branch(1번 주소와 2번 주소값 비교하여 같으면 1번 주소 위치 이동)

rom_data[5] = 16'b1000010000100010;

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)

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, imm_data, mem_write_address, mem_read_address,

mux_sel, mem_write_enable, pc_sel, alu_sel, jump_address, branch_address);

 

input clk;

input [15:0] inst_in;

 

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

output [7:0] imm_data;

output read_enable1, read_enable2, write_enable;

output [4:0] mem_write_address, mem_read_address;

output mux_sel;

output mem_write_enable;

output [1:0] pc_sel;

output alu_sel;

output [5:0] jump_address;

output [4:0] branch_address;

 

reg [7:0] imm_data;

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

reg read_enable1, read_enable2, write_enable;

reg [4:0] mem_write_address, mem_read_address;

reg mux_sel;

reg mem_write_enable;

reg [1:0] pc_sel;

reg alu_sel;

reg [5:0] jump_address;

reg [4:0] branch_address;

 

always@(inst_in)

begin

if(inst_in[15:10] == 6'b000001) // R-Type

begin

read_address1 = inst_in[9:5];

read_address2 = inst_in[4:0];

read_enable1 = 1;

read_enable2 = 1;

mux_sel = 0;

write_address = inst_in[9:5];

write_enable = 1;

mem_write_enable = 0;

pc_sel = 2'b00;

alu_sel = 1'b0;

end

else if(inst_in[15:13] == 3'b001) // I-Type

begin

read_address1 = inst_in[12:8];

imm_data = inst_in[7:0];

read_enable1 = 1;

read_enable2 = 0;

mux_sel = 0;

write_address = inst_in[12:8];

write_enable = 1;

mem_write_enable = 0;

pc_sel = 2'b00;

alu_sel = 1'b0;

end

 

else if(inst_in[15:10] == 6'b 000010) // LD

begin

mem_read_address = inst_in[4:0];

mem_write_enable = 0;

mux_sel = 1;

read_enable1 = 0;

read_enable2 = 0;

write_address = inst_in[9:5];

write_enable = 1;

pc_sel = 2'b00;

alu_sel = 1'b0;

end

else if(inst_in[15:10] == 6'b 000011) // ST

begin

mem_write_address = inst_in[4:0];

read_enable1 = 1;

mem_write_enable = 1;

write_enable = 0;

pc_sel = 2'b00;

alu_sel = 1'b0;

end

else if(inst_in[15] == 1'b1) // branch

begin

branch_address = inst_in[14:10]; // 점프할 주소 저장

read_address1 = inst_in[9:5]; // 비교할 첫번째 주소값

read_address2 = inst_in[4:0]; // 비교할 두번째 주소값

read_enable1 = 1;

read_enable2 = 1;

write_enable = 0; // 연산 결과를 레지스터에 저장 안함

pc_sel = 2'b10;

alu_sel = 1'b1; // alu subtract 연산 수행하도록 함

end

else if(inst_in[15:14] == 2'b01) // Jump

begin

jump_address = inst_in[5:0]; // 점프할 주소 저장

read_enable1 = 0;

read_enable2 = 0;

write_enable = 0;

pc_sel = 2'b01;

alu_sel = 1'b0;

end

 

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, imm_data);

 

input clk, rst, read_enable1, read_enable2, write_enable;

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

input [7:0] write_data, imm_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)

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)

rom_table[write_address] = write_data;

end

 

always@(read_address1)

begin

if(read_enable1 == 1'b1)

read_data1 = rom_table[read_address1];

end

 

always@(read_address2)

begin

if(read_enable2 == 1'b1)

read_data2 = rom_table[read_address2];

else

read_data2 = imm_data;

end

endmodule

 

module m_alu(a, b, func_sel, result_sel, result, alu_sel); // 이후 부터는 alu 연산 모듈

 

input [7:0] a, b;

input alu_sel;

 

output [7:0] result;

output func_sel;

output [1:0] result_sel;

 

reg [7:0] result;

reg [7:0] adder_result;

reg [7:0] and_result;

reg [7:0] or_result;

reg func_sel;

reg [1:0] result_sel;

 

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

m_and and1(a, b, and_result);

m_or or1(a, b, or_result);

 

always@(alu_sel) // alu_sel에 따라서 alu 연산 결정

case(alu_sel)

 

1'b0 : begin func_sel = 1'b0; result_sel = 2'b00; end

1'b1 : begin func_sel = 1'b1; result_sel = 2'b01; end

endcase

 

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.
파형 분석

. (1)에서는 기본적인 R-Type 명령어를 수행하게 되는데 , pc_sel 0 되고, 다음 pc값은 기존의 pc 1 증가된 값이 들어가게 된다.

. (2)에서는 read_enable1 read_enable2 떨어진 상태이면서 pc_sel 1 jump 명령어가 되는데, 이 때 jump_address의 값은 5이고 다음 pc는 해당 jump_address의 값이 들어가게 된다.

. (3)에서 pc_sel 2 상태 , branch 명령어가 수행되므로 read_address1 read_address2 비교하게 되는데 둘의 값이 같으므로 branch_address의 값인 3을 현재 pc 값과 더하여 다음 pc 저장하게 되고, 결국 다음 pc 9 변경된다.

 

참고 문헌

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

저작자 표시 비영리 동일 조건 변경 허락
크리에이티브 커먼즈 라이선스
Creative Commons License



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




1.

. 기존에 구현한 Single Cycle CPU Memory에서 데이터를 Load(LD)하고, Store(ST)하는 기능을 추가한다.

. 기본적으로 알고 있는 연산 결과를 메모리에 저장하고(LD), 저장된 결과를 꺼내와서(ST) 다른 연산을 하는 기능이 아닌, 단순히 하나의 레지스터 값을 메모리에 넣고 빼는 단순한 기능을 구현한다.


2.
알고리즘

. LD / ST Instructions

1) LD ST 명령어는 모두 6bits op-code 5bits 레지스터 주소, 그리고 5bits 메모리 주소값을 가지고 있다.

2) LD 경우 op-code 000010값을 가지고 있으며 메모리 주소(00001)로부터 얻어온 데이터를 레지스터 주소(00000) 가리키는 곳에 쓴다.

3) ST 경우 op-code 000011값을 가지고 있으며 레지스터 주소(00000)로부터 얻어온 데이터를 메모리 주소(00001) 가리키는 곳에 쓴다.

. Datapath

1) 위의 데이터패스는 PC로부터 Rom Table에서 instruction을 꺼내와서 Decoder를 거쳐 앞의 op-code 해당 명령어를 파악한 mux enable신호를 통해서 R-Type, I-Type, LD, ST 명령을 수행할 있는 구조를 보여준다.

2) LD ST 구조를 만들기 위하여 2x1 MUX Data Memory 유닛을 추가하였는데, R-Type에서 사용될 RS 해당하는 부분이 ALU 연산 결과나 메모리에서 꺼낸 데이터 하나를 받도록 MUX 두었고, RS 데이터 (read_data1) 메모리로 저장될 있는 데이터패스도 추가되었다.

3) LD 경우 메모리 쓰기 신호는 disable 되며, 메모리에서 읽은 데이터를 RS 가리키는 레지스터에 저장한다.

4) ST 경우 메모리 쓰기 신호는 enable 되며, RS에서 나온 데이터값이 메모리에 저장된다.


3.

module cpu3(clk, pc, rst, write_data, read_address1, read_address2, read_enable1,

read_enable2, mem_write_address, mem_read_address, mux_sel, mem_write_enable,

mux_data, mem_data);

 

input clk, rst;

output [7:0] write_data;

output [5:0] pc;

output [4:0] read_address1, read_address2;

output read_enable1, read_enable2;

output [5:0] mem_write_address, mem_read_address;

output mux_sel, mem_write_enable;

output [7:0] mux_data;

output [7:0] mem_data;

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

reg [5:0] pc;

reg [7:0] read_data1, read_data2, imm_data;

reg [15:0] inst_out;

reg read_enable1, read_enable2, write_enable, mux_sel;

reg [5:0] mem_write_address, mem_read_address;

reg mux_sel, mem_write_enable;

reg [7:0] mux_data;

reg [7:0] mem_data;

// 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, imm_data,

mem_write_address, mem_read_address, mux_sel,

mem_write_enable);

// register 모듈 시행

m_register register(clk, rst, read_enable1, read_enable2, write_enable,

read_address1, read_address2, write_address, read_data1, read_data2, mux_data, imm_data);

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

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

// memory 모듈 시행

mem memory(read_data1, mem_write_address, mem_read_address, mem_write_enable,

clk, mem_data);

// mux 모듈 시행

m_mux mux(write_data, mem_data, mux_data, mux_sel);

 

always@(posedge clk)

begin

pc = pc + 1'b1; // 클럭마다 pc 1 증가

end

 

endmodule

 

module m_mux(write_data, mem_data, mux_data, mux_sel);

 

input [7:0] write_data, mem_data;

input mux_sel;

 

output [7:0] mux_data;

reg [7:0] mux_data;

 

always@(mux_sel)

begin

case(mux_sel)

1'b 0 : mux_data=write_data;

1'b 1 : mux_data=mem_data;

endcase

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)

begin

rom_data[0] = 16'b0000010000000001; // R-Type(1씩 증가)

rom_data[1] = 16'b0000010000000001;

rom_data[2] = 16'b0000010000000001;

rom_data[3] = 16'b0010000000000010; // I-Type(2씩 증가)

rom_data[4] = 16'b0010000000000010;

rom_data[5] = 16'b0010000000000010;

rom_data[6] = 16'b0000110000000011; // ST 3번 메모리에 0번 레지스터값 저장

rom_data[7] = 16'b0000010000000001; // R-Type(1씩 증가)

rom_data[8] = 16'b0000010000000001;

rom_data[9] = 16'b0010000000000010; // I-Type(2씩 증가)

rom_data[10] = 16'b0010000000000010;

rom_data[11] = 16'b0000100000000011; // LD 3번 메모리 값을 0번 레지스터에 저장

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)

begin

inst_out = rom_data[pc]; // 클럭마다 instruction 받아옴

end

 

endmodule

 

module m_inst_decoder(clk, inst_in, read_address1, read_address2, write_address,

read_enable1, read_enable2, write_enable, imm_data, mem_write_address, mem_read_address, mux_sel, mem_write_enable);

 

input clk;

input [15:0] inst_in;

 

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

output [7:0] imm_data;

output read_enable1, read_enable2, write_enable;

output [4:0] mem_write_address, mem_read_address;

output mux_sel;

output mem_write_enable;

reg [7:0] imm_data;

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

reg read_enable1, read_enable2, write_enable;

reg [4:0] mem_write_address, mem_read_address;

reg mux_sel;

reg mem_write_enable;

 

always@(inst_in)

begin

if(inst_in[15:10] == 6'b000001) // R-Type

begin

read_address1 = inst_in[9:5];

read_address2 = inst_in[4:0];

read_enable1 = 1;

read_enable2 = 1;

mux_sel = 0;

write_address = inst_in[9:5];

write_enable = 1;

mem_write_enable = 0;

end

else if(inst_in[15:13] == 3'b001) // I-Type

begin

read_address1 = inst_in[12:8];

imm_data = inst_in[7:0];

read_enable1 = 1;

read_enable2 = 0;

mux_sel = 0;

write_address = inst_in[12:8];

write_enable = 1;

mem_write_enable = 0;

end

else if(inst_in[15:10] == 6'b 000010) // LD

begin

mem_read_address = inst_in[4:0];

mem_write_enable = 0;

mux_sel = 1;

read_enable1 = 0;

read_enable2 = 0;

write_address = inst_in[9:5];

write_enable = 1;

end

 

else if(inst_in[15:10] == 6'b 000011) // ST

begin

mem_write_address = inst_in[4:0];

read_enable1 = 1;

mem_write_enable = 1;

write_enable = 0;

end

end

/* // 클럭에 동기화된 write 신호를 instruction에 동기화 시켜줌(위로 올림)

always@(posedge clk)

begin

if(inst_in[15:10] == 6'b000001)

write_address = inst_in[9:5];

else if(inst_in[15:13] == 3'b001)

write_address = inst_in[12:8];

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, imm_data);

 

input clk, rst, read_enable1, read_enable2, write_enable;

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

input [7:0] write_data, imm_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)

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)

rom_table[write_address] = write_data;

end

 

always@(read_address1)

begin

if(read_enable1 == 1'b1) // R-Type의 경우 read_address1의 데이터값 read_data1에 저장

read_data1 = rom_table[read_address1];

end

 

always@(read_address2)

begin

if(read_enable2 == 1'b1) // R-Type의 경우 read_address2의 데이터값 read_data2에 저장

read_data2 = rom_table[read_address2];

else // I-Type의 경우 imm_data의 값을 read_data2에 저장

read_data2 = imm_data;

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.
파형 분석

. (1)에서 보면 rst 0 , instruction 들어있는 rom_data 배열과 레지스터가 저장될 rom_table 초기화 시킨다.

. (2)에서 pc1에서 3까지는 R-Type instruction 받아서 수행하므로 write_data(ALU 연산 결과) mux_data(write_data또는 memory에서 읽은 데이터 하나) 값이 1 증가함을 있다.

. (3)에서 pc4에서 6까지는 I-Type instruction 받아서 수행하므로 write_data mux_data 값이 2 증가함을 있다. (I-Type 경우 imm_data 값을 2 줘서 클럭마다 read_address1 가리키는 곳에 imm_data 더하는 방식을 취했다)

. (4)에서 mem_write_enable 1, ST 명령이 수행되는데 mem_write_address 3번의 위치에 그 전에 수행했던 read_data1의 값(이 때의 read_data1 write_data read_address 1번지의 위치에 쓰여지므로, 바로 사이클의 결과값인 9 저장) 저장된다.

. (5)에서 read_enable1 read_enable2 0이고 mem_write_enable 값도 0이므로 LD 명령을 수행한다. 때의 mem_read_address 3이므로 3번지에 메모리에 저장되어 있던 값이 mux_data로 나오게 되는데, (4)에서 메모리 3번 위치에 9를 저장했으므로 9가 출력되어 나옴을 있다.

 

참고 문헌

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

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



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




1.

. 기존에 구현한 Single Cycle CPU I-type 형식의 instruction 처리하는 기능을 추가한다.

. Instruction Decoder에서 R-type I-type instruction 해석하여 상황에 맞는 controller signal 설정하고 정상적인 동작상태를 보인다.


2.
알고리즘

. Instruction Fetch

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

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

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

. Decoder

R-type

I-type

1) 받아온 instruction 중에서 R-type 6비트를 I-type 3비트를 명령어로 사용한다.

2) R-type 하위 10비트 각각 5비트씩은 read_address1, read_address2 사용하고, I-type 하위13비트 5비트는 read_address1, 8비트는 immediate 값으로 사용한다.

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

. Register & ALU

1) Decoder에서 해석된 operand(명령어) R-type(6비트), I-type(3비트) 모두 adder기능을 수행한다.

2) R-type 경우 read_address1 read_address2주소에 해당하는 read_data1 read_data2 rom_table에서 꺼내서 ALU 연산(adder) 통해서 결과값을 다시 클럭이 posedge 때마다 read_address1(write_address) 위치에 삽입한다. (ex. a = a + b)

3) I-type 경우 read_address1 주소에 해당하는 read_data1 rom_table에서 꺼내고 immediate값을 바로 ALU 연산(adder)하여 결과값을 다시 매 클럭이 posedge일 때마다 read_address1(write_address) 삽입한다. (ex. a = a + constant(10))

3) R-type에서 read_enable1, read_enable2 instruction write_enable값은 클럭에 동기화되어 1 할당되고 이는 클럭마다 2개의 data add 연산하여 레지스터에 쓰는 구조를 갖게됨을 의미한다. I-type의 경우 read_enable2 0으로 되고 이는 read_address2 대신에 immediate 사용함을 의미한다.


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

if(inst_in[15:10] == 6'b000001) // R-type 명령어일 때

begin

read_address1 = inst_in[9:5];

read_address2 = inst_in[4:0];

read_enable1 = 1;

read_enable2 = 1;

end

else if(inst_in[15:13] == 3'b001) // I-type 명령어 일 때

begin

read_address1 = inst_in[12:8];

imm_data = inst_in[7:0]; // read_address2 대신 imm_data값 저장

read_enable1 = 1;

read_enable2 = 0;

end

end

 

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

begin

if(inst_in[15:10] == 6'b000001) // R-type 명령어일 때

write_address = inst_in[9:5];

else if(inst_in[15:13] == 3'b001) // I-type 명령어일 때

write_address = inst_in[12:8];

 

write_enable = 1; // 어느 타입이건 매 클럭마다 write

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];

else // 아니면 imm_data를 바로 read_data2에 저장

read_data2 = imm_data;

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.
파형 분석

. 그림 (1)에서 보면 rst 0으로 초기화 시켜서 rom_data rom_data[0]부터 rom_data[4]까지는 R-type 형식의 instruction rom_data[5]부터 rom_data[10]까지는 I-type 형식의 instruction, 그리고 rom_data[11]부터 rom_data[63]까지는 다시 R-type instruction으로 만든다. R-type 6비트의 명령어(adder만 사용) 5비트의 rs(source), 5비트의 rt(target) 사용하고, I-type 3비트의 명령어(adder 사용) 5비트의 rs(source), 8비트의 immediate value 사용한다.

또한, rom_table rom_table[0] 0(8‘b00000000)으로 저장하고 차례대로 1‘b1 증가하여 마지막 rom_table[31]에는 8'b00011111 초기화시킨다.

I-type rom_data[5]에는 immediate value 3으로, 이후엔 2 초기화되었다.

. R-type rom_table[0] rom_table[1] 더해서 다시 rom_table[0] 저장하는 형태이므로 그림 (2) 같이 클럭마다 1 증가함을 있다.

. I-type rom_table[0] immediate value 더하므로, I-type 시작하는(, read_enable2 0 되는 부분인) rom_table[5] 경우에 3의 값으로 초기화 되어있었으므로 그림 (3)과 같이 write_data(rom_table[0]) 값이 3 증가하며, 후에는 그림 (4) 같이 2 증가됨을 있다.

. 그리고 다시 R-type 시작되는 그림 (5) 보면 이후부터 다시 wirte_data 1 증가됨을 확인할 있다.

 

참고 문헌

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


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



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




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