aboutsummaryrefslogtreecommitdiff
path: root/design/stack_machine.v
diff options
context:
space:
mode:
authorWojciech Kosior <kwojtus@protonmail.com>2020-09-01 10:54:59 +0200
committerWojciech Kosior <kwojtus@protonmail.com>2020-09-01 11:04:22 +0200
commitee1f6c47e1eff920068f4bceaf604f9535a2e8a9 (patch)
tree580eb001a72601d254bb29cc348a529490f84808 /design/stack_machine.v
parentcd02ddff8886aa1db29f80d3cc5cf99a349d8258 (diff)
downloadAGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.tar.gz
AGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.zip
start anew
Diffstat (limited to 'design/stack_machine.v')
-rw-r--r--design/stack_machine.v353
1 files changed, 353 insertions, 0 deletions
diff --git a/design/stack_machine.v b/design/stack_machine.v
new file mode 100644
index 0000000..1fddb18
--- /dev/null
+++ b/design/stack_machine.v
@@ -0,0 +1,353 @@
+`default_nettype none
+
+module stack_machine
+ (
+ input wire ACK_I,
+ input wire CLK_I,
+ output reg [19:0] ADR_O,
+ input wire [15:0] DAT_I,
+ output reg [15:0] DAT_O,
+ input wire RST_I,
+ output reg STB_O,
+ output reg CYC_O,
+ output reg WE_O,
+ input wire STALL_I,
+
+ /* non-wishbone */
+ output wire finished
+ );
+
+ reg [19:0] pc;
+ reg [19:0] sp;
+
+ reg [15:0] instr;
+
+ reg [31:0] r0;
+ reg [31:0] r1;
+ reg [31:0] im;
+
+ parameter STEP_START = 0;
+ parameter STEP_LOADING_INSTRUCTION = 1;
+ parameter STEP_PARSING_INSTRUCTION = 2;
+ parameter STEP_LOAD_OR_STORE = 3;
+ parameter STEP_PERFORM_OPERATION = 4;
+ reg [2:0] step;
+
+ reg [15:0] DAT_I_latched;
+ reg [15:0] instruction_latched;
+ reg instruction_just_received;
+ wire [15:0] instruction;
+ assign instruction = instruction_just_received ?
+ DAT_I_latched : instruction_latched;
+
+ /* Results of instruction parsing */
+ wire shift_immediate; /* only if modify_immediate is true */
+ assign shift_immediate = instruction[11];
+
+ /* only if shift_immediate is true */
+ wire [10:0] immediate_bits_to_shift;
+ assign immediate_bits_to_shift = instruction[10:0];
+
+ /* only if shift_immediate is false */
+ wire set_immediate;
+ assign set_immediate = instruction[10];
+
+ /* only if (set_immediate && !shift_immediate) is true */
+ wire [31:0] immediate_value_to_set;
+ assign immediate_value_to_set = {{22{instruction[9]}}, instruction[9:0]};
+
+ /* only if (!set_immediate && !shift_immediate) is true */
+ wire add_immediate;
+ assign add_immediate = instruction[9];
+
+ /* only if (add_immediate && !set_immediate && !shift_immediate) is true */
+ wire [9:0] immediate_value_to_add;
+ assign immediate_value_to_add = instruction[8:0];
+
+
+ wire [31:0] new_im;
+ assign new_im = shift_immediate ? {im[20:0], immediate_bits_to_shift} :
+ set_immediate ? immediate_value_to_set :
+ add_immediate ? im + immediate_value_to_add : im;
+
+
+ wire shift_regs;
+ assign shift_regs = instruction[12];
+
+
+ wire load_or_store;
+ assign load_or_store = instruction[15];
+
+ wire [19:0] addr_to_use; /* only if load_or_store is true */
+ /* The implementation is currently unable to make non-aligned accesses */
+ assign addr_to_use = new_im / 2 + (immediate_addressing ? 0 : sp);
+
+ wire load; /* only if load_or_store is true */
+ assign load = instruction[14];
+
+ wire store; /* only if load_or_store is true */
+ assign store = !load;
+
+ wire immediate_addressing; /* only if load_or_store is true */
+ assign immediate_addressing = instruction[13];
+ wire sp_addressing; /* only if load_or_store is true */
+ assign sp_addressing = !immediate_addressing;
+
+ wire load_or_store_r0; /* only if load_or_store is true */
+ assign load_or_store_r0 = instruction[12];
+
+ wire load_or_store_r1; /* only if load_or_store is true */
+ assign load_or_store_r1 = !load_or_store_r0;
+
+
+ /* only if load_or_store is false */
+ wire cond_jump;
+ assign cond_jump = instruction[14:13] == 2'b11;
+
+ /* only if load_or_store is false */
+ wire jump;
+ assign jump = instruction[14:13] == 2'b10;
+
+ /* only if load_or_store is false */
+ wire exchange_r1_im;
+ assign exchange_r1_im = instruction[14:13] == 2'b01;
+
+ /* only if load_or_store is false */
+ wire immediate_modification;
+ assign immediate_modification
+ = instruction[14:13] == 0 &&
+ (shift_immediate || set_immediate || add_immediate);
+
+ wire extended_instruction; /* only if load_or_store is false */
+ assign extended_instruction = instruction[14:13] == 0 && ! shift_immediate &&
+ !set_immediate && !add_immediate;
+
+ /* only if (!load_or_store && extended_instruction) is true */
+ wire [8:0] extended_instruction_bits;
+ assign extended_instruction_bits = instruction[8:0];
+
+ /* extended instructions */
+ parameter INSTR_MUL = 9'd6;
+ parameter INSTR_DIV = 9'd5;
+ parameter INSTR_SUB = 9'd4;
+ parameter INSTR_ADD = 9'd3;
+ parameter INSTR_SET_SP = 9'd2;
+ parameter INSTR_HALT = 9'd1;
+ parameter INSTR_NOP = 9'd0;
+
+ /* module for division */
+ wire [31:0] div_quotient;
+ wire [31:0] div_remainder;
+ wire div_done;
+
+ div
+ #(
+ .WIDTH(32)
+ ) div
+ (
+ .clock(CLK_I),
+ .start(step == STEP_PARSING_INSTRUCTION),
+ .dividend(r0),
+ .divisor(r1),
+
+ .quotient(div_quotient),
+ .remainder(div_remainder),
+ .done(div_done)
+ );
+
+ assign finished = !load_or_store && extended_instruction &&
+ extended_instruction_bits == INSTR_HALT;
+
+
+ reg [15:0] second_word_to_store;
+
+ /*
+ * Variables necessary to know where we are when transferring
+ * a sequence of words through wishbone
+ */
+ reg first_command_sent;
+ reg first_ack_received;
+
+ /* Informs us, that DAT_I_latched should be moved to r0 or r1 */
+ reg load_half_of_r0;
+ reg load_half_of_r1;
+
+`ifdef SIMULATION
+ /*
+ * RST should still be used when powering up, even in benches;
+ * this is just to avoid undefined values
+ */
+ initial begin
+ ADR_O <= 0;
+ STB_O <= 0;
+ CYC_O <= 0;
+ WE_O <= 0;
+
+ r0 <= 0;
+ r1 <= 0;
+ im <= 0;
+ pc <= 0;
+ sp <= 20'h40000;
+ step <= STEP_START;
+ instruction_latched <= 0;
+ instruction_just_received <= 0;
+ end
+`endif
+
+ always @ (posedge CLK_I) begin
+ DAT_I_latched <= DAT_I;
+
+ /*
+ * Later part of this always block sets them to 1 under certain
+ * conditions, which takes precedence over this assignment
+ */
+ load_half_of_r0 <= 0;
+ load_half_of_r1 <= 0;
+ instruction_just_received <= 0;
+
+ if (RST_I) begin
+ STB_O <= 0;
+ CYC_O <= 0;
+
+ pc <= 0;
+ sp <= 20'h40000;
+ step <= STEP_START;
+ end else begin
+ case (step)
+ STEP_START : begin
+ ADR_O <= pc;
+ STB_O <= 1;
+ CYC_O <= 1;
+ WE_O <= 0;
+ step <= STEP_LOADING_INSTRUCTION;
+ pc <= pc + 1;
+ end
+ STEP_LOADING_INSTRUCTION : begin
+ if (!STALL_I)
+ STB_O <= 0;
+
+ if (ACK_I) begin
+ instruction_just_received <= 1;
+ step <= STEP_PARSING_INSTRUCTION;
+ CYC_O <= 0;
+ end
+ end // case: STEP_LOADING_INSTRUCTION
+ STEP_PARSING_INSTRUCTION : begin
+ im <= new_im;
+ instruction_latched <= instruction;
+
+ first_command_sent <= 0;
+ first_ack_received <= 0;
+
+ if (shift_regs)
+ {r0, r1} <= {r1, r0}; /* magic! */
+
+ if (load_or_store) begin
+ CYC_O <= 1;
+ STB_O <= 1;
+ WE_O <= store;
+ ADR_O <= addr_to_use;
+
+ /* Even if not a store, setting these won't break anything */
+ DAT_O <= load_or_store_r0 ? r0[15:0] : r1[15:0];
+ second_word_to_store <= load_or_store_r0 ?
+ r0[31:16] : r1[31:16];
+
+ if (load_or_store_r0)
+ sp <= sp + (load ? 2 : -2);
+
+ step <= STEP_LOAD_OR_STORE;
+ end else begin // if (load_or_store)
+ if (immediate_modification) begin
+ step <= STEP_START;
+ end else if (exchange_r1_im || extended_instruction) begin
+ step <= STEP_PERFORM_OPERATION;
+ end else if (jump) begin
+ pc <= new_im / 2;
+ step <= STEP_START;
+ end else if (cond_jump) begin
+ if (r1 != 0)
+ pc <= new_im / 2;
+
+ step <= STEP_START;
+ end else begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ step <= STEP_START;
+ end
+ end // else: !if(load_or_store)
+ end // case: STEP_PARSING_INSTRUCTION
+ STEP_LOAD_OR_STORE : begin
+ if (!STALL_I) begin
+ ADR_O <= ADR_O + 1;
+
+ DAT_O <= second_word_to_store;
+
+ if (!first_command_sent)
+ first_command_sent <= 1;
+ else
+ STB_O <= 0;
+ end // if (!STALL_I)
+
+ if (ACK_I) begin
+ if (load) begin
+ if (load_or_store_r0)
+ load_half_of_r0 <= 1;
+ else
+ load_half_of_r1 <= 1;
+ end
+
+ if (!first_ack_received)
+ first_ack_received <= 1;
+ else
+ step <= STEP_START;
+ end // if (ACK_I)
+ end // case: STEP_LOAD_OR_STORE
+ STEP_PERFORM_OPERATION : begin
+ step <= STEP_START; /* unless overwritten in case block below */
+
+ if (extended_instruction) begin
+ case (extended_instruction_bits)
+ INSTR_NOP :
+ ;
+ INSTR_HALT :
+ step <= step; /* stay in this step forever */
+ INSTR_SET_SP :
+ sp <= im / 2;
+ INSTR_ADD :
+ r0 <= r0 + r1;
+ INSTR_SUB :
+ r0 <= r0 - r1;
+ INSTR_DIV : begin
+ {r0, r1} <= {div_quotient, div_remainder};
+ if (!div_done)
+ step <= step;
+ end
+ INSTR_MUL :
+ r0 <= r0 * r1;
+ default : begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ end
+ endcase // case (extended_instruction_bits)
+ end else if (exchange_r1_im) begin
+ {r1, im} <= {im, r1};
+ end else begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ end
+ end // case: STEP_PERFORM_OPERATION
+ endcase // case (step)
+ end // else: !if(RST_I)
+
+ if (load_half_of_r0)
+ r0 <= {DAT_I_latched, r0[31:16]};
+
+ if (load_half_of_r1)
+ r1 <= {DAT_I_latched, r1[31:16]};
+ end // always @ (posedge CLK_I)
+
+endmodule // stack_machine