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

Subversion Repositories rtf68ksys

[/] [rtf68ksys/] [trunk/] [rtl/] [verilog/] [rtfTextController.v] - Rev 2

Compare with Previous | Blame | View Log

// ============================================================================
//	(C) 2006-2011  Robert Finch
//	robfinch@<remove>opencores.org
//
//	rtfTextController.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 -         ---nnnnn  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 rtfTextController(
	rst_i, clk_i,
	cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_o,
	lp, curpos,
	vclk, eol, eof, blank, border, rgbIn, rgbOut
);
parameter COLS = 12'd52;
parameter ROWS = 12'd31;
 
// 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  [ 1:0] sel_i;	// byte select
input  [31:0] adr_i;	// address
input  [15:0] dat_i;	// data input
output [15:0] dat_o;	// data output
reg    [15:0] dat_o;
 
//
input lp;				// light pen
input [15:0] curpos;	// cursor position
 
// Video signals
input vclk;				// video dot clock
input eol;				// end of scan line
input eof;				// 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
 
 
wire [23:0] bkColor24;	// background color
wire [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 [ 1:0] mode;
reg [ 4:0] maxScanline;
reg [ 4:0] maxScanpix;
reg [ 4:0] cursorStart, cursorEnd;
reg [15:0] cursorPos;
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 [7:0] charOut;		// character ROM output
wire [3:0] txtBkCode;	// background color code
wire [4:0] txtFgCode;	// foreground color code
reg  [4:0] txtTcCode;	// transparent color code
reg  bgt;
 
wire [8:0] tdat_o;
wire [8:0] cdat_o;
wire [7:0] chdat_o;
 
wire [2:0] scanindex = scanline[2:0];
 
 
//--------------------------------------------------------------------
// Address Decoding
// I/O range FFDx
//--------------------------------------------------------------------
wire cs_text = cyc_i && stb_i && (adr_i[31:16]==16'hFFD0);
wire cs_color= cyc_i && stb_i && (adr_i[31:16]==16'hFFD1);
wire cs_rom  = cyc_i && stb_i && (adr_i[31:16]==16'hFFD2);
wire cs_reg  = cyc_i && stb_i && (adr_i[31: 8]==24'hFFDA_00);
 
 
always @(cs_text or cs_color or cs_rom or cs_reg or tdat_o or cdat_o or chdat_o or rego)
	if (cs_text) dat_o <= tdat_o;
	else if (cs_color) dat_o <= cdat_o;
	else if (cs_rom) dat_o <= chdat_o;
	else if (cs_reg) dat_o <= rego;
	else dat_o <= 16'h0000;
 
 
//--------------------------------------------------------------------
// Video Memory
//--------------------------------------------------------------------
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Address Calculation:
//  - Simple: the row times the number of  cols plus the col plue the
//    base screen address
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
wire [17:0] rowcol = row * numCols;
always @(posedge vclk)
	txtAddr <= startAddress + rowcol + col;
 
// text screen RAM
syncRam4kx9_1rw1r textRam0
(
	.wclk(clk_i),
	.wadr(adr_i[13:1]),
	.i(dat_i),
	.wo(tdat_o),
	.wce(cs_text),
	.we(we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr(txtAddr[12:0]),
	.o(txtOut),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
// screen attribute RAM
syncRam4kx9_1rw1r colorRam0
(
	.wclk(clk_i),
	.wadr(adr_i[13:1]),
	.i(dat_i),
	.wo(cdat_o),
	.wce(cs_color),
	.we(we_i),
	.wrst(1'b0),
 
	.rclk(vclk),
	.radr(txtAddr[12:0]),
	.o({txtBkCode,txtFgCode}),
	.rce(ld_shft),
	.rrst(1'b0)
);
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Character bitmap ROM
// - room for 512 characters
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
syncRam4kx9_1rw1r charRam0
(
	.wclk(clk_i),
	.wadr(adr_i[11:0]),
	.i(dat_i),
	.wo(chdat_o),
	.wce(cs_rom),
	.we(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 [3:0] txtBkCode1;
reg [4:0] txtFgCode1;
always @(posedge vclk)
	if (nhp & ld_shft) txtBkCode1 <= txtBkCode;
always @(posedge vclk)
	if (nhp & ld_shft) txtFgCode1 <= txtFgCode;
 
//--------------------------------------------------------------------
// bus interfacing
// - there is a one cycle latency for reads, an ack is generated
//   after the synchronous RAM read
// - writes can be acknowledged right away.
//--------------------------------------------------------------------
reg ramRdy;
always @(posedge clk_i)
	ramRdy = cs_text|cs_rom|cs_color|cs_reg;
 
assign ack_o = (cyc_i & stb_i) ? (we_i ? (cs_text|cs_color|cs_rom|cs_reg) : ramRdy) : 1'b0;
 
 
//--------------------------------------------------------------------
// 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
//      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
//--------------------------------------------------------------------
 
//--------------------------------------------------------------------
// 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)
	if (cs_reg) begin
		case(adr_i[4:1])
		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
		windowTop    <= 12'd14;
		windowLeft   <= 12'd117;
		pixelWidth   <= 4'd1;
		pixelHeight  <= 4'd3;		// 262 pixels (248 with border)
 
		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;
		txtTcCode    <= 5'd31;
	end
	else begin
 
		if (cs_reg & we_i) begin	// register write ?
 
			case(adr_i[4:1])
			4'd00:	numCols    <= dat_i;		// horizontal displayed
			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[4:0];
			4'd08:	begin
					cursorStart <= dat_i[4:0];	// scan line sursor starts on
					rBlink      <= dat_i[7:5];
					end
			4'd09:	cursorEnd   <= dat_i[4:0];	// scan line cursor ends on
			4'd10:	startAddress <= dat_i;
			4'd11:	cursorPos <= dat_i;
			endcase
		end
	end
 
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
 
// "Box" cursor bitmap
reg [7:0] curout;
always @(scanindex)
	case(scanindex)
	3'd0:	curout = 8'b11111111;
	3'd1:	curout = 8'b10000001;
	3'd2:	curout = 8'b10000001;
	3'd3:	curout = 8'b10000001;
	3'd4:	curout = 8'b10000001;
	3'd5:	curout = 8'b10000001;
	3'd6:	curout = 8'b10011001;
	3'd7:	curout = 8'b11111111;
	endcase
 
 
//-------------------------------------------------------------
// Video Stuff
//-------------------------------------------------------------
 
// Horizontal counter:
//
 
HVCounter uhv1
(
	.rst(rst_i),
	.vclk(vclk),
	.pixcce(1'b1),
	.sync(eol),
	.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(eol),
	.sync(eof),
	.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(eol & eof),
	.enp(1'b1),
	.ld_n(1'b1),
	.d(6'd0),
	.q(bcnt)
);
 
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()
);
 
// These tables map a five bit color code to an eight bit color value.
rtfColorROM ucm1 (.clk(vclk), .ce(nhp & ld_shft), .code(txtBkCode1),  .color(bkColor24) );
rtfColorROM ucm2 (.clk(vclk), .ce(nhp & ld_shft), .code(txtFgCode1),  .color(fgColor24) );
always @(posedge vclk)
	if (nhp & ld_shft)
		bgt <= {1'b0,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 3 character times relative to the video counters.
// - this means we must adapt the blanking signal by shifting the blanking window
//   three character times.
wire bpix = hctr[1] ^ scanline[4];// ^ blink;
always @(posedge vclk)
	if (nhp)	
		iblank <= (row >= numRows) || (col >= numCols + 3) || (col < 3);
 
 
// 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
 
 

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.