URL
https://opencores.org/ocsvn/rtftextcontroller/rtftextcontroller/trunk
Subversion Repositories rtftextcontroller
[/] [rtftextcontroller/] [trunk/] [rtl/] [verilog/] [rfTextController.sv] - Rev 32
Compare with Previous | Blame | View Log
// ============================================================================// __// \\__/ o\ (C) 2006-2023 Robert Finch, Waterloo// \ __ / All rights reserved.// \/_// robfinch<remove>@finitron.ca// ||//// rfTextController.sv// text controller//// BSD 3-Clause License// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// 1. Redistributions of source code must retain the above copyright notice, this// list of conditions and the following disclaimer.//// 2. Redistributions in binary form must reproduce the above copyright notice,// this list of conditions and the following disclaimer in the documentation// and/or other materials provided with the distribution.//// 3. Neither the name of the copyright holder nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.////// Text Controller//// FEATURES//// This core requires an external timing generator to provide horizontal// and vertical sync signals, but otherwise can be used as a display// controller on it's own. However, this core may also be embedded within// another core such as a VGA controller.//// Window positions are referenced to the rising edge of the vertical and// horizontal sync pulses.//// The core includes an embedded dual port RAM to hold the screen// characters.//// The controller expects a 256kB memory region to be reserved.//// Memory Map:// 00000-3FFFF display ram// 40000-7FFFF character bitmap ram// 80000-800FF controller registers////--------------------------------------------------------------------// Registers//// 00h// 7 - 0 cccccccc number of columns (horizontal displayed number of characters)// 15- 8 rrrrrrrr number of rows (vertical displayed number of characters)// 19-16 dddd character output delay// 43-32 nnnn nnnnnnnn window left (horizontal sync position - reference for left edge of displayed)// 59-48 nnnn nnnnnnnn window top (vertical sync position - reference for the top edge of displayed)// 08h// 5- 0 nnnnnn char height in pixels, maximum scan line// 11- 8 wwww pixel size - width// 15-12 hhhh pixel size - height// 21-16 nnnnnn char width in pixels// 24 r reset state bit// 32 e controller enable// 40 m multi-color mode// 41 a anti-alias mode// 48-52 nnnnn yscroll// 56-60 nnnnn xscroll// 10h// 30- 0 cccccccc cccccccc color code for transparent background RGB 4,9,9,9 (only RGB 7,7,7 used)// 63-32 cccc...cccc border color ZRGB 4,9,9,9// 18h// 30- 0 cccccccc cccccccc tile color code 1// 62-32 cccccccc cccccccc tile color code 2// 20h// 4- 0 eeeee cursor end// 7- 5 bbb blink control// BP: 00=no blink// BP: 01=no display// BP: 10=1/16 field rate blink// BP: 11=1/32 field rate blink// 12- 8 sssss cursor start// 15-13 ttt cursor image type (none, box, underline, sidebar, checker, solid// 47-32 aaaaaaaa aaaaaaaa cursor position// 28h// 15- 0 aaaaaaaa aaaaaaaa start address (index into display memory)// 30h// 15- 0 aaaaaaaa aaaaaaaa font address in char bitmap memory// 31-24 dddddd font ascent// 63-32 nnnnnnnn nnnnnnnn font ram lock "LOCK" or "UNLK"//--------------------------------------------------------------------//// 1209 LUTs / 1003 FFs / 48 BRAMs / 1 DSP// ============================================================================//`define USE_CLOCK_GATE//`define SUPPORT_AAM 1`define TC_RAM_ADDR 32'hEC000001`define TC_CBM_ADDR 32'hEC040001`define TC_REG_ADDR 32'hEC080001module rfTextController(rst_i, clk_i, cs_config_i, cs_io_i,cti_i, cyc_i, stb_i, ack_o, wr_i, sel_i, adr_i, dat_i, dat_o,dot_clk_i, hsync_i, vsync_i, blank_i, border_i, zrgb_i, zrgb_o, xonoff_i);parameter num = 4'd1;parameter COLS = 8'd64;parameter ROWS = 8'd32;parameter BUSWID = 32;parameter TEXT_CELL_COUNT = 8192;parameter CFG_BUS = 8'd0;parameter CFG_DEVICE = 5'd1;parameter CFG_FUNC = 3'd0;parameter CFG_VENDOR_ID = 16'h0;parameter CFG_DEVICE_ID = 16'h0;parameter CFG_SUBSYSTEM_VENDOR_ID = 16'h0;parameter CFG_SUBSYSTEM_ID = 16'h0;parameter CFG_ROM_ADDR = 32'hFFFFFFF0;// Sysconinput rst_i; // resetinput clk_i; // clockinput cs_config_i;input cs_io_i;// Slave signalsinput [2:0] cti_i;input cyc_i; // valid bus cycleinput stb_i; // data strobeoutput ack_o; // data acknowledgeinput wr_i; // writeinput [BUSWID/8-1:0] sel_i; // byte lane selectinput [31:0] adr_i; // addressinput [BUSWID-1:0] dat_i; // data inputoutput reg [BUSWID-1:0] dat_o; // data output// Video signalsinput dot_clk_i; // video dot clockinput hsync_i; // end of scan lineinput vsync_i; // end of frameinput blank_i; // blanking signalinput border_i; // border areainput [39:0] zrgb_i; // input pixel streamoutput reg [39:0] zrgb_o; // output pixel streaminput xonoff_i;integer n2,n3;reg controller_enable;reg [39:0] bkColor40, bkColor40d, bkColor40d2, bkColor40d3; // background colorreg [39:0] fgColor40, fgColor40d, fgColor40d2, fgColor40d3; // foreground colorwire [1:0] pix; // pixel value from character generator 1=on,0=offreg por;wire vclk;reg [63:0] rego;reg [5:0] yscroll;reg [5:0] xscroll;reg [11:0] windowTop;reg [11:0] windowLeft;reg [ 7:0] numCols;reg [ 7:0] numRows;reg [ 7:0] charOutDelay;reg [ 1:0] mode;reg [ 5:0] maxRowScan;reg [ 5:0] maxScanpix;reg [1:0] tileWidth; // width of tile in bytes (0=1,1=2,2=4,3=8)reg [ 5:0] cursorStart, cursorEnd;reg [15:0] cursorPos;reg [2:0] cursorType;reg [15:0] startAddress;reg [15:0] fontAddress;reg font_locked;reg [5:0] fontAscent;reg [ 2:0] rBlink;reg [31:0] bdrColor; // Border colorreg [ 3:0] pixelWidth; // horizontal pixel width in clock cyclesreg [ 3:0] pixelHeight; // vertical pixel height in scan linesreg mcm; // multi-color modereg aam; // anti-alias modewire [11:0] hctr; // horizontal reference counter (counts clocks since hSync)wire [11:0] scanline; // scan linereg [ 7:0] row; // vertical reference counter (counts rows since vSync)reg [ 7:0] col; // horizontal columnreg [ 5:0] rowscan; // scan line within rowreg [ 5:0] colscan; // pixel column number within cellwire nxt_row; // when to increment the row counterwire nxt_col; // when to increment the column counterreg [ 5:0] bcnt; // blink timing counterwire blink;reg iblank;reg [5:0] maxScanlinePlusOne;wire nhp; // next horizontal pixelwire ld_shft = nxt_col & nhp;// display and timing signalsreg [15:0] txtAddr; // index into memoryreg [15:0] penAddr;wire [63:0] screen_ram_out; // character codewire [20:0] txtBkColor; // background color codewire [20:0] txtFgColor; // foreground color codewire [5:0] txtZorder;reg [30:0] txtTcCode; // transparent color codereg [30:0] tileColor1;reg [30:0] tileColor2;reg bgt, bgtd, bgtd2;wire [63:0] tdat_o;wire [63:0] chdat_o;reg [63:0] cfg_dat [0:31];reg [63:0] cfg_out;function [63:0] fnRbo;input n;input [63:0] i;fnRbo = n ? {i[7:0],i[15:8],i[23:16],i[31:24],i[39:32],i[47:40],i[55:48],i[63:56]} : i;endfunction//--------------------------------------------------------------------// bus interfacing// Address Decoding// I/O range Dx//--------------------------------------------------------------------// Register the inputsreg cs_config;reg cs_rom, cs_reg, cs_text, cs_any;reg cs_rom1, cs_reg1, cs_text1;reg cs_tc;reg [17:0] radr_i;reg [63:0] rdat_i;reg rwr_i;reg [7:0] rsel_i;reg [7:0] wrs_i;reg [31:0] tc_ram_addr;reg [31:0] tc_cbm_addr;reg [31:0] tc_reg_addr;always_ff @(posedge clk_i)cs_any <= cyc_i & stb_i & cs_io_i;always_ff @(posedge clk_i)cs_config <= cyc_i & stb_i & cs_config_i && adr_i[27:20]==CFG_BUS && adr_i[19:15]==CFG_DEVICE && adr_i[14:12]==CFG_FUNC;always_ff @(posedge clk_i)cs_rom1 <= adr_i[31:18] == tc_cbm_addr[31:18];always_ff @(posedge clk_i)cs_reg1 <= adr_i[31: 8] == tc_reg_addr[31: 8];always_ff @(posedge clk_i)cs_text1 <= adr_i[31:18] == tc_ram_addr[31:18];always_combcs_rom <= cs_rom1 && cs_any;always_combcs_reg <= cs_reg1 && cs_any;always_combcs_text <= cs_text1 && cs_any;always_ff @(posedge clk_i)wrs_i <= (BUSWID==64) ? {8{wr_i}} & sel_i :adr_i[2] ? {{4{wr_i}} & sel_i,4'h0} : {4'h0,{4{wr_i}} & sel_i};always_ff @(posedge clk_i)rwr_i <= wr_i;always_ff @(posedge clk_i)rsel_i <= (BUSWID==64) ? sel_i : adr_i[2] ? {sel_i,4'h0} : {4'h0,sel_i};always_ff @(posedge clk_i)radr_i <= adr_i;always_ff @(posedge clk_i)rdat_i <= (BUSWID==64) ? dat_i : (BUSWID==32) ? {2{dat_i}} : {4{dat_i}};// Register outputsalways_ff @(posedge clk_i)if (BUSWID==64)casez({cs_config,cs_rom,cs_reg,cs_text})4'b1???: dat_o <= cfg_out;4'b01??: dat_o <= chdat_o;4'b001?: dat_o <= rego;4'b0001: dat_o <= tdat_o;default: dat_o <= 'h0;endcaseelse if (BUSWID==32)casez({cs_config,cs_rom,cs_reg,cs_text})4'b1???: dat_o <= radr_i[2] ? cfg_out[63:32] : cfg_out[31:0];4'b01??: dat_o <= radr_i[2] ? chdat_o[63:32] : chdat_o[31:0];4'b001?: dat_o <= radr_i[2] ? rego[63:32] : rego[31:0];4'b0001: dat_o <= radr_i[2] ? tdat_o[63:32] : tdat_o[31:0];default: dat_o <= 'd0;endcaseelsedat_o <= 'd0;//always @(posedge clk_i)// if (cs_text) begin// $display("TC WRite: %h %h", adr_i, dat_i);// $stop;// end// - there is a four cycle latency for reads, an ack is generated// after the synchronous RAM read// - writes can be acknowledged right away.ack_gen #(.READ_STAGES(5),.WRITE_STAGES(1),.REGISTER_OUTPUT(1))uag1 (.rst_i(rst_i),.clk_i(clk_i),.ce_i(1'b1),.i((cs_any|cs_config) & ~rwr_i),.we_i((cs_any|cs_config) & rwr_i),.o(ack_o),.rid_i(0),.wid_i(0),.rid_o(),.wid_o());//--------------------------------------------------------------------// config//--------------------------------------------------------------------initial beginfor (n3 = 0; n3 < 32; n3 = n3 + 1)cfg_dat[n3] = 'd0;endalways_ff @(posedge clk_i)if (rst_i) begintc_ram_addr <= `TC_RAM_ADDR;tc_cbm_addr <= `TC_CBM_ADDR;tc_reg_addr <= `TC_REG_ADDR;endelse beginif (cs_config) beginif (rwr_i)case(radr_i[7:3])5'h02:beginif (&rsel_i[3:0] && rdat_i[31:0]==32'hFFFFFFFF)tc_ram_addr <= 32'hFFFFFFFF; // no memory is neededelse beginif (rsel_i[0]) tc_ram_addr[7:0] <= rdat_i[7:0];if (rsel_i[1]) tc_ram_addr[15:8] <= rdat_i[15:8];if (rsel_i[2]) tc_ram_addr[23:16] <= rdat_i[23:16];if (rsel_i[3]) tc_ram_addr[31:24] <= rdat_i[31:24];endif (&rsel_i[7:4] && rdat_i[31:0]==32'hFFFFFFFF)tc_cbm_addr <= 32'hFFFFFFFF; // no memory is neededelse beginif (rsel_i[4]) tc_cbm_addr[7:0] <= rdat_i[7:0];if (rsel_i[5]) tc_cbm_addr[15:8] <= rdat_i[15:8];if (rsel_i[6]) tc_cbm_addr[23:16] <= rdat_i[23:16];if (rsel_i[7]) tc_cbm_addr[31:24] <= rdat_i[31:24];endend5'h03:beginif (&rsel_i[3:0] && rdat_i[31:0]==32'hFFFFFFFF)tc_reg_addr <= 32'hFFFFFFFF; // no memory is neededelse beginif (rsel_i[0]) tc_reg_addr[7:0] <= rdat_i[7:0];if (rsel_i[1]) tc_reg_addr[15:8] <= rdat_i[15:8];if (rsel_i[2]) tc_reg_addr[23:16] <= rdat_i[23:16];if (rsel_i[3]) tc_reg_addr[31:24] <= rdat_i[31:24];endenddefault:cfg_dat[radr_i[7:3]] <= rdat_i;endcaseelsecase(radr_i[7:3])5'h00: cfg_out <= {32'h0,CFG_DEVICE_ID,CFG_VENDOR_ID};5'h01: cfg_out <= {8'h00,8'h00,8'h00,8'd32,24'h0,8'h0};5'h02: cfg_out <= {tc_cbm_addr,tc_ram_addr};5'h03: cfg_out <= {32'hFFFFFFFF,tc_reg_addr};5'h04: cfg_out <= 64'hFFFFFFFFFFFFFFFF;5'h05: cfg_out <= {CFG_SUBSYSTEM_ID,CFG_SUBSYSTEM_VENDOR_ID,32'h0};5'h06: cfg_out <= {24'h00,8'h00,CFG_ROM_ADDR};5'h07: cfg_out <= {8'd8,8'd0,8'd0,8'd0,32'h0};default: cfg_out <= cfg_dat[radr_i[7:3]];endcaseendend//--------------------------------------------------------------------//--------------------------------------------------------------------`ifdef USE_CLOCK_GATEBUFHCE ucb1 (.I(dot_clk_i), .CE(controller_enable), .O(vclk));`elseassign vclk = dot_clk_i;`endif//--------------------------------------------------------------------// Video Memory//--------------------------------------------------------------------//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Address Calculation:// - Simple: the row times the number of cols plus the col plus the// base screen address//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -reg [15:0] rowcol;always_ff @(posedge vclk)txtAddr <= startAddress + rowcol + col;// Register read-back memory// This core to be found under Memory-Cores folder// Allows reading back of register values by shadowing them with ramwire [3:0] rrm_adr = radr_i[6:3];wire [63:0] rrm_o;regReadbackMem #(.WID(8)) rrm0L(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[0]),.i(rdat_i[7:0]),.o(rrm_o[7:0]));regReadbackMem #(.WID(8)) rrm0H(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[1]),.i(rdat_i[15:8]),.o(rrm_o[15:8]));regReadbackMem #(.WID(8)) rrm1L(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[2]),.i(rdat_i[23:16]),.o(rrm_o[23:16]));regReadbackMem #(.WID(8)) rrm1H(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[3]),.i(rdat_i[31:24]),.o(rrm_o[31:24]));regReadbackMem #(.WID(8)) rrm2L(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[4]),.i(rdat_i[39:32]),.o(rrm_o[39:32]));regReadbackMem #(.WID(8)) rrm2H(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[5]),.i(rdat_i[47:40]),.o(rrm_o[47:40]));regReadbackMem #(.WID(8)) rrm3L(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[6]),.i(rdat_i[55:48]),.o(rrm_o[55:48]));regReadbackMem #(.WID(8)) rrm3H(.wclk(clk_i),.adr(rrm_adr),.wce(cs_reg),.we(rwr_i & rsel_i[7]),.i(rdat_i[63:56]),.o(rrm_o[63:56]));wire [26:0] lfsr1_o;lfsr27 #(.WID(27)) ulfsr1(rst_i, dot_clk_i, 1'b1, 1'b0, lfsr1_o);wire [63:0] lfsr_o = {6'h10,lfsr1_o[26:24],4'b0,lfsr1_o[23:21],4'b0,lfsr1_o[20:18],4'b0,lfsr1_o[17:15],4'b0,lfsr1_o[14:12],4'b0,lfsr1_o[11:9],4'b0,7'h00,lfsr1_o[8:0]};wire [63:0] lfsr_o2 = {6'h10,// lfsr1_o[26:24],4'b0,lfsr1_o[23:21],4'b0,lfsr1_o[20:18],4'b0,// lfsr1_o[17:15],4'b0,lfsr1_o[14:12],4'b0,lfsr1_o[11:9],4'b0,4'b0,lfsr1_o[26:24],4'b0,lfsr1_o[23:21],lfsr1_o[20:18],4'b0,4'b0,lfsr1_o[17:15],4'b0,lfsr1_o[14:12],lfsr1_o[11:9],4'b0,7'h00,lfsr1_o[8:0]};wire [63:0] lfsr_o1 = {lfsr1_o[3:0],2'b00,// lfsr1_o[26:24],4'b0,lfsr1_o[23:21],4'b0,lfsr1_o[20:18],4'b0,// lfsr1_o[17:15],4'b0,lfsr1_o[14:12],4'b0,lfsr1_o[11:9],4'b0,4'b0,lfsr1_o[26:24],4'b0,lfsr1_o[23:21],lfsr1_o[20:18],4'b0,4'b0,lfsr1_o[17:15],lfsr1_o[14:12],4'b0,4'b0,lfsr1_o[11:9],7'h00,lfsr1_o[8:0]};/* This snippit of code for performing burst accesses, under construction.wire pe_cs;edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs_text), .pe(pe_cs), .ne(), .ee() );reg [14:0] ctr;always @(posedge clk_i)if (pe_cs) beginif (cti_i==3'b000)ctr <= adr_i[16:3];elsectr <= adr_i[16:3] + 12'd1;cnt <= 3'b000;endelse if (cs_text && cnt[2:0]!=3'b100 && cti_i!=3'b000) beginctr <= ctr + 2'd1;cnt <= cnt + 3'd1;endreg [13:0] radr;always @(posedge clk_i)radr <= pe_cs ? adr_i[16:3] : ctr;*///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// text screen RAM//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -rfTextScreenRam #(.TEXT_CELL_COUNT(TEXT_CELL_COUNT))screen_ram1(.clka_i(clk_i),.csa_i(cs_text),.wea_i(rwr_i),.sela_i(rsel_i),.adra_i(radr_i[16:3]),.data_i(rdat_i),.data_o(tdat_o),.clkb_i(vclk),.csb_i(ld_shft|por),.web_i(por),.selb_i(8'hFF),.adrb_i(txtAddr[13:0]),.datb_i(lfsr_o),//txtAddr[12:0] > 13'd1664 ? lfsr_o1 : lfsr_o),.datb_o(screen_ram_out));//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Character bitmap RAM// - room for 8160 8x8 characters//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -wire [63:0] char_bmp; // character ROM outputrfTextCharRam charRam0(.clk_i(clk_i),.cs_i(cs_rom),.we_i(rwr_i & ~font_locked),.sel_i(rsel_i),.adr_i(radr_i[15:3]),.dat_i(rdat_i[63:0]),.dat_o(chdat_o),.dot_clk_i(vclk),.ce_i(ld_shft),.fontAddress_i(fontAddress),.char_code_i(screen_ram_out[12:0]),.maxScanpix_i(maxScanpix),.maxscanline_i(maxScanlinePlusOne),.scanline_i(rowscan[5:0]),.bmp_o(char_bmp));// pipeline delay - sync color with character bitmap outputreg [20:0] txtBkCode1;reg [20:0] txtFgCode1;reg [5:0] txtZorder1;always @(posedge vclk)if (ld_shft) txtBkCode1 <= screen_ram_out[36:16];always @(posedge vclk)if (ld_shft) txtFgCode1 <= screen_ram_out[57:37];always @(posedge vclk)if (ld_shft) txtZorder1 <= screen_ram_out[63:58];//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Register read port//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -always_combif (cs_reg)rego <= rrm_o;elserego <= 64'h0000;//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Register write port//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -always_ff @(posedge clk_i)if (rst_i) beginpor <= 1'b1;mcm <= 1'b0;aam <= 1'b0;controller_enable <= 1'b1;xscroll <= 5'd0;yscroll <= 5'd0;txtTcCode <= 24'h1ff;bdrColor <= 32'hFFBF2020;startAddress <= 16'h0000;fontAddress <= 16'h0008;font_locked <= 1'b1;fontAscent <= 6'd12;cursorStart <= 5'd00;cursorEnd <= 5'd31;cursorPos <= 16'h0003;cursorType <= 3'd4; // checker// 104x63/*windowTop <= 12'd26;windowLeft <= 12'd260;pixelWidth <= 4'd0;pixelHeight <= 4'd1; // 525 pixels (408 with border)*/// 52x31/*// 84x47windowTop <= 12'd16;windowLeft <= 12'd90;pixelWidth <= 4'd1; // 681 pixelspixelHeight <= 4'd1; // 384 pixels*/// 64x32if (num==4'd1) beginwindowTop <= 12'd4058;//12'd16;windowLeft <= 12'd3918;//12'd3956;//12'd86;pixelWidth <= 4'd0; // 800 pixelspixelHeight <= 4'd0; // 600 pixelsnumCols <= COLS;numRows <= ROWS;maxRowScan <= 6'd17;maxScanpix <= 6'd11;rBlink <= 3'b111; // 01 = non displaycharOutDelay <= 8'd5;endelse if (num==4'd2) beginwindowTop <= 12'd4032;//12'd16;windowLeft <= 12'd3720;//12'd86;pixelWidth <= 4'd0; // 800 pixelspixelHeight <= 4'd0; // 600 pixelsnumCols <= 40;numRows <= 25;maxRowScan <= 5'd7;maxScanpix <= 6'd7;rBlink <= 3'b111; // 01 = non displaycharOutDelay <= 8'd6;endendelse beginif (bcnt > 6'd10)por <= 1'b0;if (cs_reg & rwr_i) begin // register write ?$display("TC Write: r%d=%h", rrm_adr, rdat_i);case(rrm_adr)4'd0: beginif (rsel_i[0]) numCols <= rdat_i[7:0];if (rsel_i[1]) numRows <= rdat_i[15:8];if (rsel_i[2]) charOutDelay <= rdat_i[23:16];if (rsel_i[4]) windowLeft[7:0] <= rdat_i[39:32];if (rsel_i[5]) windowLeft[11:8] <= rdat_i[43:40];if (rsel_i[6]) windowTop[7:0] <= rdat_i[55:48];if (rsel_i[7]) windowTop[11:8] <= rdat_i[59:56];end4'd1:beginif (rsel_i[0]) maxRowScan <= rdat_i[4:0];if (rsel_i[1]) beginpixelHeight <= rdat_i[15:12];pixelWidth <= rdat_i[11:8]; // horizontal pixel widthendif (rsel_i[2]) maxScanpix <= rdat_i[20:16];if (rsel_i[3]) por <= rdat_i[24];if (rsel_i[4]) controller_enable <= rdat_i[32];if (rsel_i[5])beginmcm <= rdat_i[40];aam <= rdat_i[41];endif (rsel_i[6]) yscroll <= rdat_i[52:48];if (rsel_i[7]) xscroll <= rdat_i[60:56];end4'd2: // Color Controlbeginif (rsel_i[0]) txtTcCode[7:0] <= rdat_i[7:0];if (rsel_i[1]) txtTcCode[15:8] <= rdat_i[15:8];if (rsel_i[2]) txtTcCode[23:16] <= rdat_i[23:16];if (rsel_i[3]) txtTcCode[30:24] <= rdat_i[30:24];if (rsel_i[4]) bdrColor[7:0] <= rdat_i[39:32];if (rsel_i[5]) bdrColor[15:8] <= rdat_i[47:40];if (rsel_i[6]) bdrColor[23:16] <= rdat_i[55:48];if (rsel_i[7]) bdrColor[31:24] <= rdat_i[63:56];end4'd3: // Color Control 2beginif (rsel_i[0]) tileColor1[7:0] <= rdat_i[7:0];if (rsel_i[1]) tileColor1[15:8] <= rdat_i[15:8];if (rsel_i[2]) tileColor1[23:16] <= rdat_i[23:16];if (rsel_i[3]) tileColor1[30:24] <= rdat_i[30:24];if (rsel_i[4]) tileColor2[7:0] <= rdat_i[39:32];if (rsel_i[5]) tileColor2[15:8] <= rdat_i[47:40];if (rsel_i[6]) tileColor2[23:16] <= rdat_i[55:48];if (rsel_i[7]) tileColor2[30:24] <= rdat_i[62:56];end4'd4: // Cursor Controlbeginif (rsel_i[0]) begincursorEnd <= rdat_i[4:0]; // scan line sursor starts onrBlink <= rdat_i[7:5];endif (rsel_i[1]) begincursorStart <= rdat_i[12:8]; // scan line cursor ends oncursorType <= rdat_i[15:13];endif (rsel_i[4]) cursorPos[7:0] <= rdat_i[39:32];if (rsel_i[5]) cursorPos[15:8] <= rdat_i[47:40];end4'd5: // Page flipping / scrollingbeginif (rsel_i[0]) startAddress[7:0] <= rdat_i[7:0];if (rsel_i[1]) startAddress[15:8] <= rdat_i[15:8];end4'd6: //beginif (rsel_i[0]) fontAddress[7:0] <= rdat_i[7:0];if (rsel_i[1]) fontAddress[15:8] <= rdat_i[15:8];if (rsel_i[3]) fontAscent[5:0] <= rdat_i[5:0];if (&rsel_i[7:4]) beginif (rdat_i[63:32]=="LOCK")font_locked <= 1'b1;else if (rdat_i[63:32]=="UNLK")font_locked <= 1'b0;endenddefault: ;endcaseendend//--------------------------------------------------------------------// Cursor image is computed based on the font size, so the available// hardware cursors are really simple. More sophisticated hardware// cursors can be had via the sprite controller.//--------------------------------------------------------------------reg [31:0] curout;wire [31:0] curout1;always_ff @(posedge vclk)if (ld_shft) begincurout = 'd0;case(cursorType)// No cursor3'd0: ;// "Box" cursor3'd1:begincase(rowscan)maxRowScan,5'd0: curout = 32'hFFFFFFFF;/*maxRowScan-1:if (rowscan==maxRowScan-1) begincurout[maxScanpix[5:1]] = 1'b1;curout[maxScanpix[5:1]+1] = 1'b1;end*/default:begincurout[maxScanpix] = 1'b1;curout[0] = 1'b1;endendcaseend// Vertical Line cursor3'd2: curout[maxScanpix] = 1'b1;// Underline cursor3'd3:if (rowscan==fontAscent)curout = 32'hFFFFFFFF;// Checker cursor3'd4: curout = rowscan[1] ? 32'h33333333 : 32'hCCCCCCCC;// Solid cursor3'd7: curout = 32'hFFFFFFFF;default: curout = 32'hFFFFFFFF;endcaseendft_delay#(.WID(32),.DEP(3))uftd1(.clk(vclk),.ce(ld_shft),.i(curout),.o(curout1));//-------------------------------------------------------------// Video Stuff//-------------------------------------------------------------wire pe_hsync;wire pe_vsync;edge_det edh1(.rst(rst_i),.clk(vclk),.ce(1'b1),.i(hsync_i),.pe(pe_hsync),.ne(),.ee());edge_det edv1(.rst(rst_i),.clk(vclk),.ce(1'b1),.i(vsync_i),.pe(pe_vsync),.ne(),.ee());// We generally don't care about the exact reset point, unless debugging in// simulation. The counters will eventually cycle to a proper state. A little// bit of logic / routing can be avoided by omitting the reset.`ifdef SIMwire sym_rst = rst_i;`elsewire sym_rst = 1'b0;`endif// Raw scanline countervid_counter #(12) u_vctr (.rst(sym_rst), .clk(vclk), .ce(pe_hsync), .ld(pe_vsync), .d(windowTop), .q(scanline), .tc());vid_counter #(12) u_hctr (.rst(sym_rst), .clk(vclk), .ce(1'b1), .ld(pe_hsync), .d(windowLeft), .q(hctr), .tc());// Vertical pixel height counter, synchronized to scanline #0reg [3:0] vpx;wire nvp = vpx==pixelHeight;always @(posedge vclk)if (sym_rst)vpx <= 4'b0;else beginif (pe_hsync) beginif (scanline==12'd0)vpx <= 4'b0;else if (nvp)vpx <= 4'd0;elsevpx <= vpx + 4'd1;endendreg [3:0] hpx;assign nhp = hpx==pixelWidth;always @(posedge vclk)if (sym_rst)hpx <= 4'b0;else beginif (hctr==12'd0)hpx <= 4'b0;else if (nhp)hpx <= 4'd0;elsehpx <= hpx + 4'd1;end// The scanline row within a character bitmapalways @(posedge vclk)if (sym_rst)rowscan <= 5'd0;else beginif (pe_hsync & nvp) beginif (scanline==12'd0)rowscan <= yscroll;else if (rowscan==maxRowScan)rowscan <= 5'd0;elserowscan <= rowscan + 5'd1;endendassign nxt_col = colscan==maxScanpix;always @(posedge vclk)if (sym_rst)colscan <= 5'd0;else beginif (nhp) beginif (hctr==12'd0)colscan <= xscroll;else if (nxt_col)colscan <= 5'd0;elsecolscan <= colscan + 5'd1;endend// The screen rowalways @(posedge vclk)if (sym_rst)row <= 8'd0;else beginif (pe_hsync & nvp) beginif (scanline==12'd0)row <= 8'd0;else if (rowscan==maxRowScan)row <= row + 8'd1;endend// The screen columnalways @(posedge vclk)if (sym_rst)col <= 8'd0;else beginif (hctr==12'd0)col <= 8'd0;else if (nhp) beginif (nxt_col)col <= col + 8'd1;endend// More useful, the offset of the start of the text display on a line.always @(posedge vclk)if (sym_rst)rowcol <= 16'd0;else beginif (pe_hsync & nvp) beginif (scanline==12'd0)rowcol <= 8'd0;else if (rowscan==maxRowScan)rowcol <= rowcol + numCols;endend// Takes 3 clock for scanline to become stable, but should be stable before any// chars are displayed.reg [13:0] rxmslp1;always_ff @(posedge vclk)maxScanlinePlusOne <= maxRowScan + 4'd1;// Blink counter//always_ff @(posedge vclk)if (sym_rst)bcnt <= 6'd0;else beginif (pe_vsync)bcnt <= bcnt + 6'd1;endreg blink_en;always_ff @(posedge vclk)blink_en <= (cursorPos+charOutDelay-2'd1==txtAddr);// && (rowscan[4:0] >= cursorStart) && (rowscan[4:0] <= cursorEnd);VT151 ub2(.e_n(!blink_en),.s(rBlink),.i0(1'b1), .i1(1'b0), .i2(bcnt[4]), .i3(bcnt[5]),.i4(1'b1), .i5(1'b0), .i6(bcnt[4]), .i7(bcnt[5]),.z(blink),.z_n());always_ff @(posedge vclk)if (ld_shft)bkColor40 <= {txtZorder1[5:2],txtBkCode1[20:14],5'b0,txtBkCode1[13:7],5'b0,txtBkCode1[6:0],5'b0};always_ff @(posedge vclk)if (ld_shft)bkColor40d <= bkColor40;always_ff @(posedge vclk)if (ld_shft)bkColor40d2 <= bkColor40d;always_ff @(posedge vclk)if (nhp)bkColor40d3 <= bkColor40d2;always_ff @(posedge vclk)if (ld_shft)fgColor40 <= {txtZorder1[5:2],txtFgCode1[20:14],5'b0,txtFgCode1[13:7],5'b0,txtFgCode1[6:0],5'b0};always_ff @(posedge vclk)if (ld_shft)fgColor40d <= fgColor40;always_ff @(posedge vclk)if (ld_shft)fgColor40d2 <= fgColor40d;always_ff @(posedge vclk)if (nhp)fgColor40d3 <= fgColor40d2;always_ff @(posedge vclk)if (ld_shft)bgt <= txtBkCode1=={txtTcCode[26:20],txtTcCode[17:11],txtTcCode[8:2]};always_ff @(posedge vclk)if (ld_shft)bgtd <= bgt;always_ff @(posedge vclk)if (nhp)bgtd2 <= bgtd;// Convert character bitmap to pixelsreg [63:0] charout1;always_ff @(posedge vclk)charout1 <= blink ? (char_bmp ^ curout1) : char_bmp;// Convert parallel to serialrfTextShiftRegister ups1(.rst(rst_i),.clk(vclk),.mcm(mcm),// .aam(aam),.ce(nhp),.ld(ld_shft),.a(maxScanpix[5:0]),.qin(2'b0),.d(charout1),.qh(pix));// Pipelining Effect:// - character output is delayed by 2 or 3 character times relative to the video counters// depending on the resolution selected// - this means we must adapt the blanking signal by shifting the blanking window// two or three character times.wire bpix = hctr[2] ^ rowscan[4];// ^ blink;always_ff @(posedge vclk)if (nhp)iblank <= (row >= numRows) || (col >= numCols + charOutDelay) || (col < charOutDelay);`ifdef SUPPORT_AAMfunction [11:0] fnBlendComponent;input [11:0] c1;input [11:0] c2;input [1:0] pix;case(pix)2'b00: fnBlendComponent = c2;2'b01: fnBlendComponent = ((c1 * 4'd5) + (c2 * 4'd11)) >> 4;2'b10: fnBlendComponent = ((c1 * 4'd11) + (c2 * 4'd5)) >> 4;2'b11: fnBlendComponent = c1;endcaseendfunctionfunction [39:0] fnBlend;input [39:0] c1;input [39:0] c2;input [1:0] pix;fnBlend = {|pix ? c1[39:36] : c2[39:36],fnBlendComponent(c1[35:24],c2[35:24]),fnBlendComponent(c1[23:12],c2[23:12]),fnBlendComponent(c1[11: 0],c2[11: 0])};endfunction`endif// Choose between input RGB and controller generated RGB// Select between foreground and background colours.// Note the ungated dot clock must be used here, or output from other// controllers would not be visible if the clock were gated off.always_ff @(posedge dot_clk_i)casez({controller_enable&xonoff_i,blank_i,iblank,border_i,bpix,mcm,aam,pix})9'b01???????: zrgb_o <= 40'h00000000;9'b11???????: zrgb_o <= 40'h00000000;9'b1001?????: zrgb_o <= {bdrColor[30:27],bdrColor[26:18],3'b0,bdrColor[17:9],3'b0,bdrColor[8:0],3'b0};`ifdef SUPPORT_AAM9'b1000?01??: zrgb_o <= fnBlend(fgColor40d3,zrgb_i[39:36] > bkColor40d3[39:36]) ? zrgb_i : bkColor40d3, pix);`endif9'b1000?000?: zrgb_o <= (zrgb_i[39:36] > bkColor40d3[39:36]) ? zrgb_i : bkColor40d3;9'b1000?001?: zrgb_o <= fgColor40d3; // ToDo: compare z-order9'b1000?1000: zrgb_o <= (zrgb_i[39:36] > bkColor40d3[39:36]) ? zrgb_i : bkColor40d3;9'b1000?1001: zrgb_o <= fgColor40d3;9'b1000?1010: zrgb_o <= {tileColor1[30:27],tileColor1[26:18],3'b0,tileColor1[17:9],3'b0,tileColor1[8:0],3'b0};9'b1000?1011: zrgb_o <= {tileColor2[30:27],tileColor2[26:18],3'b0,tileColor2[17:9],3'b0,tileColor2[8:0],3'b0};// 6'b1010?0: zrgb_o <= bgtd ? zrgb_i : bkColor32d;default: zrgb_o <= zrgb_i;endcaseendmodule
