Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #1516
| From | Chris Hinsley <chris.hinsley@gmail.com> |
|---|---|
| Newsgroups | comp.lang.forth |
| Date | 2011-04-25 16:17 +0100 |
| Message-ID | <2011042516174712230-chrishinsley@gmailcom> (permalink) |
| References | <cea3f9ee-8e66-4a64-acda-53e46ace819c@34g2000pru.googlegroups.com> <abWdnfSMsqLrKDfQnZ2dnUVZ8sudnZ2d@brightview.co.uk> |
| Subject | Re: Writing a forth kernel |
On 2011-04-17 10:40:06 +0100, Jan Coombs said:
> On 17/04/11 02:11, usao wrote:
>> Im working on a home-brew 12-bit CPU, and would like to impelement
>> FORTH on it. Where can I locate details on how to implement a kernel
>> using assembly?
>
> This recent Novix style CPU is about the same size as yours, and has
> documentation, code support and applications:
>
> "J1 is a small (200 lines of Verilog) stack-based CPU, intended
> for FPGAs. A complete J1 with 16Kbytes of RAM fits easily on a
> small Xilinx FPGA"
>
> http://www.excamera.com/sphinx/fpga-j1.html
>
> I'm part way through translating the code into MyHDL, a sort of
> interactive hardware development environment. This is a learning
> exercise for me, so, if I haven't learned enough I'll have a go at
> Bernd Paysan's b16 processor next.
>
> For machines this small the compiler is often PC hosted, but it might
> be interesting to include one on a very small target like one of these.
>
> Jan Coombs
Jan, here's a version of the J1 I did, with a bit of code tidying and
renameing to help me understand it better. Any errors are mine and not
nesseserally the original authors.
I was going to paramaterise it so you can pick and choose the width of
the registers and depth of the stacks etc. But in case this helps at
all have a copy of this.
module j1(
input i_clk, input i_rst, input [15:0] io_din,
output io_rd, output io_wr, output [15:0] io_addr, output [15:0] io_dout);
// pc register
reg [12:0] pc;
reg [12:0] _pc;
// instruction word
wire [15:0] insn;
// data stack
reg [4:0] dsp; // data stack index
reg [4:0] _dsp; // next data stack index
reg [15:0] ds0; // current top of data stack
reg [15:0] _ds0; // next top of data stack
// return stack
reg [4:0] rsp; // return stack index
reg [4:0] _rsp; // next return stack index
reg [15:0] _rs0; // next top of return stack
wire _dsW; // data stack write signal
reg _rsW; // return stack write signal
wire _ramWE; // RAM write enable
wire [15:0] ramrd;
// next pc value if we need it
wire [15:0] pc_plus_1;
assign pc_plus_1 = pc + 1;
// internal data and return stacks.
// each clock we may write the top of data stack
// or the next top of return stack
// plus we read out the next on data stack and current top of return stack
reg [15:0] dstack[0:31];
reg [15:0] rstack[0:31];
always @(posedge i_clk)
begin
if (_dsW) dstack[_dsp] = ds0;
if (_rsW) rstack[_rsp] = _rs0;
end
wire [15:0] ds1 = dstack[dsp];
wire [15:0] rs0 = rstack[rsp];
// opcode for the ALU operation.
// For jump and call the operation is T, for 0branch it is N.
// For ALU ops it is loaded from the instruction field.
reg [3:0] opcode;
always @(*)
begin
case (insn[14:13])
2'b00: opcode = 0; // jump
2'b10: opcode = 0; // call
2'b01: opcode = 1; // 0branch
2'b11: opcode = insn[11:8]; // ALU
endcase
end
// this bit is specific to your FPGA !
// it's a dual port ram with A and B channels
// instructions are coming from A
`define RAMS 3
`define w (16 >> `RAMS)
`define w1 (`w - 1)
genvar i;
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(i_clk),
.ADDRA({_pc}),
.DIB(ds1[`w*i+`w1:`w*i]),
// .DIPB(2'b0),
.WEB(_ramWE & (_ds0[15:14] == 0)),
.ENB(|_ds0[15:14] == 0),
.CLKB(i_clk),
.ADDRB(_ds0[15:1]),
.DOB(ramrd[`w*i+`w1:`w*i]));
end
endgenerate
// compute next top of data stack
always @(*)
begin
if (insn[15])
begin
// immediate value from instruction word
_ds0 = {1'b0, insn[14:0]};
end
else
begin
// do the alu opcode
case (opcode)
4'b0000: _ds0 = ds0;
4'b0001: _ds0 = ds1;
4'b0010: _ds0 = ds0 + ds1;
4'b0011: _ds0 = ds0 & ds1;
4'b0100: _ds0 = ds0 | ds1;
4'b0101: _ds0 = ds0 ^ ds1;
4'b0110: _ds0 = ~ds0;
4'b0111: _ds0 = {16{(ds1 == ds0)}};
4'b1000: _ds0 = {16{($signed(ds1) < $signed(ds0))}};
4'b1001: _ds0 = ds1 >> ds0[3:0];
4'b1010: _ds0 = ds0 - 1;
4'b1011: _ds0 = rs0;
4'b1100: _ds0 = |ds0[15:14] ? io_din : ramrd;
4'b1101: _ds0 = ds1 << ds0[3:0];
4'b1110: _ds0 = {rsp, 3'b000, dsp};
4'b1111: _ds0 = {16{(ds1 < ds0)}};
endcase
end
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 = ds0;
assign io_dout = ds1;
assign _ramWE = is_alu & insn[5];
assign _dsW = is_lit | (is_alu & insn[7]);
// data and return stack deltas if needed
wire [1:0] dd = insn[1:0];
wire [1:0] rd = insn[3:2];
always @(*)
begin
if (is_lit)
begin
// literal
_dsp = dsp + 1;
_rsp = rsp;
_rsW = 0;
_rs0 = _pc;
end
else if (is_alu)
begin
// alu op
_dsp = dsp + {{3{dd[1]}}, dd};
_rsp = rsp + {{3{rd[1]}}, rd};
_rsW = insn[6];
_rs0 = ds0;
end
else
begin
// jump, call or 0branch
// what happens to data stack
if (insn[15:13] == 3'b001)
begin
// 0branch we drop the condition
_dsp = dsp - 1;
end
else
begin
_dsp = dsp;
end
// what happens to return stack
if (insn[15:13] == 3'b010)
begin
// call
_rsp = rsp + 1;
_rsW = 1;
_rs0 = {pc_plus_1[14:0], 1'b0};
end
else
begin
// jump or 0branch
_rsp = rsp;
_rsW = 0;
_rs0 = _pc;
end
end
end
// what the next pc is going to be
always @(*)
begin
if (i_rst)
begin
// reset
_pc = pc;
end
else
begin
if ((insn[15:13] == 3'b000)
| ((insn[15:13] == 3'b001) & (|ds0 == 0))
| (insn[15:13] == 3'b010))
begin
// going to be jump, 0branch or call
_pc = insn[12:0];
end
else if (is_alu & insn[12])
begin
// alu op also includes a return
_pc = rs0[15:1];
end
else
begin
// or just moving on to next instruction
_pc = pc_plus_1;
end
end
end
// each clock update to the next state or reset
always @(posedge i_clk)
begin
if (i_rst)
begin
// reset
pc <= 0;
dsp <= 0;
rsp <= 0;
ds0 <= 0;
end
else
begin
// next state
pc <= _pc;
dsp <= _dsp;
rsp <= _rsp;
ds0 <= _ds0;
end
end
endmodule
Back to comp.lang.forth | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Writing a forth kernel usao <rwatki@gmail.com> - 2011-04-16 18:11 -0700
Re: Writing a forth kernel BruceMcF <agila61@netscape.net> - 2011-04-16 19:18 -0700
Re: Writing a forth kernel "P.M.Lawrence" <pml540114@gmail.com> - 2011-04-17 00:21 -0700
Re: Writing a forth kernel Jan Coombs <jan_2011-02@murray-microft.co.uk> - 2011-04-17 10:40 +0100
Re: Writing a forth kernel Chris Hinsley <chris.hinsley@gmail.com> - 2011-04-25 16:17 +0100
Re: Writing a forth kernel Jan Coombs <jan_2011-02@murray-microft.co.uk> - 2011-04-29 00:51 +0100
Re: Writing a forth kernel wzab <wzab01@gmail.com> - 2011-05-13 09:04 -0700
Re: Writing a forth kernel Jan Coombs <jan_2011-02@murray-microft.co.uk> - 2011-05-13 23:49 +0100
Re: Writing a forth kernel Albert van der Horst <albert@spenarnc.xs4all.nl> - 2011-04-17 22:38 +0000
Re: Writing a forth kernel Tarkin <tarkin000@gmail.com> - 2011-04-26 08:14 -0700
Re: Writing a forth kernel Chris Hinsley <chris.hinsley@gmail.com> - 2011-04-27 02:09 +0100
csiph-web