`include "defines.vh"
module decode_unit #(
parameter INSTR_WIDTH = 16, // instructions are 16 bits in width
parameter R_ADDR_WIDTH = 5
)(
input wire [INSTR_WIDTH-1:0] instruction,
output reg [`OPCODE_COUNT-1:0] opcode_type,
output wire [`GROUP_COUNT-1:0] opcode_group,
output reg [R_ADDR_WIDTH-1:0] opcode_rd,
output reg [R_ADDR_WIDTH-1:0] opcode_rr,
output reg [11:0] opcode_imd,
output reg [2:0] opcode_bit
);
/*Fiindca register file-ul procesorului nostru (ATtiny20)
are doar 16 registre, putem ignora bitii Rr si Rd de pe pozitiile 9 si 8
(Atmel garanteaza ca, din motive de compatibilitate, vor fi mereu setati
pe 1, sau, echivalent, vor fi folosite numai registrele R16 ? R31).
Deci opcode = 000111rdxxxxxxxx devifne 00011111xxxxxxxx. (Btw, that's ADD)
*/
always @* begin
casez (instruction)
16'b0000_11??_????_????: begin
opcode_type = `TYPE_ADD;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
16'b0001_11??_????_????: begin
opcode_type = `TYPE_ADC;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
16'b0010_00??_????_????: begin
opcode_type = `TYPE_AND;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
16'b0010_01??_????_????: begin
opcode_type = `TYPE_EOR;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
/* TODO 5: LD_Y */
16'b1000_000?_????_1000: begin
opcode_type = `TYPE_LD_Y;
opcode_rd = instruction[8:4];
opcode_rr = {R_ADDR_WIDTH{1'bx}};
opcode_imd = 12'bx;
end
/* TODO 3: LDI */
16'b1110_????_????_????: begin
opcode_type = `TYPE_LDI;
opcode_rd = {1'b1, instruction[7:4]};
opcode_rr = {R_ADDR_WIDTH{1'bx}};
opcode_imd = {4'b0, instruction[11:8], instruction[3:0]};
end
/* TODO 6,7: instructions */
16'b1010_0???_????_????: begin
opcode_type = `TYPE_LDS;
opcode_rd = {1'b1, instruction[7:4]};
opcode_rr = {R_ADDR_WIDTH{1'bx}};
opcode_imd = {~instruction[8], instruction[8], instruction[10:9], instruction[3:0]};
end
16'b0010_11??_????_????: begin
opcode_type = `TYPE_MOV;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
opcode_imd = 12'bx;
end
16'b1001_010?_????_0001: begin
opcode_type = `TYPE_NEG;
opcode_rd = instruction[8:4];
opcode_rr = {R_ADDR_WIDTH{1'bx}};
end
16'b0000_0000_0000_0000: begin
opcode_type = `TYPE_NOP;
opcode_rd = {R_ADDR_WIDTH{1'bx}};
opcode_rr = {R_ADDR_WIDTH{1'bx}};
end
16'b0010_10??_????_????: begin
opcode_type = `TYPE_OR;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
16'b0001_10??_????_????: begin
opcode_type = `TYPE_SUB;
opcode_rd = instruction[8:4];
opcode_rr = {instruction[9], instruction[3:0]};
end
/*TODO 4: STS */
16'b1010_1???_????_????: begin
opcode_type = `TYPE_STS;
opcode_rd = {R_ADDR_WIDTH{1'bx}};
opcode_rr = {1'b1, instruction[7:4]};
opcode_imd = {~instruction[8], instruction[8], instruction[10:9], instruction[3:0]};
end
/* TODO : De codificat instructiunile din laborator. */
default: begin
opcode_type = `TYPE_UNKNOWN;
opcode_rd = {R_ADDR_WIDTH{1'bx}};
opcode_rr = {R_ADDR_WIDTH{1'bx}};
end
/*TODO : completati cu opcodes ale voastre.
Where can I find such opcodes? Make them up or read the lab and see
they're at http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf */
/* Cand gasiti o instructiune de UAL, setati opcode_type la valoarea corecta */
/* instruction seamana cu un ADD? -> opcode_type = `TYPE_ADD; */
endcase
end
assign opcode_group[`GROUP_ALU_ONE_OP] =
(opcode_type == `TYPE_NEG);
assign opcode_group[`GROUP_ALU_TWO_OP] =
(opcode_type == `TYPE_ADD) ||
(opcode_type == `TYPE_ADC) ||
(opcode_type == `TYPE_SUB) ||
(opcode_type == `TYPE_AND) ||
(opcode_type == `TYPE_EOR) ||
(opcode_type == `TYPE_OR);
assign opcode_group[`GROUP_ALU] =
opcode_group[`GROUP_ALU_ONE_OP] ||
opcode_group[`GROUP_ALU_TWO_OP];
assign opcode_group[`GROUP_LOAD_DIRECT] =
(opcode_type == `TYPE_LDS);
assign opcode_group[`GROUP_LOAD_INDIRECT] =
(opcode_type == `TYPE_LD_Y);
assign opcode_group[`GROUP_STORE_DIRECT] =
(opcode_type == `TYPE_STS);
assign opcode_group[`GROUP_STORE_INDIRECT] =
0;
assign opcode_group[`GROUP_REGISTER] =
/* TODO 3: LDI */
(opcode_type == `TYPE_LDI) ||
(opcode_type == `TYPE_MOV);
assign opcode_group[`GROUP_LOAD] =
opcode_group[`GROUP_LOAD_DIRECT] ||
opcode_group[`GROUP_LOAD_INDIRECT];
assign opcode_group[`GROUP_STORE] =
opcode_group[`GROUP_STORE_DIRECT] ||
opcode_group[`GROUP_STORE_INDIRECT];
assign opcode_group[`GROUP_MEMORY] =
(opcode_group[`GROUP_LOAD] ||
opcode_group[`GROUP_STORE]);
endmodule