HierarchyFilesModulesSignalsTasksFunctionsHelp
/*
  Copyright (c) 2004 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
  Behavioral KCPSMX implementation.
*/

`include "kcpsmx_inc.v"

/** Top kcpsmx module. */
[Up: kcpsmx_tb dut]
module kcpsmxIndex(
  address, instruction,
  port_id,
  write_strobe, out_port,
  read_strobe, in_port,
  interrupt,
`ifdef HAS_INTERRUPT_ACK
  interrupt_ack,
`endif
  reset, clk
);
output reg [`code_depth-1:0] address; ///< Address output.
input [`code_width-1:0] instruction; ///< Instruction input.
output reg [`port_depth-1:0] port_id; ///< Port address.
output reg write_strobe; ///< Port output strobe.
output reg [`port_width-1:0] out_port; ///< Port output.
output reg read_strobe; ///< Port input strobe.
input [`port_width-1:0] in_port; ///< Port input.
input interrupt; ///< Interrupt request.
`ifdef HAS_INTERRUPT_ACK
output interrupt_ack; ///< Interrupt acknowledge (output).
`endif
input reset; ///< Reset input.
input clk; ///< Clock input.

/* Processor registers and signals. */
reg [`code_depth-1:0] program_counter; ///< Program counter.
reg timing_control; ///< Timing control register.

reg zero; ///< Zero flag
reg carry; ///< Carry flag
reg interrupt_enable; ///< Interrupt enable.
reg interrupt_latch; ///< Interrupt latch hold.
reg interrupt_ack; ///< Interrupt acknowledge.
reg zero_saved; ///< Interrupt-saved zero flag.
reg carry_saved; ///< Interrupt-saved carry flag.
`ifdef HAS_RESET_LATCH
reg [1:0] reset_latch; ///< Reset latch.
`endif
reg zero_carry_write_enable; ///< Zero/Carry update.

wire internal_reset; ///< Internal reset signal.
wire [`code_depth-1:0] program_counter_1; ///< Program_counter plus 1.
wire [`stack_depth-1:0] stack_pointer_1; ///< Stack_pointer plus/minus 1.
reg [`stack_depth-1:0] stack_pointer_1p; ///< Registered (previous) stack_pointer_1
wire conditional_match; ///< True when unconditional or flags match.

/* IDU - Instruction decode unit. */
wire [`operation_width-1:0] idu_operation;
`ifdef KCPSM1
wire [`suboperation_width-1:0] idu_suboperation;
`endif
`ifdef KCPSM2
wire idu_suboperation;
`endif
wire [2:0] idu_shift_operation;
wire idu_shift_direction, idu_shift_constant;
wire idu_operand_selection;
wire [`register_depth-1:0] idu_x_address, idu_y_address;
wire [`operand_width-1:0] idu_implied_value;
wire [`port_depth-1:0] idu_port_address;
`ifdef HAS_SCRATCH_MEMORY
wire [`scratch_depth-1:0] idu_scratch_address;
`endif
wire [`code_depth-1:0] idu_code_address;
wire idu_conditional;
wire [1:0] idu_condition_flags;
wire idu_interrupt_enable;

kcpsmx_idu idu(
  instruction,
  idu_operation,
`ifdef KCPSM1
  idu_suboperation,
`endif
`ifdef KCPSM2
  idu_suboperation,
`endif
  idu_shift_operation, idu_shift_direction, idu_shift_constant,
  idu_operand_selection,
  idu_x_address, idu_y_address,
  idu_implied_value, idu_port_address,
`ifdef HAS_SCRATCH_MEMORY
  idu_scratch_address,
`endif
  idu_code_address,
  idu_conditional, idu_condition_flags,
  idu_interrupt_enable
);

/* ALU - Arithmetic/logic unit. */
wire [`operand_width-1:0] alu_result, alu_operand_a, alu_operand_b;
wire alu_zero_out, alu_carry_out;

kcpsmx_alu alu(
  idu_operation,
  idu_shift_operation, idu_shift_direction, idu_shift_constant,
  alu_result, alu_operand_a, alu_operand_b, carry,
  alu_zero_out, alu_carry_out
);

/* Register file. */
reg register_x_write_enable;
wire [`register_width-1:0] register_x_data_in, register_x_data_out, register_y_data_out;

kcpsmx_register register(
  idu_x_address, register_x_write_enable, register_x_data_in, register_x_data_out,
  idu_y_address, register_y_data_out,
  reset, clk
);

/* Call/return stack. */
reg [`stack_depth-1:0] stack_pointer; ///< Call stack pointer.
wire [`stack_width-1:0] stack_data_out;
wire [`stack_width-1:0] stack_data_in =
  (interrupt_latch == 0) ? program_counter_1 : program_counter;
reg stack_write_enable;
wire [`stack_depth-1:0] stack_address =
  (stack_write_enable) ? stack_pointer : stack_pointer_1;

kcpsmx_stack stack(
  stack_address, stack_write_enable, stack_data_in, stack_data_out,
  reset, clk
);

/* Scratchpad RAM. */
`ifdef HAS_SCRATCH_MEMORY
reg scratch_write_enable;
wire [`scratch_depth-1:0] scratch_address =
  (idu_operand_selection == 0) ? idu_scratch_address :
  register_y_data_out[`scratch_depth-1:0];
wire [`scratch_width-1:0] scratch_data_out;

kcpsmx_scratch scratch(
  scratch_address, scratch_write_enable, register_x_data_out, scratch_data_out,
  reset, clk
);
`endif

/* Miscellaneous. */
`ifdef HAS_RESET_LATCH
assign internal_reset = reset_latch[1];
`else
assign internal_reset = reset;
`endif
assign program_counter_1 = program_counter + 1;
assign stack_pointer_1 =
  (stack_write_enable) ? stack_pointer + 1 : stack_pointer - 1;
assign conditional_match =
  (!idu_conditional
  || idu_condition_flags == `flag_c && carry
  || idu_condition_flags == `flag_nc && ~carry
  || idu_condition_flags == `flag_z && zero
  || idu_condition_flags == `flag_nz && ~zero
  ) ? 1 : 0;

assign alu_operand_a = register_x_data_out;
assign alu_operand_b =
  (idu_operand_selection == 0) ? idu_implied_value : register_y_data_out;
// synthesis parallel_case full_case
assign register_x_data_in =
`ifdef HAS_SCRATCH_MEMORY
  (idu_operation == `opcode_fetch) ? scratch_data_out :
`endif
`ifdef KCPSM1
  (idu_operation[3:1] == `opcode_input) ? in_port :
`else
  (idu_operation == `opcode_input) ? in_port :
`endif
  alu_result;

task jump;
input [`code_depth-1:0] next_address;
begin
  program_counter <= next_address;
end
endtask

task push;
input [`code_depth-1:0] next_address;
begin
  stack_pointer <= stack_pointer_1p; // == stack_pointer+1
  program_counter <= next_address;
end
endtask

task pop;
begin
  stack_pointer <= stack_pointer_1; // == stack_pointer-1
  program_counter <= stack_data_out;
end
endtask

task execute;
input [`operation_width-1:0] operation;
`ifdef KCPSM1
input [`suboperation_width-1:0] suboperation;
`endif
`ifdef KCPSM2
input suboperation;
`endif
begin
  // synthesis parallel_case full_case
`ifdef KCPSM1
  casex (operation)
`else
  case (operation)
`endif
    `opcode_load: register_x_write_enable <= 1;

    `opcode_and,
    `opcode_or,
    `opcode_xor,
    `opcode_add,
    `opcode_addcy,
    `opcode_sub,
    `opcode_subcy,
    `opcode_rs: begin
        register_x_write_enable <= 1; // writeback sX
        zero_carry_write_enable <= 1; // writeback zero, carry
      end

`ifdef KCPSM1
    {`opcode_ctl, 1'b?}:
      casex (suboperation)
        {`opcode_jump, 2'b??}:
          if (conditional_match) jump(idu_code_address);

        {`opcode_call, 2'b??}:
          if (conditional_match) push(idu_code_address);

        `opcode_return:
          if (conditional_match) pop;

        `opcode_returni: begin
            pop;
            zero <= zero_saved;
            carry <= carry_saved;
            interrupt_enable <= idu_interrupt_enable;
          end

        `opcode_interrupt: interrupt_enable <= idu_interrupt_enable;
      endcase

    {`opcode_input, 1'b?}: begin
        read_strobe <= 1;
        register_x_write_enable <= 1;
      end

    {`opcode_output, 1'b?}:
      write_strobe <= 1;
`endif // KCPSM1

`ifdef KCPSM2
    `opcode_jump: // == `opcode_return
      if (suboperation) // jump
        if (conditional_match) jump(idu_code_address);
      else // return
        if (conditional_match) pop;

    `opcode_call:
      if (suboperation && conditional_match) push(idu_code_address);

    `opcode_returni: // == `opcode_interrupt
      if (!suboperation) begin // returni
        pop;
        zero <= zero_saved;
        carry <= carry_saved;
        interrupt_enable <= idu_interrupt_enable;
      end
      else // interrupt
        interrupt_enable <= idu_interrupt_enable;

    `opcode_input: begin
        read_strobe <= 1;
        register_x_write_enable <= 1;
      end

    `opcode_output:
      write_strobe <= 1;
`endif // KCPSM2

`ifdef KCPSM3
    `opcode_jump:
      if (conditional_match) jump(idu_code_address);

    `opcode_call:
      if (conditional_match) push(idu_code_address);

    `opcode_return:
      if (conditional_match) pop;

    `opcode_returni: begin
        pop;
        zero <= zero_saved;
        carry <= carry_saved;
        interrupt_enable <= idu_interrupt_enable;
      end

    `opcode_interrupt: interrupt_enable <= idu_interrupt_enable;

    `opcode_input: begin
        read_strobe <= 1;
        register_x_write_enable <= 1;
      end

    `opcode_output:
      write_strobe <= 1;
`endif // KCPSM3


`ifdef HAS_COMPARE_OPERATION
    `opcode_compare:
      zero_carry_write_enable <= 1;
`endif

`ifdef HAS_TEST_OPERATION
    `opcode_test:
      zero_carry_write_enable <= 1;
`endif

`ifdef HAS_SCRATCH_MEMORY
    `opcode_fetch:
      register_x_write_enable <= 1; // transfer scratch to sX

    `opcode_store:
      scratch_write_enable <= 1; // transfer sX to scratch
`endif

    default: ;
  endcase
end
endtask

// combinatorial block
always @(program_counter, idu_port_address, register_x_data_out) begin
  // default actions
  address = program_counter;
  port_id = idu_port_address;
  out_port = register_x_data_out;
end

`ifdef HAS_RESET_LATCH
always @(posedge clk) begin: on_reset
  if (reset) reset_latch <= 'b11;
  else begin
    reset_latch[1] <= reset_latch[0];
    reset_latch[0] <= 0;
  end
end
`endif

// sequential block
always @(posedge clk) begin
  /* Idle values and default actions. */
  read_strobe <= 0; write_strobe <= 0;
  register_x_write_enable <= 0;
`ifdef HAS_SCRATCH_MEMORY
  scratch_write_enable <= 0;
`endif
  interrupt_ack <= 0;
  zero_carry_write_enable <= 0;

  if (internal_reset) begin: on_internal_reset
    /* Reset values. */
    timing_control <= 0;
    program_counter <= `reset_vector;
    stack_write_enable <= 1; stack_pointer <= 0; stack_pointer_1p <= 0;
    zero <= 0; carry <= 0;
    interrupt_enable <= 0; interrupt_latch <= 0;
  end
  else begin: on_run
    timing_control <= ~timing_control; // step timing control
    stack_write_enable <= ~timing_control;
    stack_pointer_1p <= stack_pointer_1;

    if (interrupt && interrupt_enable) interrupt_latch <= 1;

    if (timing_control == 0) begin
      program_counter <= program_counter_1; // default next program counter

      if (interrupt_latch) begin
        interrupt_enable <= 0; interrupt_latch <= 0; interrupt_ack <= 1;
        zero_saved <= zero; carry_saved <= carry;
        push(`interrupt_vector);
      end
      else
`ifdef KCPSM1
        execute(idu_operation, idu_suboperation);
`endif
`ifdef KCPSM2
        execute(idu_operation, idu_suboperation);
`endif
`ifdef KCPSM3
        execute(idu_operation);
`endif
    end
    else begin // timing_control == 1
      if (zero_carry_write_enable) begin
        zero <= alu_zero_out; carry <= alu_carry_out;
      end
    end

  end // on_run

end
endmodule


/** Register file; dual-port RAM. */
[Up: kcpsmx register]
module kcpsmx_registerIndex(
  x_address, x_write_enable, x_data_in, x_data_out,
  y_address, y_data_out,
  reset, clk
);
input clk, reset, x_write_enable;
input [`register_depth-1:0] x_address, y_address;
input [`register_width-1:0] x_data_in;
output [`register_width-1:0] x_data_out, y_data_out;

reg [`register_width-1:0] dpr[0:`register_size-1];

assign x_data_out = dpr[x_address];
assign y_data_out = dpr[y_address];

always @(posedge clk)
  if (x_write_enable) dpr[x_address] <= x_data_in;

endmodule


/** Scratchpad RAM; single-port RAM. */
`ifdef HAS_SCRATCH_MEMORY
[Up: kcpsmx scratch]
module kcpsmx_scratchIndex(
  address, write_enable, data_in, data_out,
  reset, clk
);
input clk, reset, write_enable;
input [`scratch_depth-1:0] address;
input [`scratch_width-1:0] data_in;
output [`scratch_width-1:0] data_out;

reg [`scratch_width-1:0] spr[0:`scratch_size-1];

assign data_out = spr[address];
always @(posedge clk) if (write_enable) spr[address] <= data_in;

endmodule
`endif

/** Call/return stack; single-port RAM. */
[Up: kcpsmx stack]
module kcpsmx_stackIndex(
  address, write_enable, data_in, data_out,
  reset, clk
);
input clk, reset, write_enable;
input [`stack_depth-1:0] address;
input [`stack_width-1:0] data_in;
output [`stack_width-1:0] data_out;

reg [`stack_width-1:0] spr[0:`stack_size-1];

assign data_out = spr[address];
always @(posedge clk) if (write_enable) spr[address] <= data_in;

endmodule


/** Instruction decode unit. */
[Up: kcpsmx idu]
module kcpsmx_iduIndex(
  instruction,
  operation,
`ifdef KCPSM1
  suboperation,
`endif
`ifdef KCPSM2
  suboperation,
`endif
  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
);
input [`code_width-1:0] instruction; ///< Instruction.
output [`operation_width-1:0] operation; ///< Main operation.
`ifdef KCPSM1
output [`suboperation_width-1:0] suboperation; ///< Suboperation operation.
`endif
`ifdef KCPSM2
output suboperation; ///< Suboperation operation.
`endif
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 (kps(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 KCPSM1
assign operation =
  (instruction[15:12] == `opcode_reg) ? instruction[3:0] :
  instruction[15:12];
assign suboperation = 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 KCPSM2
assign operation = {instruction[17], instruction[15:13]};
assign suboperation = 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 KCPSM3
assign operation = 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];

endmodule


/** Arithmetic-logic unit. */
[Up: kcpsmx alu]
module kcpsmx_aluIndex(
  operation,
  shift_operation, shift_direction, shift_constant,
  result, operand_a, operand_b, carry_in,
  zero_out, carry_out
);
input [`operation_width-1:0] operation; ///< Main operation.
input [2:0] shift_operation; ///< Rotate/shift operation.
input shift_direction; ///< Rotate/shift left(0)/right(1).
input shift_constant; ///< Shift constant (0 or 1).
output reg [`operand_width-1:0] result; ///< ALU result.
input [`operand_width-1:0] operand_a, operand_b; ///< ALU operands.
input carry_in; ///< Carry in.
output reg zero_out; ///< Zero out.
output reg carry_out; ///< Carry out.

/** Adder/substracter second operand. */
wire [`operand_width-1:0] addsub_b =
  (operation == `opcode_sub
  || operation == `opcode_subcy
`ifdef HAS_COMPARE_OPERATION
  || operation == `opcode_compare
`endif
  ) ? ~operand_b :
  operand_b;

/** Adder/substracter carry. */
wire addsub_carry =
  (operation == `opcode_addcy) ? carry_in :
  (operation == `opcode_sub
`ifdef HAS_COMPARE_OPERATION
  || operation == `opcode_compare
`endif
  ) ? 1 : // ~b => b'
  (operation == `opcode_subcy) ? ~carry_in : // ~b - c => b' - c
  0;

/** Adder/substracter with carry. */
wire [1+`operand_width-1:0] addsub_result = operand_a + addsub_b + addsub_carry;

/** Shift bit value. */
// synthesis parallel_case full_case
wire shift_bit =
  (shift_operation == `opcode_rr) ? result[0] : // == `opcode_slx
  (shift_operation == `opcode_rl) ? result[7] : // == `opcode_srx
  (shift_operation == `opcode_rsa) ? carry_in :
  shift_constant; // == `opcode_rsc

// always @*
always @(operation,
  shift_operation, shift_direction, shift_constant, shift_bit,
  result, operand_a, operand_b, carry_in,
  zero_out, carry_out,
  addsub_result, addsub_carry
  ) begin: on_alu
  /* Defaults */
  carry_out = 0;

  // synthesis parallel_case full_case
  case (operation)
    `opcode_add,
    `opcode_addcy:
      {carry_out, result} = addsub_result;

`ifdef HAS_COMPARE_OPERATION
    `opcode_compare,
`endif
    `opcode_sub,
    `opcode_subcy:
      {carry_out, result} = {~addsub_result[8], addsub_result[7:0]};

    `opcode_and:
      result = operand_a & operand_b;

    `opcode_or:
      result = operand_a | operand_b;

`ifdef HAS_TEST_OPERATION
    `opcode_test:
      begin result = operand_a & operand_b; carry_out = ^result; end
`endif

    `opcode_xor:
      result = operand_a ^ operand_b;

    `opcode_rs:
      if (shift_direction) // shift right
        {result, carry_out} = {shift_bit, operand_a};
      else // shift left
        {carry_out, result} = {operand_a, shift_bit};

    default:
      result = operand_b;
  endcase

  zero_out = ~|result;
end

endmodule

HierarchyFilesModulesSignalsTasksFunctionsHelp

This page: Maintained by: pbleyer2004N@SPAMembedded.cl
Created:Sun Oct 24 04:56:28 2004
From: kcpsmx.v

Verilog converted to html by v2html 7.30 (written by Costas Calamvokis).Help