2013-10-28 13:19:25 +00:00

165 lines
4.0 KiB
Verilog

// J0 is a stripped-down J1.
// Major changes:
// stacks are only 16 deep
// program counter is only 7 bits (128 instructions)
// DEPTH and LSHIFT instructions removed
// multiply and swab instructions added
module j0(
input sys_clk_i, input sys_rst_i,
output [6:0] insn_addr,
input [15:0] insn,
output mem_rd,
output mem_wr,
output [15:0] mem_addr,
output [15:0] mem_dout,
input [15:0] mem_din,
input pause
);
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; // Top of data stack
reg [15:0] _st0;
wire dstkW; // D stack write
reg [6:0] pc;
reg [6:0] _pc;
reg [4:0] rsp;
reg [4:0] _rsp;
reg rstkW; // R stack write
reg [15:0] rstkD; // R stack write value
wire [6:0] pc_plus_1 = pc + 1;
// The D and R stacks
reg [15:0] dstack[0:31];
reg [15:0] rstack[0:31];
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 [4: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[4], insn[11:8]}; // ALU
default: st0sel <= 4'bxxxx;
endcase
// Compute the new value of T.
if (insn[15])
_st0 <= immediate;
else
case (st0sel)
5'b00000: _st0 <= st0;
5'b00001: _st0 <= st1;
5'b00010: _st0 <= st0 + st1;
5'b00011: _st0 <= st0 & st1;
5'b00100: _st0 <= st0 | st1;
5'b00101: _st0 <= st0 ^ st1;
5'b00110: _st0 <= ~st0;
5'b00111: _st0 <= {16{(st1 == st0)}};
5'b01000: _st0 <= {16{($signed(st1) < $signed(st0))}};
5'b01001: _st0 <= st1 >> st0[3:0];
5'b01010: _st0 <= st0 - 1;
5'b01011: _st0 <= rst0;
5'b01100: _st0 <= mem_din;
5'b01101: _st0 <= st1 * st0;
5'b01110: _st0 <= {st0[7:0], st0[15:8]};
5'b01111: _st0 <= {16{(st1 < st0)}};
default: _st0 <= 16'hxxxx;
endcase
end
wire is_alu = (insn[15:13] == 3'b011);
wire is_lit = (insn[15]);
// assign mem_rd = (is_alu & (insn[11:8] == 4'hc));
assign mem_rd = (st0sel == 5'hc);
assign mem_wr = is_alu & insn[5];
assign mem_addr = st0;
assign mem_dout = st1;
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 // ALU
_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, 1'b0};
end else begin
_rsp = rsp;
rstkW = 0;
rstkD = _pc;
end
end
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[6:0];
else if (is_alu & insn[12])
_pc = rst0[7:1];
else
_pc = pc_plus_1;
end
assign insn_addr = pause ? pc : _pc;
always @(posedge sys_clk_i)
begin
if (sys_rst_i) begin
pc <= 0;
dsp <= 0;
st0 <= 0;
rsp <= 0;
end else if (!pause) begin
pc <= _pc;
dsp <= _dsp;
st0 <= _st0;
rsp <= _rsp;
if (dstkW)
dstack[_dsp] = st0;
if (rstkW)
rstack[_rsp] = rstkD;
end
end
endmodule // j1