I wanted to start learning Verilog and made a really simple brainfuck CPU.
Specifications:
Memory | 16384 Bytes |
Cell size | 1 Byte |
Cell overflow | Wrap |
Address overflow | Wrap |
Max code size | 1024 Instructions |
Maximum nested loops | 512 |
I/O | Full stdin/stdout |
Can be synthesized | Nope |
Registers | 139314 Bits |
module main;
reg [7:0] mem [0:16383];
reg [13:0] ptr = 0;
reg [2:0] code [0:1023];
reg [9:0] pc = 0;
reg [9:0] stack [0:511];
reg [9:0] sp = 0;
integer stdin, stdout;
reg clk = 0;
reg [7:0] skip = 0;
integer tmp1;
reg [7:0] tmp2;
always @(posedge clk) begin
if (skip) begin
if (code[pc] == 3'b110) skip++; // [
if (code[pc] == 3'b111) skip--; // ]
end else case(code[pc])
3'b000: mem[ptr]++; // +
3'b001: mem[ptr]--; // -
3'b010: $fwrite(stdout, "%c", mem[ptr]); // .
3'b011: begin
tmp1 = $fread(tmp2, stdin); // ,
mem[ptr] = tmp2;
end
3'b100: ptr++; // >
3'b101: ptr--; // <
3'b110: begin // [
if (!mem[ptr]) begin
skip = 1;
end else begin
stack[sp] = pc;
sp++;
end
end
3'b111: begin // ]
if (mem[ptr]) begin
pc = stack[sp - 1];
end else begin
sp--;
end
end
endcase
pc++;
if (pc == 0) $finish;
end
integer k;
initial begin
for (k = 0; k < 16383; k = k + 1) mem[k] = 0;
for (k = 0; k < 1023; k = k + 1) code[k] = 0;
for (k = 0; k < 255; k = k + 1) stack[k] = 0;
code[0] = 3'b000;
code[1] = 3'b110;
code[2] = 3'b011;
code[3] = 3'b010;
code[4] = 3'b111;
stdin = $fopen("/dev/stdin", "r");
stdout = $fopen("/dev/stdout", "w");
end
always #1 clk = ~clk;
endmodule
I have pre-loaded the cat program +[,.]
which echos back everything you input.
To compile it i am using Icarus Verilog:
pixel@pixel-PC:~/bfcpu$ iverilog -o bf bf.v
pixel@pixel-PC:~/bfcpu$ ./bf
Hello
Hello
World
World
And it works!
Unfortunately it cannot be synthesized because it uses file I/O and because I am using arrays instead of memory.