Created
May 16, 2016 21:30
-
-
Save four0four/753ea6761247cc18ef39363738b314d7 to your computer and use it in GitHub Desktop.
terribad BFCPU
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
/* 8 bit brainfuck cpu | |
** Author's note: This is a really bad processor. It does all sorts of stupid/bad things in the aim of brainfucking hardware. | |
** codeMem -> 3 bit wire, input opcodes from code memory | |
** codeAddr -> 8 bit address, current pc (usually) | |
** dataMem -> 8 bit read/write to the working array | |
** dataAddr -> 8 bit address to working array | |
** !USE READ FIRST! | |
*/ | |
// TODO - only exec non-[] opcodes if execEn is set | |
// add ic inc/dec into [] opcodes | |
// always inc/dec if execEn is clear, according to skipTo{open,close} | |
// still check opcodes - if we hit a [], we want to clear skipTo so the next clock resumes normal execution | |
module bfcpu( | |
input wire clk, // cpu clock | |
input wire reset, // active low reset (pull up to run) | |
input wire [2:0] codeMem, // brainfuck code memory data | |
output wire [7:0] codeAddr, // brainfuck code memory address | |
output wire dataWriteEn, // brainfuck data/work array write enable line | |
input wire [7:0] dataMemIn, // brainfuck data/work array (into CPU) | |
output wire [7:0] dataMemOut, // brainfuck data/work array (into RAM) | |
output wire [7:0] dataAddr); // brainfuck data/work address | |
parameter PINC=3'b000; // '>' | |
parameter PDEC=3'b001; // '<' | |
parameter DINC=3'b010; // '+' (two cycle) | |
parameter DDEC=3'b011; // '-' (two cycle) | |
parameter OUTB=3'b100; // '.' (??? cycle) | |
parameter INPB=3'b101; // ',' (do we even implement this?) | |
parameter JZER=3'b110; // '[' | |
parameter RETZ=3'b111; // ']' | |
// internal registers | |
reg [7:0] ic; // instruction counter | |
reg [7:0] dc; // data counter | |
reg skipToOpen; // skipping to a '[' (decrementing ic) | |
reg skipToClose; // skipping to a ']' | |
reg [7:0] toWrite; // directly written to RAM | |
reg dataOp; // set to indicate we're in the middle of a data op - these take two cycles (read / writeback) | |
reg memWrite; | |
wire execEn = !(skipToOpen || skipToClose) && !(codeAddr == 8'hFF); | |
wire icDir = skipToClose || !(skipToOpen); // run backward (0) only if skiptoopen is set, otherwise go fwd (1) | |
wire [7:0] icNext = (icDir ? (ic + 1) : (ic - 1)); | |
always @(posedge clk) begin | |
// internal wires | |
if (reset == 1'b1) begin | |
// run this shit | |
if (dataOp == 1'b0) begin | |
memWrite <= 0; | |
end | |
case(codeMem) | |
DINC: | |
if (dataOp == 1'b1) begin | |
toWrite <= dataMemIn + 1; | |
dataOp <= 0; | |
ic <= icNext; | |
end else if (execEn == 1'b1) begin // wait for dmem read | |
dataOp <= 1; | |
memWrite <= 1; | |
end | |
else if (execEn == 1'b0) ic <= icNext; | |
DDEC: | |
if (dataOp == 1'b1) begin | |
toWrite <= dataMemIn - 1; | |
dataOp <= 0; | |
ic <= icNext; | |
end else if (execEn == 1'b1) begin // wait for dmem read | |
dataOp <= 1; | |
memWrite <= 1; | |
end | |
else if (execEn == 1'b0) ic <= icNext; | |
PINC: | |
if (execEn == 1'b1) begin | |
dc <= dc + 1; | |
ic <= icNext; | |
end | |
else if (execEn == 1'b0) ic <= icNext; | |
PDEC: | |
if (execEn == 1'b1) begin | |
dc <= dc - 1; | |
ic <= icNext; | |
end | |
else if (execEn == 1'b0) ic <= icNext; | |
JZER: | |
if (dataOp == 1'b1) begin | |
dataOp <= 0; | |
if (dataMemIn == 0) begin // go find a ']', then resume exec | |
skipToClose <= 1; | |
ic <= icNext; | |
end else begin // we're going to be back - don't skip exec | |
ic <= icNext; | |
end | |
end else if (skipToOpen == 1'b1) begin // we were looking for this! | |
skipToOpen <= 0; | |
dataOp <= 1; // necessary? | |
end else if (execEn == 1'b1) begin | |
dataOp <= 1; | |
end | |
RETZ: | |
if (dataOp == 1'b1) begin | |
dataOp <= 0; | |
if(skipToClose == 1'b1) begin | |
skipToClose <= 0; // found it! resume exec | |
ic <= ic + 1; | |
end else begin // we've been executing on the way | |
skipToOpen <= 1; | |
ic <= ic - 1; | |
end | |
end else begin | |
dataOp <= 1; | |
end | |
default: ic <= icNext; // wtf? just try the next one... | |
endcase | |
end | |
else begin | |
// startup conditions | |
ic <= 0; | |
dc <= 0; | |
skipToClose <= 0; | |
skipToOpen <= 0; | |
end | |
end | |
/* // determine next instruction counter combinatorially. | |
always @(posedge clk) begin | |
if(icDir == 1'b1) icNext <= ic + 1; | |
else icNext <= ic - 1; | |
end*/ | |
assign dataWriteEn = memWrite; | |
assign dataMemOut = toWrite; | |
assign dataAddr = dc; | |
assign codeAddr = ic; | |
endmodule |
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
module bftop( | |
input CLK, | |
input BTN_CLK, | |
input BTN_RST, | |
output [7:0] LED); | |
wire [7:0] dMemAddr; | |
wire [7:0] dMemIn; | |
wire [7:0] dMemOut; | |
wire [7:0] cMemAddr; | |
wire [2:0] cMemOut; | |
wire dWriteLine; | |
wire debugClock; | |
wire incTest; | |
reg [7:0] cnt; | |
BUFG buttonBuf( | |
.I(incTest), | |
.O(debugClock) ); | |
debugClock test( | |
.button(BTN_CLK), | |
.clk(CLK), | |
.debugClk(incTest)); | |
bfcpu cpu( | |
.clk(debugClock), | |
.reset(~BTN_RST), | |
.codeMem(cMemOut), | |
.codeAddr(cMemAddr), | |
.dataWriteEn(dWriteLine), | |
.dataMemIn(dMemIn), | |
.dataMemOut(dMemOut), | |
.dataAddr(dMemAddr) | |
); | |
/* debugDataMem dMem( | |
.clk(CLK), | |
.we(dWriteLine), | |
.dout(dMemIn), | |
.debugOut(LED), | |
.din(dMemOut), | |
.addr(dMemAddr) | |
);*/ | |
blk_mem_gen_v7_3_0 cMem( | |
.clka(CLK), | |
.addra(cMemAddr), | |
.douta(cMemOut) | |
); | |
blk_mem_gen_v7_3_1 dMem( | |
.clka(CLK), | |
.addra(dMemAddr), | |
.dina(dMemOut), | |
.douta(dMemIn), | |
.wea(dWriteLine) | |
); | |
assign LED = dMemIn; | |
endmodule | |
// temporary data memory - used for testing on hardware | |
module debugDataMem( | |
input wire clk, | |
input wire we, | |
output reg [7:0] dout, | |
output wire [7:0] debugOut, | |
input wire [7:0] din, | |
input wire [7:0] addr); | |
reg [7:0] data [0:255]; | |
always @ (posedge clk) begin | |
if(we == 1'b0) begin | |
data[addr] <= din; | |
end | |
dout <= data[addr]; | |
end | |
assign debugOut = data[7'b0]; | |
endmodule | |
// test this - should be alright for testing | |
module debugClock( | |
input wire button, | |
input wire clk, | |
output wire debugClk); | |
reg [15:0] cnt; | |
reg [1:0] sync; | |
reg state; | |
wire nochange = (sync[0] == ~state); | |
always @ (posedge clk) begin | |
sync[0] <= ~button; // pulled down | |
sync[1] <= sync[0]; | |
end | |
always @ (posedge clk) begin | |
if(nochange) begin | |
cnt <= 0; | |
end else begin | |
cnt <= cnt + 1; | |
if(cnt == 0'hFFFF) | |
state <= ~state; | |
end | |
end | |
assign debugClk = state; | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment