- `include "defines.vh"
- module control_unit #(
- parameter INSTR_WIDTH = 16, // instructions are 16 bits in width
- parameter DATA_WIDTH = 8, // registers are 8 bits in width
- parameter I_ADDR_WIDTH = 10, // 2*1024 bytes of flash (or ROM in our case)
- parameter ADDR_WIDTH = 16, // 64KB address space
- parameter R_ADDR_WIDTH = 5 // 32 registers
- )(
- input wire clk,
- input wire reset,
- // To/from instruction memory
- output reg [I_ADDR_WIDTH-1:0] program_counter,
- input wire [INSTR_WIDTH-1:0] instruction,
- // From FSM
- // TODO move state and add debug state
- output wire [`STAGE_COUNT-1:0] pipeline_stage,
- // To/from register file
- output wire [R_ADDR_WIDTH-1:0] rr_addr,
- output wire [R_ADDR_WIDTH-1:0] rd_addr,
- inout wire [DATA_WIDTH-1:0] rr_data,
- inout wire [DATA_WIDTH-1:0] rd_data,
- output wire rr_cs,
- output wire rd_cs,
- output wire rr_we,
- output wire rd_we,
- output wire rr_oe,
- output wire rd_oe,
- // To/from ALU
- output wire alu_enable,
- output reg [`OPSEL_COUNT-1:0] alu_opsel,
- output wire [DATA_WIDTH-1:0] alu_flags_in,
- input wire [DATA_WIDTH-1:0] alu_flags_out,
- output reg [DATA_WIDTH-1:0] alu_rr,
- output reg [DATA_WIDTH-1:0] alu_rd,
- input wire [DATA_WIDTH-1:0] alu_out,
- // To/from bus interface unit
- output wire [ADDR_WIDTH-1:0] bus_addr,
- inout wire [DATA_WIDTH-1:0] bus_data,
- output wire mem_cs,
- output wire mem_we,
- output wire mem_oe
- `ifdef DEBUG
- ,
- output wire [`OPCODE_COUNT-1:0] debug_opcode_type,
- output wire [`GROUP_COUNT-1:0] debug_opcode_group,
- output wire [11:0] debug_opcode_imd,
- output wire [DATA_WIDTH-1:0] debug_writeback_value,
- output wire [`SIGNAL_COUNT-1:0] debug_signals
- `endif
- );
- // From decode unit
- wire [`SIGNAL_COUNT-1:0] signals;
- wire [`OPCODE_COUNT-1:0] opcode_type;
- wire [`GROUP_COUNT-1:0] opcode_group;
- wire [R_ADDR_WIDTH-1:0] opcode_rd;
- wire [R_ADDR_WIDTH-1:0] opcode_rr;
- wire [11:0] opcode_imd;
- wire [2:0] opcode_bit;
- // Buffers for various stuff
- reg [INSTR_WIDTH-1:0] instr_buffer;
- reg [DATA_WIDTH-1:0] alu_out_buffer;
- reg [DATA_WIDTH-1:0] writeback_value;
- wire [ADDR_WIDTH-1:0] indirect_addr;
- wire [DATA_WIDTH-1:0] data_to_store;
- reg [DATA_WIDTH-1:0] sreg;
- `ifdef DEBUG
- assign debug_opcode_type = opcode_type;
- assign debug_opcode_group = opcode_group;
- assign debug_opcode_imd = opcode_imd;
- assign debug_writeback_value = writeback_value;
- assign debug_signals = signals;
- `endif
- state_machine fsm (
- .pipeline_stage (pipeline_stage),
- .clk (clk),
- .reset (reset)
- );
- decode_unit #(
- .INSTR_WIDTH(INSTR_WIDTH)
- ) decode (
- .instruction (instr_buffer),
- .opcode_type (opcode_type),
- .opcode_group(opcode_group),
- .opcode_imd (opcode_imd),
- .opcode_rd(opcode_rd),
- .opcode_rr(opcode_rr),
- .opcode_bit(opcode_bit)
- );
- signal_generation_unit sig (
- .pipeline_stage (pipeline_stage),
- .signals (signals),
- .opcode_type (opcode_type),
- .opcode_group(opcode_group)
- );
- reg_file_interface_unit #(
- .DATA_WIDTH (DATA_WIDTH),
- .INSTR_WIDTH (INSTR_WIDTH),
- .R_ADDR_WIDTH(R_ADDR_WIDTH)
- ) rf_int (
- .opcode_type (opcode_type),
- .writeback_value(writeback_value),
- .signals (signals),
- .rr_addr (rr_addr),
- .rd_addr (rd_addr),
- .rr_data (rr_data),
- .rd_data (rd_data),
- .rr_cs (rr_cs),
- .rd_cs (rd_cs),
- .rr_we (rr_we),
- .rd_we (rd_we),
- .rr_oe (rr_oe),
- .rd_oe (rd_oe),
- .opcode_rd (opcode_rd),
- .opcode_rr (opcode_rr)
- );
- bus_interface_unit #(
- .MEM_START_ADDR(8'h40),
- .MEM_STOP_ADDR (8'hBF),
- .DATA_WIDTH (DATA_WIDTH),
- .ADDR_WIDTH (ADDR_WIDTH)
- ) bus_int (
- .opcode_group (opcode_group),
- .opcode_imd (opcode_imd),
- .signals (signals),
- .bus_addr (bus_addr),
- .bus_data (bus_data),
- .mem_cs (mem_cs),
- .mem_we (mem_we),
- .mem_oe (mem_oe),
- .indirect_addr(indirect_addr),
- .data_to_store(data_to_store)
- );
- assign indirect_addr =
- (opcode_group[`GROUP_LOAD_INDIRECT] ||
- opcode_group[`GROUP_STORE_INDIRECT]) ?
- // else, indirect to memory => X or Y or Z
- {alu_rr, alu_rd} :
- // else, not indirect
- {ADDR_WIDTH{1'bx}};
- assign data_to_store =
- signals[`CONTROL_MEM_WRITE] ?
- /* TODO 4: STS */
- alu_rr :
- {DATA_WIDTH{1'bx}};
- /* Bloc de atribuire al program counter-ului */
- always @(posedge clk, posedge reset) begin
- if (reset) begin
- program_counter <= 0;
- end else if (pipeline_stage == `STAGE_WB) begin
- program_counter <= program_counter + 1;
- end
- end
- assign alu_flags_in = sreg;
- /* Bloc de atribuire al sreg-ului */
- always @(posedge clk, posedge reset)
- if (reset)
- sreg <= 0;
- else sreg <= alu_flags_out;
- always @(posedge clk, posedge reset) begin
- /* TODO : Faceti legatura intre registre si RAM prin unitatea de control. */
- /* TODO 3: LDI */
- /* TODO 5,6,7: register writes */
- if (reset)
- writeback_value <= {DATA_WIDTH{1'b0}};
- else if (opcode_group[`GROUP_ALU])
- writeback_value <= alu_out_buffer;
- else if (opcode_type == `TYPE_LDI)
- writeback_value <= opcode_imd[DATA_WIDTH-1:0];
- else if (signals[`CONTROL_MEM_READ])
- writeback_value <= bus_data;
- else if (opcode_type == `TYPE_MOV)
- writeback_value <= alu_rr;
- end
- /* Buffer pentru instructiunea citita */
- always @(posedge clk, posedge reset)
- if (reset)
- instr_buffer <= 0;
- else if (pipeline_stage == `STAGE_IF)
- instr_buffer <= instruction;
- /* Buffer pentru output-ul UAL-ului */
- always @(posedge clk, posedge reset)
- if (reset)
- alu_out_buffer <= 0;
- else if (pipeline_stage == `STAGE_EX)
- alu_out_buffer <= alu_out;
- /* Buffer pentru rd_data si rr_data */
- always @(posedge clk, posedge reset)
- if (reset) begin
- alu_rd <= 0;
- alu_rr <= 0;
- end else if (pipeline_stage == `STAGE_ID) begin
- alu_rd <= rd_data;
- alu_rr <= rr_data;
- end
- assign alu_enable = (pipeline_stage == `STAGE_EX);
- /* Set alu_opsel to appropriate operation,
- * according to opcode_type and alu_enable */
- always @* begin
- if (alu_enable == 0)
- alu_opsel = `OPSEL_COUNT'bx;
- else begin
- case (opcode_type)
- `TYPE_ADD:
- alu_opsel = `OPSEL_ADD;
- `TYPE_ADC:
- alu_opsel = `OPSEL_ADC;
- `TYPE_SUB:
- alu_opsel = `OPSEL_SUB;
- `TYPE_AND:
- alu_opsel = `OPSEL_AND;
- `TYPE_EOR:
- alu_opsel = `OPSEL_EOR;
- `TYPE_OR:
- alu_opsel = `OPSEL_OR;
- `TYPE_NEG:
- alu_opsel = `OPSEL_NEG;
- default:
- alu_opsel = `OPSEL_NONE;
- endcase
- end
- end
- endmodule