summaryrefslogtreecommitdiff
path: root/nandgame/instruction_decode.sv
blob: b78bee84a2fe04c4172a63e3313962159db61961 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Instruction decoder of Nandgame
// corresponds to levels
// - control selector
// - control unit

`timescale 1us/1us

`include "alu.sv"
`include "cond_check.sv"

`ifndef NANDGAME_INS_DECODE
`define NANDGAME_INS_DECODE

module instruction_decode  #(
  parameter DATA_WIDTH = 16
) (
  // instruction to decode
  input [15:0] instruction_in,
  
  // value of A register
  input [(DATA_WIDTH-1):0] A_in,
  // value of D register
  input [(DATA_WIDTH-1):0] D_in,
  // content of memory at address in A register
  input [(DATA_WIDTH-1):0] pA_in,
  
  // result of operation
  output [(DATA_WIDTH-1):0] result_out,
  // whether a jump should occur
  output do_jump_out,

  // whether result should be stored to A
  output dst_A_out,
  // whether result should be stored to D
  output dst_D_out,
  // whether result should be stored in memory at address in A register
  output dst_pA_out,
  // Invalid instruction
  output invalid_ins
);

wire is_immediate_int;
// bit 15 set = ALU instruction_in
// bit 15 unset = immediate
assign is_immediate_int = !instruction_in[15];

// bit 14 must be 1
assign invalid_ins = instruction_in[15] == 1 && instruction_in[14] == 0;

assign dst_A_out = is_immediate_int || instruction_in[5];
assign dst_D_out = !is_immediate_int && instruction_in[4];
assign dst_pA_out = !is_immediate_int && instruction_in[3];

wire use_pA_for_alu_op_int;
wire [(DATA_WIDTH-1):0] alu_operand_Y_int;
assign use_pA_for_alu_op_int = instruction_in[12];
assign alu_operand_Y_int = use_pA_for_alu_op_int ? pA_in : A_in;

wire [(DATA_WIDTH-1):0] alu_result_int;

alu #(
  .DATA_WIDTH(DATA_WIDTH)
) my_alu (
  .X_in(D_in),
  .Y_in(alu_operand_Y_int),
  .u_arith_nlogic_in(instruction_in[10]),
  .opcode_in(instruction_in[9:8]),
  .zx_in(instruction_in[7]),
  .sw_in(instruction_in[6]),
  .result_out(alu_result_int)
);

wire jump_result_int;

cond_check #(
  .DATA_WIDTH(DATA_WIDTH)
) my_cond (
  .X_in(alu_result_int),
  .check_ltz_in(instruction_in[2]),
  .check_eqz_in(instruction_in[1]),
  .check_gtz_in(instruction_in[0]),
  .result_out(jump_result_int)
);

assign do_jump_out = is_immediate_int ? 0 : jump_result_int;
assign result_out = is_immediate_int ? 
                  // technically not needed, since bit is 0 anyway...
                  { 1'b0, instruction_in[(DATA_WIDTH-2):0] } 
                  : alu_result_int;

endmodule

`endif