mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
344 lines
11 KiB
Verilog
344 lines
11 KiB
Verilog
/*
|
|
Copyright (C) 2004, 2006 Pablo Bleyer Kocik.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
|
|
3. The name of the author may not be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/** @file
|
|
PacoBlaze Instruction Decode Unit.
|
|
*/
|
|
|
|
`ifndef PACOBLAZE_IDU_V_
|
|
`define PACOBLAZE_IDU_V_
|
|
|
|
`include "pacoblaze_inc.v"
|
|
|
|
`ifdef USE_ONEHOT_ENCODING
|
|
`define operation_set(x) operation = (1<<x)
|
|
// `define operation_set(x) operation[x] = 1'b1
|
|
`define operation(x) operation[(x)]
|
|
`else
|
|
`define operation_set(x) operation = (x)
|
|
`define operation(x) (x)
|
|
`endif
|
|
|
|
module `PACOBLAZE_IDU(
|
|
instruction,
|
|
operation,
|
|
shift_operation, shift_direction, shift_constant,
|
|
operand_selection,
|
|
x_address, y_address,
|
|
implied_value, port_address,
|
|
`ifdef HAS_SCRATCH_MEMORY
|
|
scratch_address,
|
|
`endif
|
|
code_address,
|
|
conditional, condition_flags,
|
|
interrupt_enable
|
|
`ifdef HAS_DEBUG
|
|
, debug
|
|
`endif
|
|
);
|
|
input [`code_width-1:0] instruction; ///< Instruction
|
|
output reg [`operation_width-1:0] operation; ///< Main operation
|
|
output [2:0] shift_operation; ///< Rotate/shift operation
|
|
output shift_direction; ///< Rotate/shift left(0)/right(1)
|
|
output shift_constant; ///< Shift constant value
|
|
output operand_selection; ///< Operand selection (k/p/s:0, y:1)
|
|
output [`register_depth-1:0] x_address, y_address; ///< Operation x source/target, y source
|
|
output [`operand_width-1:0] implied_value; ///< Operand constant source
|
|
output [`port_depth-1:0] port_address; ///< Port address
|
|
`ifdef HAS_SCRATCH_MEMORY
|
|
output [`scratch_depth-1:0] scratch_address; ///< Scratchpad address
|
|
`endif
|
|
output [`code_depth-1:0] code_address; ///< Program address
|
|
output conditional; ///< Conditional operation (unconditional(0)/conditional(1))
|
|
output [1:0] condition_flags; ///< Condition flags on zero and carry
|
|
output interrupt_enable; ///< Interrupt disable(0)/enable(1)
|
|
|
|
`ifdef HAS_DEBUG
|
|
output reg [8*`idu_debug_width:1] debug; ///< Operation debug string
|
|
reg [2*8:1] debug_conditional; ///< Conditional debug string
|
|
reg [5*8:1] debug_operand; ///< Operand debug string
|
|
reg [7*8:1] debug_interrupt; ///< Interrupt debug string
|
|
`endif
|
|
|
|
`ifdef PACOBLAZE1
|
|
wire [3:0] instruction_0 =
|
|
(instruction[15:12] == `opcode_reg) ? instruction[3:0] : instruction[15:12];
|
|
wire [3:0] instruction_1 = instruction[9:6];
|
|
|
|
assign x_address = instruction[11:8];
|
|
assign y_address = instruction[7:4];
|
|
assign operand_selection =
|
|
(instruction[15] && instruction[13]) ? instruction[12] :
|
|
instruction[15];
|
|
assign code_address = instruction[7:0];
|
|
assign interrupt_enable = instruction[5];
|
|
`endif
|
|
|
|
`ifdef PACOBLAZE2
|
|
wire [3:0] instruction_0 = {instruction[17], instruction[15:13]};
|
|
wire instruction_1 = instruction[16];
|
|
|
|
assign x_address = instruction[12:8];
|
|
assign y_address = instruction[7:3];
|
|
assign operand_selection = instruction[16];
|
|
assign code_address = instruction[9:0];
|
|
assign interrupt_enable = instruction[0];
|
|
`endif
|
|
|
|
`ifdef PACOBLAZE3
|
|
wire [4:0] instruction_0 = instruction[17:13];
|
|
|
|
assign x_address = instruction[11:8];
|
|
assign y_address = instruction[7:4];
|
|
assign operand_selection = instruction[12];
|
|
assign code_address = instruction[9:0];
|
|
assign interrupt_enable = instruction[0];
|
|
assign scratch_address = instruction[5:0];
|
|
`endif
|
|
|
|
`ifdef PACOBLAZE3M
|
|
wire [4:0] instruction_0 = instruction[17:13];
|
|
|
|
assign x_address = instruction[11:8];
|
|
assign y_address = instruction[7:4];
|
|
assign operand_selection = instruction[12];
|
|
assign code_address = instruction[9:0];
|
|
assign interrupt_enable = instruction[0];
|
|
assign scratch_address = instruction[5:0];
|
|
`endif
|
|
|
|
assign shift_direction = instruction[3];
|
|
assign shift_operation = instruction[2:1];
|
|
assign shift_constant = instruction[0];
|
|
|
|
assign conditional = instruction[12];
|
|
assign condition_flags = instruction[11:10];
|
|
|
|
assign implied_value = instruction[7:0];
|
|
assign port_address = instruction[7:0];
|
|
|
|
|
|
`ifdef PACOBLAZE1
|
|
always @(instruction_0, instruction_1)
|
|
`endif
|
|
`ifdef PACOBLAZE2
|
|
always @(instruction_0, instruction_1)
|
|
`endif
|
|
`ifdef PACOBLAZE3
|
|
always @(instruction_0)
|
|
`endif
|
|
`ifdef PACOBLAZE3M
|
|
always @(instruction_0)
|
|
`endif
|
|
begin
|
|
`ifdef HAS_DEBUG
|
|
operation = 'hx; // default
|
|
`else
|
|
operation = 'h0; // default
|
|
`endif
|
|
|
|
// synthesis parallel_case full_case
|
|
`ifdef PACOBLAZE1
|
|
casex (instruction_0)
|
|
`else
|
|
case (instruction_0)
|
|
`endif
|
|
|
|
`opcode_load: `operation_set(`op_load);
|
|
`opcode_add: `operation_set(`op_add);
|
|
`opcode_addcy: `operation_set(`op_addcy);
|
|
`opcode_and: `operation_set(`op_and);
|
|
`opcode_or: `operation_set(`op_or);
|
|
`opcode_rs: `operation_set(`op_rs);
|
|
`opcode_sub: `operation_set(`op_sub);
|
|
`opcode_subcy: `operation_set(`op_subcy);
|
|
`opcode_xor: `operation_set(`op_xor);
|
|
|
|
`ifdef PACOBLAZE1
|
|
{`opcode_ctl, 1'b?}:
|
|
casex (instruction_1)
|
|
{`opcode_jump, 2'b??}: `operation_set(`op_jump);
|
|
{`opcode_call, 2'b??}: `operation_set(`op_call);
|
|
`opcode_return: `operation_set(`op_return);
|
|
`opcode_returni: `operation_set(`op_returni);
|
|
`opcode_interrupt: `operation_set(`op_interrupt);
|
|
endcase
|
|
{`opcode_input, 1'b?}: `operation_set(`op_input);
|
|
{`opcode_output, 1'b?}: `operation_set(`op_output);
|
|
`endif // PACOBLAZE1
|
|
|
|
`ifdef PACOBLAZE2
|
|
`opcode_jump: // == `opcode_return
|
|
if (instruction_1) `operation_set(`op_jump);
|
|
else `operation_set(`op_return);
|
|
`opcode_call: if (instruction_1) `operation_set(`op_call);
|
|
`opcode_interrupt: // == `opcode_returni
|
|
if (instruction_1) `operation_set(`op_interrupt);
|
|
else `operation_set(`op_returni);
|
|
`opcode_input: `operation_set(`op_input);
|
|
`opcode_output: `operation_set(`op_output);
|
|
`endif // PACOBLAZE2
|
|
|
|
`ifdef PACOBLAZE3
|
|
`opcode_jump: `operation_set(`op_jump);
|
|
`opcode_call: `operation_set(`op_call);
|
|
`opcode_return: `operation_set(`op_return);
|
|
`opcode_returni: `operation_set(`op_returni);
|
|
`opcode_interrupt: `operation_set(`op_interrupt);
|
|
`opcode_input: `operation_set(`op_input);
|
|
`opcode_output: `operation_set(`op_output);
|
|
`endif // PACOBLAZE3
|
|
|
|
`ifdef PACOBLAZE3M
|
|
`opcode_jump: `operation_set(`op_jump);
|
|
`opcode_call: `operation_set(`op_call);
|
|
`opcode_return: `operation_set(`op_return);
|
|
`opcode_returni: `operation_set(`op_returni);
|
|
`opcode_interrupt: `operation_set(`op_interrupt);
|
|
`opcode_input: `operation_set(`op_input);
|
|
`opcode_output: `operation_set(`op_output);
|
|
`endif // PACOBLAZE3M
|
|
|
|
// PB3
|
|
`ifdef HAS_COMPARE_OPERATION
|
|
`opcode_compare: `operation_set(`op_compare);
|
|
`endif
|
|
`ifdef HAS_TEST_OPERATION
|
|
`opcode_test: `operation_set(`op_test);
|
|
`endif
|
|
`ifdef HAS_SCRATCH_MEMORY
|
|
`opcode_fetch: `operation_set(`op_fetch);
|
|
`opcode_store: `operation_set(`op_store);
|
|
`endif
|
|
|
|
// PB3M
|
|
`ifdef HAS_MUL_OPERATION
|
|
`opcode_mul: `operation_set(`op_mul);
|
|
`endif
|
|
|
|
`ifdef HAS_WIDE_ALU
|
|
`opcode_addw: `operation_set(`op_addw);
|
|
`opcode_addwcy: `operation_set(`op_addwcy);
|
|
`opcode_subw: `operation_set(`op_subw);
|
|
`opcode_subwcy: `operation_set(`op_subwcy);
|
|
`endif
|
|
|
|
// default: `operation_set(0);
|
|
endcase
|
|
|
|
end
|
|
|
|
|
|
`ifdef HAS_DEBUG
|
|
|
|
`include "pacoblaze_util.v"
|
|
|
|
always @(operand_selection, x_address, y_address, implied_value)
|
|
if (operand_selection) debug_operand = {"s", numtohex(x_address), ",", "s", numtohex(y_address)};
|
|
else debug_operand = {"s", numtohex(x_address), ",", numtohex(implied_value[7:4]), numtohex(implied_value[3:0])};
|
|
|
|
always @(conditional, condition_flags) begin
|
|
case ({conditional, condition_flags})
|
|
// 3b'0??: debug_conditional = " ";
|
|
{1'b1, `flag_z}: debug_conditional = `os_z;
|
|
{1'b1, `flag_nz}: debug_conditional = `os_nz;
|
|
{1'b1, `flag_c}: debug_conditional = `os_c;
|
|
{1'b1, `flag_nc}: debug_conditional = `os_nc;
|
|
default: debug_conditional = " ";
|
|
endcase
|
|
end
|
|
|
|
always @(interrupt_enable)
|
|
if (interrupt_enable) debug_interrupt = `os_enable;
|
|
else debug_interrupt = `os_disable;
|
|
|
|
always @(operation, shift_direction, shift_operation, shift_constant,
|
|
debug_operand, debug_conditional, debug_interrupt,
|
|
code_address
|
|
)
|
|
`ifdef USE_ONEHOT_ENCODING
|
|
case (1'b1)
|
|
`else
|
|
case (operation)
|
|
`endif
|
|
`operation(`op_load): debug = {`os_load, " ", debug_operand};
|
|
`operation(`op_add): debug = {`os_add, " ", debug_operand};
|
|
`operation(`op_addcy): debug = {`os_addcy, " ", debug_operand};
|
|
`operation(`op_and): debug = {`os_and, " ", debug_operand};
|
|
`operation(`op_or): debug = {`os_or, " ", debug_operand};
|
|
`operation(`op_rs): // debug = `os_rs;
|
|
case ({shift_direction, shift_operation, shift_constant})
|
|
4'b1_11_0: debug = {`os_sr0, " s", numtohex(x_address)};
|
|
4'b1_11_1: debug = {`os_sr1, " s", numtohex(x_address)};
|
|
4'b1_01_0: debug = {`os_srx, " s", numtohex(x_address)};
|
|
4'b1_00_0: debug = {`os_sra, " s", numtohex(x_address)};
|
|
4'b1_10_0: debug = {`os_rr, " s", numtohex(x_address)};
|
|
4'b0_11_0: debug = {`os_sl0, " s", numtohex(x_address)};
|
|
4'b0_11_1: debug = {`os_sl1, " s", numtohex(x_address)};
|
|
4'b0_10_0: debug = {`os_slx, " s", numtohex(x_address)};
|
|
4'b0_00_0: debug = {`os_sla, " s", numtohex(x_address)};
|
|
4'b0_01_0: debug = {`os_rl, " s", numtohex(x_address)};
|
|
default: debug = `os_invalid;
|
|
endcase
|
|
`operation(`op_sub): debug = {`os_sub, " ", debug_operand};
|
|
`operation(`op_subcy): debug = {`os_subcy, " ", debug_operand};
|
|
`operation(`op_xor): debug = {`os_xor, " ", debug_operand};
|
|
|
|
`ifdef HAS_MUL_OPERATION
|
|
`operation(`op_mul): debug = {`os_mul, " ", debug_operand};
|
|
`endif
|
|
|
|
`operation(`op_jump): debug = {`os_jump, " ", debug_conditional, " ", adrtohex(code_address)};
|
|
`operation(`op_call): debug = {`os_call, " ", debug_conditional, " ", adrtohex(code_address)};
|
|
`operation(`op_return): debug = {`os_return, " ", debug_conditional};
|
|
`operation(`op_returni): debug = {`os_returni, " ", debug_interrupt};
|
|
`operation(`op_interrupt): debug = {`os_interrupt, " ", debug_interrupt};
|
|
|
|
`operation(`op_input): debug = {`os_input, " ", debug_operand};
|
|
`operation(`op_output): debug = {`os_output, " ", debug_operand};
|
|
`ifdef HAS_COMPARE_OPERATION
|
|
`operation(`op_compare): debug = {`os_compare, " ", debug_operand};
|
|
`endif
|
|
`ifdef HAS_TEST_OPERATION
|
|
`operation(`op_test): debug = {`os_test, " ", debug_operand};
|
|
`endif
|
|
`ifdef HAS_SCRATCH_MEMORY
|
|
`operation(`op_fetch): debug = {`os_fetch, " ", debug_operand};
|
|
`operation(`op_store): debug = {`os_store, " ", debug_operand};
|
|
`endif
|
|
|
|
default: debug = `os_invalid;
|
|
endcase
|
|
|
|
`endif // HAS_DEBUG
|
|
|
|
|
|
endmodule
|
|
|
|
`endif // PACOBLAZE_IDU_V_
|