diff --git a/css/ui.css b/css/ui.css index 3ea22d41..967901dd 100644 --- a/css/ui.css +++ b/css/ui.css @@ -39,6 +39,10 @@ .tooltiperror { color: #ff3333; } +.tooltiperrorline { + color:#ffcccc; + background-color:#660000; +} #controls_top { position: absolute; padding: 0.5em; diff --git a/presets/verilog/framebuf_vpu.v b/presets/verilog/framebuf_vpu.v new file mode 100644 index 00000000..6c996652 --- /dev/null +++ b/presets/verilog/framebuf_vpu.v @@ -0,0 +1,184 @@ +`include "hvsync_generator.v" +`include "sprite_bitmap.v" +`include "sprite_renderer.v" +`include "cpu8.v" + +// uncomment to see scope view +//`define DEBUG + +module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, + address_bus, to_cpu, from_cpu, write_enable +`ifdef DEBUG + , output [7:0] A + , output [7:0] B + , output [7:0] IP + , output carry + , output zero +`else + ,rgb +`endif +); + + input clk, reset; + input hpaddle, vpaddle; + output hsync, vsync; + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; +`ifdef DEBUG + assign IP = cpu.IP; + assign A = cpu.A; + assign B = cpu.B; + assign carry = cpu.carry; + assign zero = cpu.zero; +`else + output [3:0] rgb; +`endif + + parameter IN_HPOS = 8'b01000000; + parameter IN_VPOS = 8'b01000001; + parameter IN_FLAGS = 8'b01000010; + parameter IN_VPU = 8'b01000011; + + reg [7:0] ram[0:63]; + reg [7:0] rom[0:127]; + + output wire [7:0] address_bus; + output reg [7:0] to_cpu; + output wire [7:0] from_cpu; + output wire write_enable; + + CPU cpu(.clk(clk), + .reset(reset), + .address(address_bus), + .data_in(to_cpu), + .data_out(from_cpu), + .write(write_enable)); + + always @(posedge clk) + if (write_enable) begin + casez (address_bus) + // VPU lo byte + 8'b0001000: begin + vpu_write[15:8] <= from_cpu; + end + // VPU hi byte + 8'b0001001: begin + vpu_write[7:0] <= from_cpu; + end + // VPU write + 8'b0001010: begin + vpu_ram[vpu_write] <= from_cpu[7:4]; + vpu_ram[vpu_write+1] <= from_cpu[3:0]; + vpu_write <= vpu_write + 2; + end + // VPU move + 8'b0001011: begin + // sign extend + vpu_write <= { + vpu_write[15:8] + { {4{from_cpu[7]}}, from_cpu[7:4] }, + vpu_write[7:0] + { {4{from_cpu[3]}}, from_cpu[3:0] } + }; + end + default: ram[address_bus[5:0]] <= from_cpu; + endcase + end + + always @(*) + casez (address_bus) + // RAM + 8'b00??????: to_cpu = ram[address_bus[5:0]]; + // special read registers + IN_HPOS: to_cpu = hpos[7:0]; + IN_VPOS: to_cpu = vpos[7:0]; + IN_FLAGS: to_cpu = {3'b0, + vsync, hsync, vpaddle, hpaddle, display_on}; + IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]}; + // ROM + 8'b1???????: to_cpu = rom[address_bus[7:0] + 128]; + default: ; + endcase + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(0), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + reg [3:0] vpu_ram[0:65535]; + reg [15:0] vpu_read; + reg [15:0] vpu_write; + reg [3:0] rgb; + + always @(posedge clk) begin + if (!hpos[8] && !vpos[8]) begin + rgb <= vpu_ram[vpu_read]; + vpu_read <= vpu_read + 1; + end else begin + rgb <= 0; + if (vpos[8]) + vpu_read <= 0; + end + end +\end{lstlisting} + +We also have a simple test program that writes repeated patterns to the VPU: + +\begin{lstlisting}[language=femto8] +`ifdef EXT_INLINE_ASM + initial begin + rom = '{ + __asm +.arch femto8 +.org 128 +.len 128 + +.define VPU_LO 8 +.define VPU_HI 9 +.define VPU_WRITE 10 +.define VPU_MOVE 11 + +.define IN_HPOS $40 +.define IN_VPOS $41 +.define IN_FLAGS $42 + +.define F_DISPLAY 1 +.define F_HPADDLE 2 +.define F_VPADDLE 4 +.define F_HSYNC 8 +.define F_VSYNC 16 + +Start: + zero A + sta VPU_LO + sta VPU_HI + sta 0 +DisplayLoop: + zero B + mov A,[b] + sta VPU_WRITE + sta VPU_MOVE + sta VPU_WRITE + sta VPU_MOVE + sta VPU_WRITE + sta VPU_MOVE + lda #F_VSYNC + ldb #IN_FLAGS + and none,[B] + bz DisplayLoop +WaitVsync: + and none,[B] + bnz WaitVsync + zero B + mov A,[b] + inc A + sta 0 + jmp DisplayLoop + __endasm + }; + end +`endif diff --git a/src/views.ts b/src/views.ts index f28aa2f3..485e9086 100644 --- a/src/views.ts +++ b/src/views.ts @@ -55,7 +55,7 @@ export class SourceEditor implements ProjectView { dirtylisting = true; sourcefile : SourceFile; currentDebugLine : number; - lines2errmsg = []; + errorwidgets = []; createDiv(parent:HTMLElement, text:string) { var div = document.createElement('div'); @@ -83,7 +83,7 @@ export class SourceEditor implements ProjectView { clearTimeout(timer); timer = setTimeout( () => { current_project.updateFile(this.path, this.editor.getValue()); - }, 200); + }, 300); }); this.editor.on('cursorActivity', (ed) => { var start = this.editor.getCursor(true); @@ -111,18 +111,14 @@ export class SourceEditor implements ProjectView { getPath() : string { return this.path; } addErrorMarker(line:number, msg:string) { + var tooltip = document.createElement("span"); + tooltip.setAttribute("class", "tooltiperrorline"); var div = document.createElement("div"); div.setAttribute("class", "tooltipbox tooltiperror"); div.appendChild(document.createTextNode("\u24cd")); - var tooltip = document.createElement("span"); - tooltip.setAttribute("class", "tooltiptext"); - if (this.lines2errmsg[line]) - msg = this.lines2errmsg[line] + "\n" + msg; - tooltip.appendChild(document.createTextNode(msg)); - this.lines2errmsg[line] = msg; - div.appendChild(tooltip); this.editor.setGutterMarker(line, "gutter-info", div); - //this.editor.addLineWidget(line, div); + tooltip.appendChild(document.createTextNode(msg)); + this.errorwidgets.push(this.editor.addLineWidget(line, tooltip)); } markErrors(errors:WorkerError[]) { @@ -142,8 +138,11 @@ export class SourceEditor implements ProjectView { clearErrors() { this.editor.clearGutter("gutter-info"); this.refreshDebugState(); + //this.lines2errmsg = []; this.dirtylisting = true; - this.lines2errmsg = []; + // clear line widgets + while (this.errorwidgets.length) + this.errorwidgets.shift().clear(); } getSourceFile() : SourceFile { return this.sourcefile; }