diff --git a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v index f759aa3..cd0234a 100644 --- a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v +++ b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v @@ -39,9 +39,10 @@ wire [19:0] address_bus; wire [15:0] data_bus_read,data_bus_write; wire rd,wr,BHE,IOMEM; +wire CPU_SPEED=counter[6]; system system( - /* MISC */ counter[9],reset + /* MISC */ CPU_SPEED,reset /* MEMORY / IO */ ,address_bus,data_bus_read,data_bus_write,BHE,rd,wr,IOMEM,HALT,ERROR ); @@ -94,22 +95,85 @@ always @(posedge counter[15]) begin endcase end - - - -always @(negedge wr) begin - if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin - //disp_write_cache[disp_cache_end]<=data_bus_write[7:0]; - disp_write_cache[disp_cache_end]<=data_bus_write[15:8]; - disp_cache_end<=disp_cache_end+6'd1; - end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin - if(data_bus_write[0:0]==1) - rgb_led_color=3'b000; - else - rgb_led_color=3'b111; - end +/* TODO This seems to be a bug with YOSYS. If I don't initialise the memory + * it doesn't work (even though it does in sim), and for example if i + * initialise 1 twice to the same value it breaks again. + * + * This seems to affect brainfuck_compiled.asm and specifically when the + * compiled code starts running ( or the compiler i guess ) + */ +initial begin +disp_write_cache[ 0]=8'h46; +disp_write_cache[ 1]=8'h46; +disp_write_cache[ 2]=8'h46; +disp_write_cache[ 3]=8'h46; +disp_write_cache[ 4]=8'h46; +disp_write_cache[ 5]=8'h46; +disp_write_cache[ 6]=8'h46; +disp_write_cache[ 7]=8'h46; +disp_write_cache[ 8]=8'h46; +disp_write_cache[ 9]=8'h46; +disp_write_cache[10]=8'h46; +disp_write_cache[11]=8'h46; +disp_write_cache[12]=8'h46; +disp_write_cache[13]=8'h46; +disp_write_cache[14]=8'h46; +disp_write_cache[15]=8'h46; +disp_write_cache[16]=8'h46; +disp_write_cache[17]=8'h46; +disp_write_cache[18]=8'h46; +disp_write_cache[19]=8'h46; +disp_write_cache[20]=8'h46; +disp_write_cache[21]=8'h46; +disp_write_cache[22]=8'h46; +disp_write_cache[23]=8'h46; +disp_write_cache[24]=8'h46; +disp_write_cache[25]=8'h46; +disp_write_cache[26]=8'h46; +disp_write_cache[27]=8'h46; +disp_write_cache[28]=8'h46; +disp_write_cache[29]=8'h46; +disp_write_cache[30]=8'h46; +disp_write_cache[31]=8'h46; +disp_write_cache[32]=8'h46; +disp_write_cache[33]=8'h46; +disp_write_cache[34]=8'h46; +disp_write_cache[35]=8'h46; +disp_write_cache[36]=8'h46; +disp_write_cache[37]=8'h46; +disp_write_cache[38]=8'h46; +disp_write_cache[39]=8'h46; +disp_write_cache[40]=8'h46; +disp_write_cache[41]=8'h46; +disp_write_cache[42]=8'h46; +disp_write_cache[43]=8'h46; +disp_write_cache[44]=8'h46; +disp_write_cache[45]=8'h46; +disp_write_cache[46]=8'h46; +disp_write_cache[47]=8'h46; +disp_write_cache[48]=8'h46; +disp_write_cache[49]=8'h46; +disp_write_cache[50]=8'h46; +disp_write_cache[51]=8'h46; +disp_write_cache[52]=8'h46; +disp_write_cache[53]=8'h46; +disp_write_cache[54]=8'h46; +disp_write_cache[55]=8'h46; +disp_write_cache[56]=8'h46; +disp_write_cache[57]=8'h46; +disp_write_cache[58]=8'h46; +disp_write_cache[59]=8'h46; +disp_write_cache[60]=8'h46; +disp_write_cache[61]=8'h46; +disp_write_cache[62]=8'h46; +disp_write_cache[63]=8'h46; end +//TODO similarly as above, if I remove this the same thing breaks +always @(negedge wr) begin +end + + //------------------------------------------// // Cache to allow the slow display to have a // chance to keep up with the relentless CPU @@ -118,24 +182,33 @@ reg [5:0] disp_cache_start=0; reg [5:0] disp_cache_end=0; reg [7:0] disp_write_cache [63:0]; reg ascii_state=0; -always @(posedge clk48)begin - case (ascii_state) - 1'b0:begin - if(ascii_data_ready&disp_cache_start!=disp_cache_end)begin - ascii_data<=disp_write_cache[disp_cache_start]; - disp_cache_start<=disp_cache_start+6'd1; - ascii_data_write_req<=1; - ascii_state<=1'b1; - end +always @(posedge CPU_SPEED)begin + + if(wr==0)begin + if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin + disp_write_cache[disp_cache_end]<=data_bus_write[15:8]; + disp_cache_end<=disp_cache_end+6'd1; + end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin + if(data_bus_write[0:0]==1) + rgb_led_color=3'b000; + else + rgb_led_color=3'b111; end - 1'b1:begin - if(!ascii_data_ready)begin - ascii_data_write_req<=0; - ascii_state<=1'b0; - end + end else if(ascii_state==1'b0)begin + if(ascii_data_ready&disp_cache_start!=disp_cache_end)begin + ascii_data<=disp_write_cache[disp_cache_start]; + disp_cache_start<=disp_cache_start+6'd1; + ascii_data_write_req<=1; + ascii_state<=1'b1; end - default: begin end - endcase + end + + if(ascii_state==1'b1)begin + if(!ascii_data_ready)begin + ascii_data_write_req<=0; + ascii_state<=1'b0; + end + end end wire I2C_SPEED=counter[7]; @@ -190,7 +263,7 @@ pcf8574_for_HD44780 PCF8574_driver( wire SCL,SDA,I2C_BUSY,I2C_SEND; assign gpio_1=SCL; assign gpio_0=SDA; -reg [7:0]i2c_data; + I2C_driver i2c_driver( .clock(I2C_SPEED), @@ -200,7 +273,7 @@ I2C_driver i2c_driver( .address(7'h27), .I2C_BUSY(I2C_BUSY), .I2C_SEND(I2C_SEND), - .i2c_data(i2c_data), + .i2c_data(i2c_data) ); endmodule diff --git a/system/peripherals/ascii_to_HD44780_driver.v b/system/peripherals/ascii_to_HD44780_driver.v index e176c67..f43d4a8 100644 --- a/system/peripherals/ascii_to_HD44780_driver.v +++ b/system/peripherals/ascii_to_HD44780_driver.v @@ -44,8 +44,8 @@ initial begin init_cmd_data[ 5] = 4'h8; init_cmd_data[ 6] = 4'h0; //0x07 init_cmd_data[ 7] = 4'h7; - init_cmd_data[ 8] = 4'h0; //0x0C - init_cmd_data[ 9] = 4'hC; + init_cmd_data[ 8] = 4'h0; //0x0F + init_cmd_data[ 9] = 4'hF; init_cmd_data[10] = 4'h0; //0x01 init_cmd_data[11] = 4'h1; init_cmd_data[12] = 4'h0; //0x06 @@ -55,12 +55,9 @@ initial begin end reg [4:0] init_seq=0; -reg [5:0] data_write_wait_counter = 0; reg [3:0] init_cmd_data [15:0]; -reg byte_n=0; - reg [7:0]print_data; reg [1:0]line=0; @@ -70,186 +67,202 @@ reg [7:0] driver_state =0; reg next_line; -always @(posedge clock,negedge rst_n) begin +always @(posedge clock) begin if(rst_n==0)begin in_data_ready<=0; write_req<=1'b0; init_seq<=5'd0; - data_write_wait_counter<=6'd0; - byte_n<=1'b0; cmd_data<=1'b0; line<=0; col<=0; driver_state<=0; end else begin - if (data_write_wait_counter!=6'd0 && done_writing) begin - data_write_wait_counter<=data_write_wait_counter-6'd1; - write_req<=1'b0; - in_data_ready<=0; - end else begin - case(driver_state) - 8'd0:begin - if(done_writing)begin - if(init_seq!=5'd16&&data_write_wait_counter==6'd0)begin - /** Initialise display **/ - data<=init_cmd_data[init_seq[3:0]]; - init_seq<=init_seq+5'd1; - write_req<=1'b1; - data_write_wait_counter<=6'd50; - in_data_ready<=0; - end else if(col==6'd20)begin - /** Check if we run out of screen **/ - data<=4'hf; - write_req<=1'b1; - cmd_data<=1'b0; - data_write_wait_counter<=6'd50; - driver_state<=8'd2; - next_line<=1; - end else if(data_write_req==1)begin - if(in_ascii_data==8'h0a)begin - data<=4'hf; - cmd_data<=1'b0; - write_req<=1'b1; - driver_state<=8'd2; - next_line<=1; - end else if(in_ascii_data==8'h0d)begin - data<=4'hf; - cmd_data<=1'b0; - write_req<=1'b1; - driver_state<=8'd2; - next_line<=0; - end else begin - cmd_data<=1'b1; - print_data<=in_ascii_data; - driver_state<=8'd9; - end - in_data_ready<=0; - end else begin - in_data_ready<=1; - end + case(driver_state) + 8'd0:begin + if(init_seq!=5'd16)begin + /** Initialise display **/ + data<=init_cmd_data[init_seq[3:0]]; + cmd_data<=1'b0; + in_data_ready<=0; + if(!done_writing)begin + init_seq<=init_seq+5'd1; + driver_state<=8'd12; + write_req<=1'b0; end else begin - write_req<=1'b0; - in_data_ready<=0; + write_req<=1'b1; end - end - 8'd1:begin - if(done_writing==1) - driver_state<=8'd2; - end - 8'd2:begin - data<=4'hE; + end else if(col==6'd20)begin + /** Check if we run out of screen **/ + driver_state<=8'd6; cmd_data<=1'b0; - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd3; - write_req<=1'b0; - end else - write_req<=1'b1; - end - 8'd3:begin - if(done_writing==1) - driver_state<=8'd4; - end - 8'd4:begin - data<=4'h0; - cmd_data<=1'b0; - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd5; - write_req<=1'b0; - end else - write_req<=1'b1; - end - 8'd5:begin - if(done_writing==1) + next_line<=1; + end else if(data_write_req==1)begin + if(in_ascii_data==8'h0A)begin driver_state<=8'd6; + cmd_data<=1'b0; + next_line<=1; + end else if(in_ascii_data==8'h0D)begin + driver_state<=8'd6; + cmd_data<=1'b0; + next_line<=0; + end else begin + if (in_ascii_data[7:5]==3'b000||in_ascii_data[7:7]==1'b1) + if(in_ascii_data==8'h00) + print_data<=8'h23; + else + print_data<=8'h3F; + else + print_data<=in_ascii_data; + cmd_data<=1'b1; + driver_state<=8'd9; + end + in_data_ready<=0; + end else begin + in_data_ready<=1; end - 8'd6:begin + end + + //////////////////////////////////////////////// + /* TODO: These are unreachable states but from + * what i assume to be a bug in yosys. They need + * to be here for brainfuck_compiled.asm to work. + * Specifically for the compiled program to not output + * random characters. + */ + 8'd14:begin + data<=4'hf; + next_line<=1; + if(!done_writing)begin + driver_state<=8'd1; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd13:begin + data<=4'hf; + if(!done_writing)begin + driver_state<=8'd1; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd1:begin + if(done_writing==1) + driver_state<=8'd2; + end + 8'd2:begin + data<=4'hE; + if(!done_writing)begin + driver_state<=8'd3; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd3:begin + if(done_writing==1) + driver_state<=8'd4; + end + 8'd4:begin + data<=4'h0; + cmd_data<=1'b0; + if(!done_writing)begin + driver_state<=8'd5; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd5:begin + if(done_writing==1) + driver_state<=8'd6; + end + //////////////////////////////////////////////// + + 8'd6:begin + if(next_line)begin + case(line) + 2'd0: data<=4'hC; + 2'd1: data<=4'h9; + 2'd2: data<=4'hD; + 2'd3: data<=4'hD; + endcase + end else begin + case(line) + 2'd0: data<=4'h8; + 2'd1: data<=4'hC; + 2'd2: data<=4'h9; + 2'd3: data<=4'hD; + endcase + end + if(done_writing==0)begin + driver_state<=8'd7; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd7:begin + if(done_writing==1) + driver_state<=8'd8; + end + 8'd8:begin + if(next_line)begin + case(line) + 2'd0: begin data<=4'h0; ; end + 2'd1: begin data<=4'h4; ; end + 2'd2: begin data<=4'h4; ; end + 2'd3: begin data<=4'h4; ; end + endcase + end else begin + case(line) + 2'd0: begin data<=4'h0; ; end + 2'd1: begin data<=4'h0; ; end + 2'd2: begin data<=4'h4; ; end + 2'd3: begin data<=4'h4; ; end + endcase + end + if(!done_writing)begin + driver_state<=8'd12; + col<=0; + write_req<=1'b0; if(next_line)begin case(line) - 2'd0: data<=4'hC; - 2'd1: data<=4'h9; - 2'd2: data<=4'hD; - 2'd3: data<=4'hD; - endcase - end else begin - case(line) - 2'd0: data<=4'h0; - 2'd1: data<=4'hC; - 2'd2: data<=4'h9; - 2'd3: data<=4'hD; + 2'd0: begin line<=1; end + 2'd1: begin line<=2; end + 2'd2: begin line<=3; end + 2'd3: begin line<=3; end endcase end - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd7; - write_req<=1'b0; - end else - write_req<=1'b1; - end - 8'd7:begin - if(done_writing==1) - driver_state<=8'd8; - end - 8'd8:begin - if(next_line)begin - case(line) - 2'd0: begin data<=4'h0; ; end - 2'd1: begin data<=4'h4; ; end - 2'd2: begin data<=4'h4; ; end - 2'd3: begin data<=4'h4; ; end - endcase - end else begin - case(line) - 2'd0: begin data<=4'h0; ; end - 2'd1: begin data<=4'h0; ; end - 2'd2: begin data<=4'h4; ; end - 2'd3: begin data<=4'h4; ; end - endcase - end - cmd_data<=1'b0; - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd0; - col<=0; - write_req<=1'b0; - if(next_line)begin - case(line) - 2'd0: begin line<=1; end - 2'd1: begin line<=2; end - 2'd2: begin line<=3; end - 2'd3: begin line<=3; end - endcase - end - end else - write_req<=1'b1; - end - 8'd9:begin - data<=print_data[7:4]; - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd10; - write_req<=1'b0; - end else - write_req<=1'b1; - end - 8'd10:begin - if(done_writing==1) - driver_state<=8'd11; - end - 8'd11:begin - data<=print_data[3:0]; - data_write_wait_counter<=6'd50; - if(!done_writing)begin - driver_state<=8'd0; - write_req<=1'b0; - col<=col+1; - end else - write_req<=1'b1; - end - default: begin driver_state<=0; end - endcase - end + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd9:begin + data<=print_data[7:4]; + if(!done_writing)begin + driver_state<=8'd10; + write_req<=1'b0; + end else + write_req<=1'b1; + end + 8'd10:begin + if(done_writing==1) + driver_state<=8'd11; + end + 8'd11:begin + data<=print_data[3:0]; + if(!done_writing)begin + driver_state<=8'd12; + write_req<=1'b0; + col<=col+1; + end else + write_req<=1'b1; + end + 8'd12:begin + if(done_writing) + driver_state<=8'd0; + end + default: begin driver_state<=0; end + endcase + end end