OpenCores
URL https://opencores.org/ocsvn/rtftextcontroller/rtftextcontroller/trunk

Subversion Repositories rtftextcontroller

[/] [rtftextcontroller/] [trunk/] [rtl/] [verilog/] [rtfTextController3.v] - Rev 26

Go to most recent revision | Compare with Previous | Blame | View Log

`timescale 1ns / 1ps
// ============================================================================
//        __
//   \\__/ o\    (C) 2006-2014  Robert Finch, Stratford
//    \  __ /    All rights reserved.
//     \/_//     robfinch<remove>@finitron.ca
//       ||
//
//	rtfTextController3.v
//		text controller
//
// This source file is free software: you can redistribute it and/or modify 
// it under the terms of the GNU Lesser General Public License as published 
// by the Free Software Foundation, either version 3 of the License, or     
// (at your option) any later version.                                      
//                                                                          
// This source file is distributed in the hope that it will be useful,      
// but WITHOUT ANY WARRANTY; without even the implied warranty of           
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            
// GNU General Public License for more details.                             
//                                                                          
// You should have received a copy of the GNU General Public License        
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    
//                                                                          
//
//	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.
//
//
//--------------------------------------------------------------------
// Registers
//
//      00 -         nnnnnnnn  number of columns (horizontal displayed number of characters)
//      01 -         nnnnnnnn  number of rows    (vertical displayed number of characters)
//      02 -       n nnnnnnnn  window left       (horizontal sync position - reference for left edge of displayed)
//      03 -       n nnnnnnnn  window top        (vertical sync position - reference for the top edge of displayed)
//      04 -         ---nnnnn  maximum scan line (char ROM max value is 7)
//		05 -         hhhhwwww  pixel size, hhhh=height,wwww=width
//      07 -       n nnnnnnnn  color code for transparent background
//      08 -         -BPnnnnn  cursor start / blink control
//                             BP: 00=no blink
//                             BP: 01=no display
//                             BP: 10=1/16 field rate blink
//                             BP: 11=1/32 field rate blink
//      09 -        ----nnnnn  cursor end
//      10 - aaaaaaaa aaaaaaaaa  start address (index into display memory)
//      11 - aaaaaaaa aaaaaaaaa  cursor position
//      12 - aaaaaaaa aaaaaaaaa  light pen position
//--------------------------------------------------------------------
//
// ============================================================================
 
module rtfTextController3(
	rst_i, clk_i,
	cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o,
	lp, curpos,
	vclk, hsync, vsync, blank, border, rgbIn, rgbOut
);
parameter num = 4'd1;
parameter COLS = 12'd84;
parameter ROWS = 12'd31;
parameter pTextAddress = 32'hFFD00000;
parameter pBitmapAddress = 32'hFFD20000;
parameter pRegAddress = 32'hFFDA0000;
 
// Syscon
input  rst_i;			// reset
input  clk_i;			// clock
 
// Slave signals
input  cyc_i;			// cycle valid
input  stb_i;			// data strobe
output ack_o;			// transfer acknowledge
input  we_i;			// write
input  [31:0] adr_i;	// address
input  [31:0] dat_i;	// data input
output [31:0] dat_o;	// data output
reg    [31:0] dat_o;
 
//
input lp;				// light pen
input [15:0] curpos;	// cursor position
 
// Video signals
input vclk;				// video dot clock
input hsync;			// end of scan line
input vsync;			// end of frame
input blank;			// blanking signal
input border;			// border area
input [24:0] rgbIn;		// input pixel stream
output reg [24:0] rgbOut;	// output pixel stream
 
 
reg [23:0] bkColor24;	// background color
reg [23:0] fgColor24;	// foreground color
wire [23:0] tcColor24;	// transparent color
 
wire pix;				// pixel value from character generator 1=on,0=off
 
reg [15:0] rego;
reg [11:0] windowTop;
reg [11:0] windowLeft;
reg [11:0] numCols;
reg [11:0] numRows;
reg [11:0] charOutDelay;
reg [ 1:0] mode;
reg [ 4:0] maxScanline;
reg [ 4:0] maxScanpix;
reg [ 4:0] cursorStart, cursorEnd;
reg [15:0] cursorPos;
reg [1:0] cursorType;
reg [15:0] startAddress;
reg [ 2:0] rBlink;
reg [ 3:0] bdrColorReg;
reg [ 3:0] pixelWidth;	// horizontal pixel width in clock cycles
reg [ 3:0] pixelHeight;	// vertical pixel height in scan lines
 
wire [11:0] hctr;		// horizontal reference counter (counts clocks since hSync)
wire [11:0] scanline;	// scan line
wire [11:0] row;		// vertical reference counter (counts rows since vSync)
wire [11:0] col;		// horizontal column
reg  [ 4:0] rowscan;	// scan line within row
wire nxt_row;			// when to increment the row counter
wire nxt_col;			// when to increment the column counter
wire [ 5:0] bcnt;		// blink timing counter
wire blink;
reg  iblank;
 
wire nhp;				// next horizontal pixel
wire ld_shft = nxt_col & nhp;
 
 
// display and timing signals
reg [15:0] txtAddr;		// index into memory
reg [15:0] penAddr;
wire [8:0] txtOut;		// character code
wire [8:0] charOut;		// character ROM output
wire [8:0] txtBkColor;	// background color code
wire [8:0] txtFgColor;	// foreground color code
reg  [8:0] txtTcCode;	// transparent color code
reg  bgt;
 
wire [27:0] tdat_o;
wire [8:0] chdat_o;
 
wire [2:0] scanindex = scanline[2:0];
 
 
//--------------------------------------------------------------------
// Address Decoding
// I/O range Dx
//--------------------------------------------------------------------
wire cs_text = cyc_i && stb_i && (adr_i[31:16]==pTextAddress[31:16]);
wire cs_rom  = cyc_i && stb_i && (adr_i[31:16]==pBitmapAddress[31:16]);
wire cs_reg  = cyc_i && stb_i && (adr_i[31: 6]==pRegAddress[31:6]);
wire cs_any = cs_text|cs_rom|cs_reg;
 assign tdat_o[9] = 1'b0;
 
// Register outputs
always @(posedge clk_i)
	if (cs_text) dat_o <= {4'd0,tdat_o};
	else if (cs_rom) dat_o <= {23'd0,chdat_o};
	else if (cs_reg) dat_o <= {16'd0,rego};
	else dat_o <= 32'h0000;
 
//always @(posedge clk_i)
//	if (cs_text) begin
//		$display("TC WRite: %h %h", adr_i, dat_i);
//		$stop;
//	end
 
//--------------------------------------------------------------------
// Video Memory
//--------------------------------------------------------------------
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Address Calculation:
//  - Simple: the row times the number of  cols plus the col plus the
//    base screen address
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
wire [17:0] rowcol = row * numCols;
always @(posedge vclk)
	txtAddr <= startAddress + rowcol[15:0] + col;
 
// text screen RAM
syncRam4kx9_1rw1r textRam0
(
	.wclk(clk_i),
	.wadr(adr_i[13:2]),
	.i(dat_i[8:0]),
	.wo(tdat_o[8:0]),
	.wce(cs_text),
	.we(we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr(txtAddr[11:0]),
	.o(txtOut),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
// screen attribute RAM
syncRam4kx9_1rw1r fgColorRam
(
	.wclk(clk_i),
	.wadr(adr_i[13:2]),
	.i(dat_i[18:10]),
	.wo(tdat_o[18:10]),
	.wce(cs_text),
	.we(we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr(txtAddr[11:0]),
	.o(txtFgColor),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
// screen attribute RAM
syncRam4kx9_1rw1r bkColorRam
(
	.wclk(clk_i),
	.wadr(adr_i[13:2]),
	.i(dat_i[27:19]),
	.wo(tdat_o[27:19]),
	.wce(cs_text),
	.we(we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr(txtAddr[11:0]),
	.o(txtBkColor),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Character bitmap ROM
// - room for 512 characters
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
syncRam4kx9_1rw1r charRam0
(
	.wclk(clk_i),
	.wadr(adr_i[13:2]),
	.i(dat_i),
	.wo(chdat_o),
	.wce(cs_rom),
	.we(1'b0),//we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr({txtOut,rowscan[2:0]}),
	.o(charOut),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
 
// pipeline delay - sync color with character bitmap output
reg [8:0] txtBkCode1;
reg [8:0] txtFgCode1;
always @(posedge vclk)
	if (nhp & ld_shft) txtBkCode1 <= txtBkColor;
always @(posedge vclk)
	if (nhp & ld_shft) txtFgCode1 <= txtFgColor;
 
//--------------------------------------------------------------------
// bus interfacing
// - there is a two cycle latency for reads, an ack is generated
//   after the synchronous RAM read
// - writes can be acknowledged right away.
//--------------------------------------------------------------------
reg ramRdy,ramRdy1;
always @(posedge clk_i)
begin
	ramRdy1 <= cs_any;
	ramRdy <= ramRdy1 & cs_any;
end
 
assign ack_o = cs_any ? (we_i ? 1'b1 : ramRdy) : 1'b0;
 
 
//--------------------------------------------------------------------
// Registers
//
// RW   00 -         nnnnnnnn  number of columns (horizontal displayed number of characters)
// RW   01 -         nnnnnnnn  number of rows    (vertical displayed number of characters)
//  W   02 -       n nnnnnnnn  window left       (horizontal sync position - reference for left edge of displayed)
//  W   03 -       n nnnnnnnn  window top        (vertical sync position - reference for the top edge of displayed)
//  W   04 -         ---nnnnn  maximum scan line (char ROM max value is 7)
//	W	05 -         hhhhwwww  pixel size, hhhh=height,wwww=width
//  W   07 -       n nnnnnnnn  transparent color
//  W   08 -         -BPnnnnn  cursor start / blink control
//                             BP: 00=no blink
//                             BP: 01=no display
//                             BP: 10=1/16 field rate blink
//                             BP: 11=1/32 field rate blink
//  W   09 -        ----nnnnn  cursor end
//  W   10 - aaaaaaaa aaaaaaaaa  start address (index into display memory)
//  W   11 - aaaaaaaa aaaaaaaaa  cursor position
//  R   12 - aaaaaaaa aaaaaaaaa  light pen position
//--------------------------------------------------------------------
 
//--------------------------------------------------------------------
// Light Pen
//--------------------------------------------------------------------
wire lpe;
edge_det u1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(lp), .pe(lpe), .ne(), .ee() );
 
always @(posedge clk_i)
	if (rst_i)
		penAddr <= 32'h0000_0000;
	else begin
		if (lpe)
			penAddr <= txtAddr;
	end
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Register read port
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
always @(cs_reg or cursorPos or penAddr or adr_i or numCols or numRows)
	if (cs_reg) begin
		case(adr_i[5:2])
		4'd0:		rego <= numCols;
		4'd1:		rego <= numRows;
		4'd11:		rego <= cursorPos;
		4'd12:		rego <= penAddr;
		default:	rego <= 16'h0000;
		endcase
	end
	else
		rego <= 16'h0000;
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Register write port
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
reg interlace;
always @(posedge clk_i)
	if (rst_i) begin
// 104x63
/*
		windowTop    <= 12'd26;
		windowLeft   <= 12'd260;
		pixelWidth   <= 4'd0;
		pixelHeight  <= 4'd1;		// 525 pixels (408 with border)
*/
// 52x31
/*
		// 84x47
		windowTop    <= 12'd16;
		windowLeft   <= 12'd90;
		pixelWidth   <= 4'd1;		// 681 pixels
		pixelHeight  <= 4'd1;		// 384 pixels
*/
		// 56x31
		if (num==4'd1) begin
            windowTop    <= 12'd16;//12'd16;
            windowLeft   <= 12'h66;//12'd86;
            pixelWidth   <= 4'd1;		// 680 pixels
            pixelHeight  <= 4'd2;		// 256 pixels
            numCols      <= COLS;
            numRows      <= ROWS;
            maxScanline  <= 5'd7;
            maxScanpix   <= 5'd7;
            rBlink       <= 3'b111;		// 01 = non display
            startAddress <= 16'h0000;
            cursorStart  <= 5'd00;
            cursorEnd    <= 5'd31;
            cursorPos    <= 16'h0003;
            cursorType 	 <= 2'b00;
            txtTcCode    <= 9'h1ff;
            charOutDelay <= 12'd2;
		end
		else if (num==4'd2) begin
            windowTop    <= 12'd64;//12'd16;
            windowLeft   <= 12'h376;//12'd86;
            pixelWidth   <= 4'd0;        // 680 pixels
            pixelHeight  <= 4'd1;        // 256 pixels
            numCols      <= 40;
            numRows      <= 25;
            maxScanline  <= 5'd7;
            maxScanpix   <= 5'd7;
            rBlink       <= 3'b111;        // 01 = non display
            startAddress <= 16'h0000;
            cursorStart  <= 5'd00;
            cursorEnd    <= 5'd31;
            cursorPos    <= 16'h0003;
            cursorType   <= 2'b00;
            txtTcCode    <= 9'h1ff;
            charOutDelay <= 12'd2;
		end
	end
	else begin
 
		if (cs_reg & we_i) begin	// register write ?
			$display("TC Write: r%d=%h", adr_i[5:2], dat_i);
			case(adr_i[5:2])
			4'd00:	begin
					numCols    <= dat_i[15:0];		// horizontal displayed
					charOutDelay <= dat_i[31:16];
					end
			4'd01:	numRows    <= dat_i;
			4'd02:	windowLeft <= dat_i[11:0];
			4'd03:	windowTop  <= dat_i[11:0];		// vertical sync position
			4'd04:	maxScanline <= dat_i[4:0];
			4'd05:	begin
					pixelHeight <= dat_i[7:4];
					pixelWidth  <= dat_i[3:0];	// horizontal pixel width
					end
			4'd07:	txtTcCode   <= dat_i[8:0];
			4'd08:	begin
					cursorStart <= dat_i[4:0];	// scan line sursor starts on
					rBlink      <= dat_i[7:5];
					cursorType  <= dat_i[9:8];
					end
			4'd09:	cursorEnd   <= dat_i[4:0];	// scan line cursor ends on
			4'd10:	startAddress <= dat_i;
			4'd11:	cursorPos <= dat_i[15:0];
			default: ;
			endcase
		end
	end
 
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
 
// "Box" cursor bitmap
reg [7:0] curout;
always @(scanindex or cursorType)
	case({cursorType,scanindex})
	// Box cursor
	5'b00_000:	curout = 8'b11111111;
	5'b00_001:	curout = 8'b10000001;
	5'b00_010:	curout = 8'b10000001;
	5'b00_011:	curout = 8'b10000001;
	5'b00_100:	curout = 8'b10000001;
	5'b00_101:	curout = 8'b10000001;
	5'b00_110:	curout = 8'b10011001;
	5'b00_111:	curout = 8'b11111111;
	// vertical bar cursor
	5'b01_000:	curout = 8'b11000000;
	5'b01_001:	curout = 8'b10000000;
	5'b01_010:	curout = 8'b10000000;
	5'b01_011:	curout = 8'b10000000;
	5'b01_100:	curout = 8'b10000000;
	5'b01_101:	curout = 8'b10000000;
	5'b01_110:	curout = 8'b10000000;
	5'b01_111:	curout = 8'b11000000;
	// underline cursor
	5'b10_000:	curout = 8'b00000000;
	5'b10_001:	curout = 8'b00000000;
	5'b10_010:	curout = 8'b00000000;
	5'b10_011:	curout = 8'b00000000;
	5'b10_100:	curout = 8'b00000000;
	5'b10_101:	curout = 8'b00000000;
	5'b10_110:	curout = 8'b00000000;
	5'b10_111:	curout = 8'b11111111;
	// Asterisk
	5'b11_000:	curout = 8'b00000000;
	5'b11_001:	curout = 8'b00000000;
	5'b11_010:	curout = 8'b00100100;
	5'b11_011:	curout = 8'b00011000;
	5'b11_100:	curout = 8'b01111110;
	5'b11_101:	curout = 8'b00011000;
	5'b11_110:	curout = 8'b00100100;
	5'b11_111:	curout = 8'b00000000;
	endcase
 
 
//-------------------------------------------------------------
// Video Stuff
//-------------------------------------------------------------
 
wire pe_hsync;
wire pe_vsync;
edge_det edh1
(
	.rst(rst_i),
	.clk(vclk),
	.ce(1'b1),
	.i(hsync),
	.pe(pe_hsync),
	.ne(),
	.ee()
);
 
edge_det edv1
(
	.rst(rst_i),
	.clk(vclk),
	.ce(1'b1),
	.i(vsync),
	.pe(pe_vsync),
	.ne(),
	.ee()
);
 
// Horizontal counter:
//
HVCounter uhv1
(
	.rst(rst_i),
	.vclk(vclk),
	.pixcce(1'b1),
	.sync(hsync),
	.cnt_offs(windowLeft),
	.pixsz(pixelWidth),
	.maxpix(maxScanpix),
	.nxt_pix(nhp),
	.pos(col),
	.nxt_pos(nxt_col),
	.ctr(hctr)
);
 
 
// Vertical counter:
//
HVCounter uhv2
(
	.rst(rst_i),
	.vclk(vclk),
	.pixcce(pe_hsync),
	.sync(vsync),
	.cnt_offs(windowTop),
	.pixsz(pixelHeight),
	.maxpix(maxScanline),
	.nxt_pix(nvp),
	.pos(row),
	.nxt_pos(nxt_row),
	.ctr(scanline)
);
 
always @(posedge vclk)
	rowscan <= scanline - row * (maxScanline+1);
 
 
// Blink counter
//
VT163 #(6) ub1
(
	.clk(vclk),
	.clr_n(!rst_i),
	.ent(pe_vsync),
	.enp(1'b1),
	.ld_n(1'b1),
	.d(6'd0),
	.q(bcnt),
	.rco()
);
 
wire blink_en = (cursorPos+2==txtAddr) && (scanline[4:0] >= cursorStart) && (scanline[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 @(posedge vclk)
	if (nhp & ld_shft)
		bkColor24 <= {txtBkCode1[8:6],5'h10,txtBkCode1[5:3],5'h10,txtBkCode1[2:0],5'h10};
always @(posedge vclk)
	if (nhp & ld_shft)
		fgColor24 <= {txtFgCode1[8:6],5'h10,txtFgCode1[5:3],5'h10,txtFgCode1[2:0],5'h10};
 
always @(posedge vclk)
	if (nhp & ld_shft)
		bgt <= txtBkCode1==txtTcCode;
 
 
// Convert character bitmap to pixels
// For convenience, the character bitmap data in the ROM is in the
// opposite bit order to what's needed for the display. The following
// just alters the order without adding any hardware.
//
wire [7:0] charRev = {
	charOut[0],
	charOut[1],
	charOut[2],
	charOut[3],
	charOut[4],
	charOut[5],
	charOut[6],
	charOut[7]
};
 
wire [7:0] charout1 = blink ? (charRev ^ curout) : charRev;
 
// Convert parallel to serial
ParallelToSerial ups1
(
	.rst(rst_i),
	.clk(vclk),
	.ce(nhp),
	.ld(ld_shft),
	.qin(1'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[1] ^ scanline[4];// ^ blink;
always @(posedge vclk)
	if (nhp)	
		iblank <= (row >= numRows) || (col >= numCols + charOutDelay) || (col < charOutDelay);
 
 
// Choose between input RGB and controller generated RGB
// Select between foreground and background colours.
always @(posedge vclk)
	if (nhp) begin
		casex({blank,iblank,border,bpix,pix})
		5'b1xxxx:	rgbOut <= 25'h0000000;
		5'b01xxx:	rgbOut <= rgbIn;
		5'b0010x:	rgbOut <= 24'hBF2020;
		5'b0011x:	rgbOut <= 24'hDFDFDF;
		5'b000x0:	rgbOut <= bgt ? rgbIn : bkColor24;
		5'b000x1:	rgbOut <= fgColor24;
		default:	rgbOut <= rgbIn;
		endcase
	end
 
endmodule
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.