-
-
Save aallan/a2209d843c88fb066f7b0b7fbf59458a to your computer and use it in GitHub Desktop.
J1 stack-based CPU, intended for FPGAs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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