aboutsummaryrefslogtreecommitdiff
path: root/j1/verilog/j1.v
blob: d69ca20ffa6f5139cef69eaf4afee292ea7eb576 (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
`include "common.h"

module j1(
   input wire clk,
   input wire resetq,

   output wire io_wr,
   output wire [15:0] mem_addr,
   output wire mem_wr,
   output wire [`WIDTH-1:0] dout,
   input  wire [`WIDTH-1:0] mem_din,

   input  wire [`WIDTH-1:0] io_din,

   output wire [12:0] code_addr,
   input  wire [15:0] insn
   );
  reg [`DEPTH-1:0] dsp;      // Data stack pointer
  reg [`DEPTH-1:0] dspN;
  reg [`WIDTH-1:0] st0;     // Top of data stack
  reg [`WIDTH-1:0] st0N;
  reg dstkW;         // D stack write

  reg [12:0] pc, pcN;      
  reg [`DEPTH-1:0] rsp, rspN;
  reg rstkW;          // R stack write
  wire [`WIDTH-1:0] rstkD;   // R stack write value
  reg reboot = 1;
  wire [12:0] pc_plus_1 = pc + 1;

  assign mem_addr = st0N[15:0];
  assign code_addr = {pcN};

  // The D and R stacks
  wire [`WIDTH-1:0] st1, rst0;
  stack #(.DEPTH(`DEPTH))
   dstack(.clk(clk), .resetq(resetq), .ra(dsp), .rd(st1), .we(dstkW), .wa(dspN), .wd(st0));
  stack #(.DEPTH(`DEPTH))rstack(.clk(clk), .resetq(resetq), .ra(rsp), .rd(rst0), .we(rstkW), .wa(rspN), .wd(rstkD));

  always @*
  begin
    // Compute the new value of st0
    casez ({insn[15:8]})
      8'b1??_?????: st0N = { {(`WIDTH - 15){1'b0}}, insn[14:0] };    // literal
      8'b000_?????: st0N = st0;                     // jump
      8'b010_?????: st0N = st0;                     // call
      8'b001_?????: st0N = st1;                     // conditional jump
      8'b011_?0000: st0N = st0;                     // ALU operations...
      8'b011_?0001: st0N = st1;
      8'b011_?0010: st0N = st0 + st1;
      8'b011_?0011: st0N = st0 & st1;
      8'b011_?0100: st0N = st0 | st1;
      8'b011_?0101: st0N = st0 ^ st1;
      8'b011_?0110: st0N = ~st0;
      8'b011_?0111: st0N = {`WIDTH{(st1 == st0)}};
      8'b011_?1000: st0N = {`WIDTH{($signed(st1) < $signed(st0))}};
`ifdef NOSHIFTER // `define NOSHIFTER in common.h to cut slice usage in half and shift by 1 only
      8'b011_?1001: st0N = st1 >> 1;
      8'b011_?1010: st0N = st1 << 1;
`else      // otherwise shift by 1-any number of bits
      8'b011_?1001: st0N = st1 >> st0[4:0];
      8'b011_?1010: st0N = st1 << st0[4:0];
`endif
      8'b011_?1011: st0N = rst0;
      8'b011_?1100: st0N = mem_din;
      8'b011_?1101: st0N = io_din;
      8'b011_?1110: st0N = {{(`WIDTH - 8){1'b0}}, rsp, dsp};
      8'b011_?1111: st0N = {`WIDTH{(st1 < st0)}};
      default: st0N = {`WIDTH{1'bx}};
    endcase
  end

  wire func_T_N =   (insn[6:4] == 1);
  wire func_T_R =   (insn[6:4] == 2);
  wire func_write = (insn[6:4] == 3);
  wire func_iow =   (insn[6:4] == 4);

  wire is_alu = (insn[15:13] == 3'b011);
  assign mem_wr = !reboot & is_alu & func_write;
  assign dout = st1;
  assign io_wr = !reboot & is_alu & func_iow;

  assign rstkD = (insn[13] == 1'b0) ? {{(`WIDTH - 14){1'b0}}, pc_plus_1, 1'b0} : st0;

  reg [`DEPTH-1:0] dspI, rspI;
  always @*
  begin
    casez ({insn[15:13]})
    3'b1??:   {dstkW, dspI} = {1'b1,      4'b0001};
    3'b001:   {dstkW, dspI} = {1'b0,      4'b1111};
    3'b011:   {dstkW, dspI} = {func_T_N,  {insn[1], insn[1], insn[1:0]}};
    default:  {dstkW, dspI} = {1'b0,      4'b0000};
    endcase
    dspN = dsp + dspI;

    casez ({insn[15:13]})
    3'b010:   {rstkW, rspI} = {1'b1,      4'b0001};
    3'b011:   {rstkW, rspI} = {func_T_R,  {insn[3], insn[3], insn[3:2]}};
    default:  {rstkW, rspI} = {1'b0,      4'b0000};
    endcase
    rspN = rsp + rspI;

    casez ({reboot, insn[15:13], insn[7], |st0})
    6'b1_???_?_?:   pcN = 0;
    6'b0_000_?_?,
    6'b0_010_?_?,
    6'b0_001_?_0:   pcN = insn[12:0];
    6'b0_011_1_?:   pcN = rst0[13:1];
    default:        pcN = pc_plus_1;
    endcase
  end

  always @(negedge resetq or posedge clk)
  begin
    if (!resetq) begin
      reboot <= 1'b1;
      { pc, dsp, st0, rsp } <= 0;
    end else begin
      reboot <= 0;
      { pc, dsp, st0, rsp } <= { pcN, dspN, st0N, rspN };
    end
  end
endmodule