Skip to content

Instantly share code, notes, and snippets.

@aallan
Created March 5, 2018 12:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aallan/a2209d843c88fb066f7b0b7fbf59458a to your computer and use it in GitHub Desktop.
Save aallan/a2209d843c88fb066f7b0b7fbf59458a to your computer and use it in GitHub Desktop.
J1 stack-based CPU, intended for FPGAs.
// J1 Forth CPU
// http://www.excamera.com/sphinx/fpga-j1.html
// http://www.excamera.com/files/j1.pdf
module j1(
input sys_clk_i, input sys_rst_i, input [15:0] io_din,
output io_rd, output io_wr, output [15:0] io_addr, output [15:0] io_dout);
wire [15:0] insn;
wire [15:0] immediate = { 1'b0, insn[14:0] };
wire [15:0] ramrd;
reg [4:0] dsp; // Data stack pointer
reg [4:0] _dsp;
reg [15:0] st0; // Return stack pointer
reg [15:0] _st0;
wire _dstkW; // D stack write
reg [12:0] pc;
reg [12:0] _pc;
reg [4:0] rsp;
reg [4:0] _rsp;
reg _rstkW; // R stack write
reg [15:0] _rstkD;
wire _ramWE; // RAM write enable
wire [15:0] pc_plus_1;
assign pc_plus_1 = pc + 1;
// The D and R stacks
reg [15:0] dstack[0:31];
reg [15:0] rstack[0:31];
always @(posedge sys_clk_i)
begin
if (_dstkW)
dstack[_dsp] = st0;
if (_rstkW)
rstack[_rsp] = _rstkD;
end
wire [15:0] st1 = dstack[dsp];
wire [15:0] rst0 = rstack[rsp];
// st0sel is the ALU operation. For branch and call the operation
// is T, for 0branch it is N. For ALU ops it is loaded from the instruction
// field.
reg [3:0] st0sel;
always @*
begin
case (insn[14:13])
2'b00: st0sel = 0; // ubranch
2'b10: st0sel = 0; // call
2'b01: st0sel = 1; // 0branch
2'b11: st0sel = insn[11:8]; // ALU
default: st0sel = 4'bxxxx;
endcase
end
`define RAMS 3
genvar i;
`define w (16 >> `RAMS)
`define w1 (`w - 1)
generate
for (i = 0; i < (1 << `RAMS); i=i+1) begin : ram
// RAMB16_S18_S18
RAMB16_S2_S2
ram(
.DIA(0),
// .DIPA(0),
.DOA(insn[`w*i+`w1:`w*i]),
.WEA(0),
.ENA(1),
.CLKA(sys_clk_i),
.ADDRA({_pc}),
.DIB(st1[`w*i+`w1:`w*i]),
// .DIPB(2'b0),
.WEB(_ramWE & (_st0[15:14] == 0)),
.ENB(|_st0[15:14] == 0),
.CLKB(sys_clk_i),
.ADDRB(_st0[15:1]),
.DOB(ramrd[`w*i+`w1:`w*i]));
end
endgenerate
// Compute the new value of T.
always @*
begin
if (insn[15])
_st0 = immediate;
else
case (st0sel)
4'b0000: _st0 = st0;
4'b0001: _st0 = st1;
4'b0010: _st0 = st0 + st1;
4'b0011: _st0 = st0 & st1;
4'b0100: _st0 = st0 | st1;
4'b0101: _st0 = st0 ^ st1;
4'b0110: _st0 = ~st0;
4'b0111: _st0 = {16{(st1 == st0)}};
4'b1000: _st0 = {16{($signed(st1) < $signed(st0))}};
4'b1001: _st0 = st1 >> st0[3:0];
4'b1010: _st0 = st0 - 1;
4'b1011: _st0 = rst0;
4'b1100: _st0 = |st0[15:14] ? io_din : ramrd;
4'b1101: _st0 = st1 << st0[3:0];
4'b1110: _st0 = {rsp, 3'b000, dsp};
4'b1111: _st0 = {16{(st1 < st0)}};
default: _st0 = 16'hxxxx;
endcase
end
wire is_alu = (insn[15:13] == 3'b011);
wire is_lit = (insn[15]);
assign io_rd = (is_alu & (insn[11:8] == 4'hc));
assign io_wr = _ramWE;
assign io_addr = st0;
assign io_dout = st1;
assign _ramWE = is_alu & insn[5];
assign _dstkW = is_lit | (is_alu & insn[7]);
wire [1:0] dd = insn[1:0]; // D stack delta
wire [1:0] rd = insn[3:2]; // R stack delta
always @*
begin
if (is_lit) begin // literal
_dsp = dsp + 1;
_rsp = rsp;
_rstkW = 0;
_rstkD = _pc;
end else if (is_alu) begin
_dsp = dsp + {dd[1], dd[1], dd[1], dd};
_rsp = rsp + {rd[1], rd[1], rd[1], rd};
_rstkW = insn[6];
_rstkD = st0;
end else begin // jump/call
// predicated jump is like DROP
if (insn[15:13] == 3'b001) begin
_dsp = dsp - 1;
end else begin
_dsp = dsp;
end
if (insn[15:13] == 3'b010) begin // call
_rsp = rsp + 1;
_rstkW = 1;
_rstkD = {pc_plus_1[14:0], 1'b0};
end else begin
_rsp = rsp;
_rstkW = 0;
_rstkD = _pc;
end
end
end
always @*
begin
if (sys_rst_i)
_pc = pc;
else
if ((insn[15:13] == 3'b000) |
((insn[15:13] == 3'b001) & (|st0 == 0)) |
(insn[15:13] == 3'b010))
_pc = insn[12:0];
else if (is_alu & insn[12])
_pc = rst0[15:1];
else
_pc = pc_plus_1;
end
always @(posedge sys_clk_i)
begin
if (sys_rst_i) begin
pc <= 0;
dsp <= 0;
st0 <= 0;
rsp <= 0;
end else begin
dsp <= _dsp;
pc <= _pc;
st0 <= _st0;
rsp <= _rsp;
end
end
endmodule // j1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment