aboutsummaryrefslogtreecommitdiff
path: root/docs/j1/verilog/j1.v
diff options
context:
space:
mode:
Diffstat (limited to 'docs/j1/verilog/j1.v')
-rw-r--r--docs/j1/verilog/j1.v123
1 files changed, 123 insertions, 0 deletions
diff --git a/docs/j1/verilog/j1.v b/docs/j1/verilog/j1.v
new file mode 100644
index 0000000..d69ca20
--- /dev/null
+++ b/docs/j1/verilog/j1.v
@@ -0,0 +1,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