// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2006-2020 Robert Finch, Waterloo
|
// \\__/ o\ (C) 2006-2020 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch@finitron.ca
|
// \/_// robfinch@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
// GFX_TextController.sv
|
// GFX_TextController.sv
|
// text controller
|
// text controller
|
//
|
//
|
// BSD 3-Clause License
|
// BSD 3-Clause License
|
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
// modification, are permitted provided that the following conditions are met:
|
// modification, are permitted provided that the following conditions are met:
|
//
|
//
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
// list of conditions and the following disclaimer.
|
// list of conditions and the following disclaimer.
|
//
|
//
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
// this list of conditions and the following disclaimer in the documentation
|
// this list of conditions and the following disclaimer in the documentation
|
// and/or other materials provided with the distribution.
|
// and/or other materials provided with the distribution.
|
//
|
//
|
// 3. Neither the name of the copyright holder nor the names of its
|
// 3. Neither the name of the copyright holder nor the names of its
|
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
//
|
//
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
// 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
|
// 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.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
//
|
//
|
//
|
//
|
// Text Controller
|
// Text Controller
|
//
|
//
|
// FEATURES
|
// FEATURES
|
//
|
//
|
// This core requires an external timing generator to provide horizontal
|
// This core requires an external timing generator to provide horizontal
|
// and vertical sync signals, but otherwise can be used as a display
|
// 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
|
// controller on it's own. However, this core may also be embedded within
|
// another core such as a VGA controller.
|
// another core such as a VGA controller.
|
//
|
//
|
// Window positions are referenced to the rising edge of the vertical and
|
// Window positions are referenced to the rising edge of the vertical and
|
// horizontal sync pulses.
|
// horizontal sync pulses.
|
//
|
//
|
// The core includes an embedded dual port RAM to hold the screen
|
// The core includes an embedded dual port RAM to hold the screen
|
// characters.
|
// characters.
|
//
|
//
|
// The controller expects a 128kB memory region to be reserved.
|
// The controller expects a 128kB memory region to be reserved.
|
//
|
//
|
// Memory Map:
|
// Memory Map:
|
// 00000-0FFFF display ram
|
// 00000-0FFFF display ram
|
// 17F00-17FFF controller registers
|
// 17F00-17FFF controller registers
|
// 18000-1FFFF character bitmap ram
|
// 18000-1FFFF character bitmap ram
|
//
|
//
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
// Registers
|
// Registers
|
//
|
//
|
// 00h
|
// 00h
|
// 7 - 0 cccccccc number of columns (horizontal displayed number of characters)
|
// 7 - 0 cccccccc number of columns (horizontal displayed number of characters)
|
// 15- 8 rrrrrrrr number of rows (vertical displayed number of characters)
|
// 15- 8 rrrrrrrr number of rows (vertical displayed number of characters)
|
// 19-16 dddd character output delay
|
// 19-16 dddd character output delay
|
// 43-32 nnnn nnnnnnnn window left (horizontal sync position - reference for left edge of displayed)
|
// 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)
|
// 59-48 nnnn nnnnnnnn window top (vertical sync position - reference for the top edge of displayed)
|
// 01h
|
// 01h
|
// 4- 0 nnnnn maximum scan line (char ROM max value is 7)
|
// 4- 0 nnnnn maximum scan line (char ROM max value is 7)
|
// 11- 8 wwww pixel size - width
|
// 11- 8 wwww pixel size - width
|
// 15-12 hhhh pixel size - height
|
// 15-12 hhhh pixel size - height
|
// 24 r reset state bit
|
// 24 r reset state bit
|
// 48-52 nnnnn yscroll
|
// 48-52 nnnnn yscroll
|
// 56-60 nnnnn xscroll
|
// 56-60 nnnnn xscroll
|
// 02h
|
// 02h
|
// 20- 0 cccccccc cccccccc color code for transparent background RGB 7,7,7
|
// 20- 0 cccccccc cccccccc color code for transparent background RGB 7,7,7
|
// 63-32 cccc...cccc border color ZRGB 8,8,8,8
|
// 63-32 cccc...cccc border color ZRGB 8,8,8,8
|
// 03h
|
// 03h
|
// 4- 0 eeeee cursor end
|
// 4- 0 eeeee cursor end
|
// 7- 5 bbb blink control
|
// 7- 5 bbb blink control
|
// BP: 00=no blink
|
// BP: 00=no blink
|
// BP: 01=no display
|
// BP: 01=no display
|
// BP: 10=1/16 field rate blink
|
// BP: 10=1/16 field rate blink
|
// BP: 11=1/32 field rate blink
|
// BP: 11=1/32 field rate blink
|
// 12- 8 sssss cursor start
|
// 12- 8 sssss cursor start
|
// 15-14 tt cursor image type (box, underline, sidebar, asterisk
|
// 15-14 tt cursor image type (box, underline, sidebar, asterisk
|
// 47-32 aaaaaaaa aaaaaaaa cursor position
|
// 47-32 aaaaaaaa aaaaaaaa cursor position
|
// 04h
|
// 04h
|
// 15- 0 aaaaaaaa aaaaaaaa start address (index into display memory)
|
// 15- 0 aaaaaaaa aaaaaaaa start address (index into display memory)
|
// 05h
|
// 05h
|
// 15-0 aaaaaaaa aaaaaaaa font address
|
// 15-0 aaaaaaaa aaaaaaaa font address
|
// 07h
|
// 07h
|
// 150 - - aaaaaaaa aaaaaaaa light pen position
|
// 150 - - aaaaaaaa aaaaaaaa light pen position
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
|
|
//`define USE_CLOCK_GATE
|
//`define USE_CLOCK_GATE
|
|
|
module GFX_TextController(
|
module GFX_TextController(
|
rst_i, clk_i, cs_i,
|
rst_i, clk_i, cs_i,
|
cti_i, cyc_i, stb_i, ack_o, wr_i, sel_i, adr_i, dat_i, dat_o,
|
cti_i, cyc_i, stb_i, ack_o, wr_i, sel_i, adr_i, dat_i, dat_o,
|
lp_i,
|
lp_i,
|
dot_clk_i, hsync_i, vsync_i, blank_i, border_i, zrgb_i, zrgb_o, xonoff_i
|
dot_clk_i, hsync_i, vsync_i, blank_i, border_i, zrgb_i, zrgb_o, xonoff_i
|
);
|
);
|
parameter num = 4'd1;
|
parameter num = 4'd1;
|
parameter COLS = 8'd64;
|
parameter COLS = 8'd64;
|
parameter ROWS = 8'd33;
|
parameter ROWS = 8'd33;
|
|
|
// Syscon
|
// Syscon
|
input rst_i; // reset
|
input rst_i; // reset
|
input clk_i; // clock
|
input clk_i; // clock
|
|
|
// Slave signals
|
// Slave signals
|
input cs_i; // circuit select
|
input cs_i; // circuit select
|
input [2:0] cti_i;
|
input [2:0] cti_i;
|
input cyc_i; // valid bus cycle
|
input cyc_i; // valid bus cycle
|
input stb_i; // data strobe
|
input stb_i; // data strobe
|
output ack_o; // data acknowledge
|
output ack_o; // data acknowledge
|
input wr_i; // write
|
input wr_i; // write
|
input [ 7:0] sel_i; // byte lane select
|
input [ 7:0] sel_i; // byte lane select
|
input [16:0] adr_i; // address
|
input [16:0] adr_i; // address
|
input [63:0] dat_i; // data input
|
input [63:0] dat_i; // data input
|
output reg [63:0] dat_o; // data output
|
output reg [63:0] dat_o; // data output
|
|
|
input lp_i; // light pen
|
input lp_i; // light pen
|
|
|
// Video signals
|
// Video signals
|
input dot_clk_i; // video dot clock
|
input dot_clk_i; // video dot clock
|
input hsync_i; // end of scan line
|
input hsync_i; // end of scan line
|
input vsync_i; // end of frame
|
input vsync_i; // end of frame
|
input blank_i; // blanking signal
|
input blank_i; // blanking signal
|
input border_i; // border area
|
input border_i; // border area
|
input [31:0] zrgb_i; // input pixel stream
|
input [31:0] zrgb_i; // input pixel stream
|
output reg [31:0] zrgb_o; // output pixel stream
|
output reg [31:0] zrgb_o; // output pixel stream
|
input xonoff_i;
|
input xonoff_i;
|
|
|
integer n;
|
integer n;
|
reg controller_enable;
|
reg controller_enable;
|
reg [31:0] bkColor32, bkColor32d; // background color
|
reg [31:0] bkColor32, bkColor32d; // background color
|
reg [31:0] fgColor32, fgColor32d; // foreground color
|
reg [31:0] fgColor32, fgColor32d; // foreground color
|
|
|
wire pix; // pixel value from character generator 1=on,0=off
|
wire pix; // pixel value from character generator 1=on,0=off
|
|
|
reg por;
|
reg por;
|
wire vclk;
|
wire vclk;
|
reg [63:0] rego;
|
reg [63:0] rego;
|
reg [5:0] yscroll;
|
reg [5:0] yscroll;
|
reg [5:0] xscroll;
|
reg [5:0] xscroll;
|
reg [11:0] windowTop;
|
reg [11:0] windowTop;
|
reg [11:0] windowLeft;
|
reg [11:0] windowLeft;
|
reg [ 7:0] numCols;
|
reg [ 7:0] numCols;
|
reg [ 7:0] numRows;
|
reg [ 7:0] numRows;
|
reg [ 7:0] charOutDelay;
|
reg [ 7:0] charOutDelay;
|
reg [ 1:0] mode;
|
reg [ 1:0] mode;
|
reg [ 5:0] maxRowScan;
|
reg [ 5:0] maxRowScan;
|
reg [ 5:0] maxScanpix;
|
reg [ 5:0] maxScanpix;
|
reg [ 5:0] cursorStart, cursorEnd;
|
reg [ 5:0] cursorStart, cursorEnd;
|
reg [15:0] cursorPos;
|
reg [15:0] cursorPos;
|
reg [1:0] cursorType;
|
reg [1:0] cursorType;
|
reg [15:0] fontAddress;
|
reg [15:0] fontAddress;
|
reg [15:0] startAddress;
|
reg [15:0] startAddress;
|
reg [ 2:0] rBlink;
|
reg [ 2:0] rBlink;
|
reg [31:0] bdrColor; // Border color
|
reg [31:0] bdrColor; // Border color
|
reg [ 3:0] pixelWidth; // horizontal pixel width in clock cycles
|
reg [ 3:0] pixelWidth; // horizontal pixel width in clock cycles
|
reg [ 3:0] pixelHeight; // vertical pixel height in scan lines
|
reg [ 3:0] pixelHeight; // vertical pixel height in scan lines
|
reg ecm; // extended color mode
|
reg ecm; // extended color mode
|
|
|
wire [11:0] hctr; // horizontal reference counter (counts clocks since hSync)
|
wire [11:0] hctr; // horizontal reference counter (counts clocks since hSync)
|
wire [11:0] scanline; // scan line
|
wire [11:0] scanline; // scan line
|
reg [ 7:0] row; // vertical reference counter (counts rows since vSync)
|
reg [ 7:0] row; // vertical reference counter (counts rows since vSync)
|
reg [ 7:0] col; // horizontal column
|
reg [ 7:0] col; // horizontal column
|
reg [ 5:0] rowscan; // scan line within row
|
reg [ 5:0] rowscan; // scan line within row
|
reg [ 5:0] colscan; // pixel column number within cell
|
reg [ 5:0] colscan; // pixel column number within cell
|
wire nxt_row; // when to increment the row counter
|
wire nxt_row; // when to increment the row counter
|
wire nxt_col; // when to increment the column counter
|
wire nxt_col; // when to increment the column counter
|
reg [ 5:0] bcnt; // blink timing counter
|
reg [ 5:0] bcnt; // blink timing counter
|
wire blink;
|
wire blink;
|
reg iblank;
|
reg iblank;
|
reg [5:0] maxScanlinePlusOne;
|
reg [5:0] maxScanlinePlusOne;
|
|
|
wire nhp; // next horizontal pixel
|
wire nhp; // next horizontal pixel
|
wire ld_shft = nxt_col & nhp;
|
wire ld_shft = nxt_col & nhp;
|
|
|
|
|
// display and timing signals
|
// display and timing signals
|
reg [15:0] txtAddr; // index into memory
|
reg [15:0] txtAddr; // index into memory
|
reg [15:0] penAddr;
|
reg [15:0] penAddr;
|
wire [63:0] screen_ram_out; // character code
|
wire [63:0] screen_ram_out; // character code
|
wire [63:0] char_bmp; // character ROM output
|
wire [63:0] char_bmp; // character ROM output
|
wire [20:0] txtBkColor; // background color code
|
wire [20:0] txtBkColor; // background color code
|
wire [20:0] txtFgColor; // foreground color code
|
wire [20:0] txtFgColor; // foreground color code
|
wire [5:0] txtZorder;
|
wire [5:0] txtZorder;
|
reg [20:0] txtTcCode; // transparent color code
|
reg [20:0] txtTcCode; // transparent color code
|
reg bgt, bgtd;
|
reg bgt, bgtd;
|
|
|
wire [63:0] tdat_o;
|
wire [63:0] tdat_o;
|
|
|
wire [2:0] scanindex = rowscan[2:0];
|
wire [2:0] scanindex = rowscan[2:0];
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
// bus interfacing
|
// bus interfacing
|
// Address Decoding
|
// Address Decoding
|
// I/O range Dx
|
// I/O range Dx
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
// Register the inputs
|
// Register the inputs
|
reg cs_rom, cs_reg, cs_text, cs_any;
|
reg cs_rom, cs_reg, cs_text, cs_any;
|
reg [16:0] radr_i;
|
reg [16:0] radr_i;
|
reg [63:0] rdat_i;
|
reg [63:0] rdat_i;
|
reg rwr_i;
|
reg rwr_i;
|
reg [7:0] rsel_i;
|
reg [7:0] rsel_i;
|
reg [7:0] wrs_i;
|
reg [7:0] wrs_i;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cs_rom <= cs_i && cyc_i && stb_i && (adr_i[16:8] > 9'h17F);
|
cs_rom <= cs_i && cyc_i && stb_i && (adr_i[16:8] > 9'h17F);
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cs_reg <= cs_i && cyc_i && stb_i && (adr_i[16:8] == 9'h17F);
|
cs_reg <= cs_i && cyc_i && stb_i && (adr_i[16:8] == 9'h17F);
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cs_text <= cs_i && cyc_i && stb_i && (adr_i[16:8] < 9'h100);
|
cs_text <= cs_i && cyc_i && stb_i && (adr_i[16:8] < 9'h100);
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
cs_any <= cs_i && cyc_i && stb_i;
|
cs_any <= cs_i && cyc_i && stb_i;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
wrs_i <= {8{wr_i}} & sel_i;
|
wrs_i <= {8{wr_i}} & sel_i;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rwr_i <= wr_i;
|
rwr_i <= wr_i;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rsel_i <= sel_i;
|
rsel_i <= sel_i;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
radr_i[16:3] <= adr_i[16:3];
|
radr_i[16:3] <= adr_i[16:3];
|
// Recreate LSB's for charram
|
// Recreate LSB's for charram
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
begin
|
begin
|
radr_i[0] <= sel_i[1]|sel_i[3]|sel_i[5]|sel_i[7];
|
radr_i[0] <= sel_i[1]|sel_i[3]|sel_i[5]|sel_i[7];
|
radr_i[1] <= |sel_i[3:2] | |sel_i[7:6];
|
radr_i[1] <= |sel_i[3:2] | |sel_i[7:6];
|
radr_i[2] <= |sel_i[7:4];
|
radr_i[2] <= |sel_i[7:4];
|
end
|
end
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rdat_i <= dat_i;
|
rdat_i <= dat_i;
|
|
|
// Register outputs
|
// Register outputs
|
// The output is "sticky" to give more hold time.
|
// The output is "sticky" to give more hold time.
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
casez({cs_rom,cs_reg,cs_text})
|
casez({cs_rom,cs_reg,cs_text})
|
3'b01?: dat_o <= rego;
|
3'b01?: dat_o <= rego;
|
3'b001: dat_o <= tdat_o;
|
3'b001: dat_o <= tdat_o;
|
default: dat_o <= dat_o;
|
default: dat_o <= dat_o;
|
endcase
|
endcase
|
|
|
//always @(posedge clk_i)
|
//always @(posedge clk_i)
|
// if (cs_text) begin
|
// if (cs_text) begin
|
// $display("TC WRite: %h %h", adr_i, dat_i);
|
// $display("TC WRite: %h %h", adr_i, dat_i);
|
// $stop;
|
// $stop;
|
// end
|
// end
|
|
|
// - there is a four cycle latency for reads, an ack is generated
|
// - there is a four cycle latency for reads, an ack is generated
|
// after the synchronous RAM read
|
// after the synchronous RAM read
|
// - writes can be acknowledged right away.
|
// - writes can be acknowledged right away.
|
|
|
ack_gen #(
|
ack_gen #(
|
.READ_STAGES(5),
|
.READ_STAGES(5),
|
.WRITE_STAGES(1),
|
.WRITE_STAGES(1),
|
.REGISTER_OUTPUT(1)
|
.REGISTER_OUTPUT(1)
|
)
|
)
|
uag1 (
|
uag1 (
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce_i(1'b1),
|
.ce_i(1'b1),
|
.i(cs_any),
|
.i(cs_any),
|
.we_i(cs_any & rwr_i),
|
.we_i(cs_any & rwr_i),
|
.o(ack_o)
|
.o(ack_o)
|
);
|
);
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
`ifdef USE_CLOCK_GATE
|
`ifdef USE_CLOCK_GATE
|
BUFHCE ucb1 (.I(dot_clk_i), .CE(controller_enable), .O(vclk));
|
BUFHCE ucb1 (.I(dot_clk_i), .CE(controller_enable), .O(vclk));
|
`else
|
`else
|
assign vclk = dot_clk_i;
|
assign vclk = dot_clk_i;
|
`endif
|
`endif
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
// Video Memory
|
// Video Memory
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Address Calculation:
|
// Address Calculation:
|
// - Simple: the row times the number of cols plus the col plus the
|
// - Simple: the row times the number of cols plus the col plus the
|
// base screen address
|
// base screen address
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
reg [15:0] rowcol;
|
reg [15:0] rowcol;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (ld_shft)
|
if (ld_shft)
|
txtAddr <= startAddress + rowcol + col;
|
txtAddr <= startAddress + rowcol + col;
|
|
|
// Register read-back memory
|
// Register read-back memory
|
// Allows reading back of register values by shadowing them with ram
|
// Allows reading back of register values by shadowing them with ram
|
|
|
wire [3:0] rrm_adr = radr_i[6:3];
|
wire [3:0] rrm_adr = radr_i[6:3];
|
wire [63:0] rrm_o;
|
wire [63:0] rrm_o;
|
|
|
regReadbackMem #(.WID(8)) rrm0L
|
regReadbackMem #(.WID(8)) rrm0L
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[0]),
|
.we(rwr_i & rsel_i[0]),
|
.i(rdat_i[7:0]),
|
.i(rdat_i[7:0]),
|
.o(rrm_o[7:0])
|
.o(rrm_o[7:0])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm0H
|
regReadbackMem #(.WID(8)) rrm0H
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[1]),
|
.we(rwr_i & rsel_i[1]),
|
.i(rdat_i[15:8]),
|
.i(rdat_i[15:8]),
|
.o(rrm_o[15:8])
|
.o(rrm_o[15:8])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm1L
|
regReadbackMem #(.WID(8)) rrm1L
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[2]),
|
.we(rwr_i & rsel_i[2]),
|
.i(rdat_i[23:16]),
|
.i(rdat_i[23:16]),
|
.o(rrm_o[23:16])
|
.o(rrm_o[23:16])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm1H
|
regReadbackMem #(.WID(8)) rrm1H
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[3]),
|
.we(rwr_i & rsel_i[3]),
|
.i(rdat_i[31:24]),
|
.i(rdat_i[31:24]),
|
.o(rrm_o[31:24])
|
.o(rrm_o[31:24])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm2L
|
regReadbackMem #(.WID(8)) rrm2L
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[4]),
|
.we(rwr_i & rsel_i[4]),
|
.i(rdat_i[39:32]),
|
.i(rdat_i[39:32]),
|
.o(rrm_o[39:32])
|
.o(rrm_o[39:32])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm2H
|
regReadbackMem #(.WID(8)) rrm2H
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[5]),
|
.we(rwr_i & rsel_i[5]),
|
.i(rdat_i[47:40]),
|
.i(rdat_i[47:40]),
|
.o(rrm_o[47:40])
|
.o(rrm_o[47:40])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm3L
|
regReadbackMem #(.WID(8)) rrm3L
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[6]),
|
.we(rwr_i & rsel_i[6]),
|
.i(rdat_i[55:48]),
|
.i(rdat_i[55:48]),
|
.o(rrm_o[55:48])
|
.o(rrm_o[55:48])
|
);
|
);
|
|
|
regReadbackMem #(.WID(8)) rrm3H
|
regReadbackMem #(.WID(8)) rrm3H
|
(
|
(
|
.wclk(clk_i),
|
.wclk(clk_i),
|
.adr(rrm_adr),
|
.adr(rrm_adr),
|
.wce(cs_reg),
|
.wce(cs_reg),
|
.we(rwr_i & rsel_i[7]),
|
.we(rwr_i & rsel_i[7]),
|
.i(rdat_i[63:56]),
|
.i(rdat_i[63:56]),
|
.o(rrm_o[63:56])
|
.o(rrm_o[63:56])
|
);
|
);
|
|
|
wire [23:0] lfsr1_o;
|
wire [23:0] lfsr1_o;
|
lfsr #(24) ulfsr1(rst_i, dot_clk_i, 1'b1, 1'b0, lfsr1_o);
|
lfsr #(24) ulfsr1(rst_i, dot_clk_i, 1'b1, 1'b0, lfsr1_o);
|
wire [63:0] lfsr_o = {6'h20,
|
wire [63:0] lfsr_o = {6'h20,
|
lfsr1_o[23:21],4'b0,lfsr1_o[20:18],4'b0,lfsr1_o[17:16],5'b0,
|
lfsr1_o[23:21],4'b0,lfsr1_o[20:18],4'b0,lfsr1_o[17:16],5'b0,
|
lfsr1_o[15:13],4'b0,lfsr1_o[12:10],4'b0,lfsr1_o[9:8],5'b0,
|
lfsr1_o[15:13],4'b0,lfsr1_o[12:10],4'b0,lfsr1_o[9:8],5'b0,
|
8'h00,lfsr1_o[7:0]
|
8'h00,lfsr1_o[7:0]
|
};
|
};
|
|
|
/* The following code was for WB burst access to the text memory. About the
|
/* The following code was for WB burst access to the text memory. About the
|
only time burst access is used is for screen clear. This is just code bloat.
|
only time burst access is used is for screen clear. This is just code bloat.
|
wire pe_cs;
|
wire pe_cs;
|
edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs_text), .pe(pe_cs), .ne(), .ee() );
|
edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs_text), .pe(pe_cs), .ne(), .ee() );
|
|
|
reg [14:0] ctr;
|
reg [14:0] ctr;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (pe_cs) begin
|
if (pe_cs) begin
|
if (cti_i==3'b000)
|
if (cti_i==3'b000)
|
ctr <= adr_i[16:3];
|
ctr <= adr_i[16:3];
|
else
|
else
|
ctr <= adr_i[16:3] + 12'd1;
|
ctr <= adr_i[16:3] + 12'd1;
|
cnt <= 3'b000;
|
cnt <= 3'b000;
|
end
|
end
|
else if (cs_text && cnt[2:0]!=3'b100 && cti_i!=3'b000) begin
|
else if (cs_text && cnt[2:0]!=3'b100 && cti_i!=3'b000) begin
|
ctr <= ctr + 2'd1;
|
ctr <= ctr + 2'd1;
|
cnt <= cnt + 3'd1;
|
cnt <= cnt + 3'd1;
|
end
|
end
|
|
|
reg [13:0] radr;
|
reg [13:0] radr;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
radr <= pe_cs ? adr_i[16:3] : ctr;
|
radr <= pe_cs ? adr_i[16:3] : ctr;
|
*/
|
*/
|
// text screen RAM
|
// text screen RAM
|
wire [15:0] bram_adr = radr_i[15:0];
|
wire [15:0] bram_adr = radr_i[15:0];
|
syncRam8kx64 screen_ram1
|
syncRam8kx64 screen_ram1
|
(
|
(
|
.clka(clk_i),
|
.clka(clk_i),
|
.ena(cs_text),
|
.ena(cs_text),
|
.wea(wrs_i),
|
.wea(wrs_i),
|
.addra(bram_adr[15:3]),
|
.addra(bram_adr[15:3]),
|
.dina(rdat_i),
|
.dina(rdat_i),
|
.douta(tdat_o),
|
.douta(tdat_o),
|
.clkb(vclk),
|
.clkb(vclk),
|
.enb(ld_shft|por),
|
.enb(ld_shft|por),
|
.web({8{por}}),
|
.web({8{por}}),
|
.addrb(txtAddr[12:0]),
|
.addrb(txtAddr[12:0]),
|
.dinb(lfsr_o),
|
.dinb(lfsr_o),
|
.doutb(screen_ram_out)
|
.doutb(screen_ram_out)
|
);
|
);
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Character bitmap ROM/RAM
|
// Character bitmap ROM/RAM
|
// - 32kB
|
// - 32kB
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
char_ram charRam0
|
char_ram charRam0
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.cs_i(cs_rom),
|
.cs_i(cs_rom),
|
.we_i(1'b0),
|
.we_i(1'b0),
|
.adr_i(bram_adr[14:0]),
|
.adr_i(bram_adr[14:0]),
|
.dat_i(rdat_i >> {bram_adr[2:0],3'b0}),
|
.dat_i(rdat_i >> {bram_adr[2:0],3'b0}),
|
.dot_clk_i(vclk),
|
.dot_clk_i(vclk),
|
.ce_i(ld_shft),
|
.ce_i(ld_shft),
|
.fontAddress_i(fontAddress),
|
.fontAddress_i(fontAddress),
|
.char_code_i(screen_ram_out[11:0]),
|
.char_code_i(screen_ram_out[11:0]),
|
.maxScanpix_i(maxScanpix),
|
.maxScanpix_i(maxScanpix),
|
.maxscanline_i(maxScanlinePlusOne),
|
.maxscanline_i(maxScanlinePlusOne),
|
.scanline_i(rowscan),
|
.scanline_i(rowscan),
|
.bmp_o(char_bmp)
|
.bmp_o(char_bmp)
|
);
|
);
|
|
|
// pipeline delay - sync color with character bitmap output
|
// pipeline delay - sync color with character bitmap output
|
reg [20:0] txtBkCode1;
|
wire [20:0] txtBkCode1;
|
reg [20:0] txtFgCode1;
|
wire [20:0] txtFgCode1;
|
reg [5:0] txtZorder1;
|
wire [5:0] txtZorder1;
|
always @(posedge vclk)
|
|
if (ld_shft) txtBkCode1 <= screen_ram_out[36:16];
|
delay #(.WID(21),.DEP(3)) udlyb (.clk(vclk), .ce(ld_shft), .i(screen_ram_out[36:16]), .o(txtBkCode1));
|
always @(posedge vclk)
|
delay #(.WID(21),.DEP(3)) udlyf (.clk(vclk), .ce(ld_shft), .i(screen_ram_out[57:37]), .o(txtFgCode1));
|
if (ld_shft) txtFgCode1 <= screen_ram_out[57:37];
|
delay #(.WID( 6),.DEP(3)) udlyz (.clk(vclk), .ce(ld_shft), .i(screen_ram_out[63:58]), .o(txtZorder1));
|
always @(posedge vclk)
|
|
if (ld_shft) txtZorder1 <= screen_ram_out[63:58];
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
// Light Pen
|
// Light Pen
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
wire lpe;
|
wire lpe;
|
edge_det u1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(lp_i), .pe(lpe), .ne(), .ee() );
|
edge_det u1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(lp_i), .pe(lpe), .ne(), .ee() );
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
penAddr <= 32'h0000_0000;
|
penAddr <= 32'h0000_0000;
|
else begin
|
else begin
|
if (lpe)
|
if (lpe)
|
penAddr <= txtAddr;
|
penAddr <= txtAddr;
|
end
|
end
|
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Register read port
|
// Register read port
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
always @*
|
always @*
|
if (cs_reg) begin
|
if (cs_reg) begin
|
case(rrm_adr)
|
case(rrm_adr)
|
4'd7: rego <= penAddr;
|
4'd7: rego <= penAddr;
|
default: rego <= rrm_o;
|
default: rego <= rrm_o;
|
endcase
|
endcase
|
end
|
end
|
else
|
else
|
rego <= 64'h0000;
|
rego <= 64'h0000;
|
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Register write port
|
// Register write port
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i) begin
|
if (rst_i) begin
|
por <= 1'b1;
|
por <= 1'b1;
|
controller_enable <= 1'b1;
|
controller_enable <= 1'b1;
|
xscroll <= 6'd0;
|
xscroll <= 6'd0;
|
yscroll <= 6'd0;
|
yscroll <= 6'd0;
|
txtTcCode <= 16'h1ff;
|
txtTcCode <= 16'h1ff;
|
bdrColor <= 32'hFFBF2020;
|
bdrColor <= 32'hFFBF2020;
|
startAddress <= 16'h0000;
|
startAddress <= 16'h0000;
|
fontAddress <= 16'h0000;
|
fontAddress <= 16'h0000;
|
cursorStart <= 5'd00;
|
cursorStart <= 5'd00;
|
cursorEnd <= 5'd31;
|
cursorEnd <= 5'd31;
|
cursorPos <= 16'h0003;
|
cursorPos <= 16'h0003;
|
cursorType <= 2'b00;
|
cursorType <= 2'b00;
|
// 104x63
|
// 104x63
|
/*
|
/*
|
windowTop <= 12'd26;
|
windowTop <= 12'd26;
|
windowLeft <= 12'd260;
|
windowLeft <= 12'd260;
|
pixelWidth <= 4'd0;
|
pixelWidth <= 4'd0;
|
pixelHeight <= 4'd1; // 525 pixels (408 with border)
|
pixelHeight <= 4'd1; // 525 pixels (408 with border)
|
*/
|
*/
|
// 52x31
|
// 52x31
|
/*
|
/*
|
// 84x47
|
// 84x47
|
windowTop <= 12'd16;
|
windowTop <= 12'd16;
|
windowLeft <= 12'd90;
|
windowLeft <= 12'd90;
|
pixelWidth <= 4'd1; // 681 pixels
|
pixelWidth <= 4'd1; // 681 pixels
|
pixelHeight <= 4'd1; // 384 pixels
|
pixelHeight <= 4'd1; // 384 pixels
|
*/
|
*/
|
// 48x29
|
// 48x29
|
if (num==4'd1) begin
|
if (num==4'd1) begin
|
windowTop <= 12'd4058;//12'd16;
|
windowTop <= 12'd4058;//12'd16;
|
windowLeft <= 12'd3944;//12'd3930;//12'd86;
|
windowLeft <= 12'd3964;//12'd3930;//12'd86;
|
pixelWidth <= 4'd0; // 1280 pixels
|
pixelWidth <= 4'd0; // 1280 pixels
|
pixelHeight <= 4'd0; // 720 pixels
|
pixelHeight <= 4'd0; // 720 pixels
|
numCols <= COLS;
|
numCols <= COLS;
|
numRows <= ROWS;
|
numRows <= ROWS;
|
maxRowScan <= 6'd17;
|
maxRowScan <= 6'd17;
|
maxScanpix <= 6'd11;
|
maxScanpix <= 6'd11;
|
rBlink <= 3'b111; // 01 = non display
|
rBlink <= 3'b111; // 01 = non display
|
charOutDelay <= 8'd7;
|
charOutDelay <= 8'd7;
|
end
|
end
|
else if (num==4'd2) begin
|
else if (num==4'd2) begin
|
windowTop <= 12'd4032;//12'd16;
|
windowTop <= 12'd4032;//12'd16;
|
windowLeft <= 12'd3720;//12'd86;
|
windowLeft <= 12'd3720;//12'd86;
|
pixelWidth <= 4'd0; // 800 pixels
|
pixelWidth <= 4'd0; // 800 pixels
|
pixelHeight <= 4'd0; // 600 pixels
|
pixelHeight <= 4'd0; // 600 pixels
|
numCols <= 40;
|
numCols <= 40;
|
numRows <= 25;
|
numRows <= 25;
|
maxRowScan <= 6'd7;
|
maxRowScan <= 6'd7;
|
maxScanpix <= 6'd7;
|
maxScanpix <= 6'd7;
|
rBlink <= 3'b111; // 01 = non display
|
rBlink <= 3'b111; // 01 = non display
|
charOutDelay <= 8'd6;
|
charOutDelay <= 8'd6;
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
|
|
if (bcnt > 6'd10)
|
if (bcnt > 6'd10)
|
por <= 1'b0;
|
por <= 1'b0;
|
|
|
if (cs_reg & rwr_i) begin // register write ?
|
if (cs_reg & rwr_i) begin // register write ?
|
$display("TC Write: r%d=%h", rrm_adr, rdat_i);
|
$display("TC Write: r%d=%h", rrm_adr, rdat_i);
|
case(rrm_adr)
|
case(rrm_adr)
|
4'd0: begin
|
4'd0: begin
|
if (rsel_i[0]) numCols <= rdat_i[7:0];
|
if (rsel_i[0]) numCols <= rdat_i[7:0];
|
if (rsel_i[1]) numRows <= rdat_i[15:8];
|
if (rsel_i[1]) numRows <= rdat_i[15:8];
|
if (rsel_i[2]) charOutDelay <= rdat_i[23:16];
|
if (rsel_i[2]) charOutDelay <= rdat_i[23:16];
|
if (rsel_i[4]) windowLeft[7:0] <= rdat_i[39:32];
|
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[5]) windowLeft[11:8] <= rdat_i[43:40];
|
if (rsel_i[6]) windowTop[7:0] <= rdat_i[55:48];
|
if (rsel_i[6]) windowTop[7:0] <= rdat_i[55:48];
|
if (rsel_i[7]) windowTop[11:8] <= rdat_i[59:56];
|
if (rsel_i[7]) windowTop[11:8] <= rdat_i[59:56];
|
end
|
end
|
4'd1:
|
4'd1:
|
begin
|
begin
|
if (rsel_i[0]) maxRowScan <= rdat_i[5:0];
|
if (rsel_i[0]) maxRowScan <= rdat_i[5:0];
|
if (rsel_i[1]) begin
|
if (rsel_i[1]) begin
|
pixelHeight <= rdat_i[15:12];
|
pixelHeight <= rdat_i[15:12];
|
pixelWidth <= rdat_i[11:8]; // horizontal pixel width
|
pixelWidth <= rdat_i[11:8]; // horizontal pixel width
|
end
|
end
|
if (rsel_i[2]) maxScanpix <= rdat_i[21:16];
|
if (rsel_i[2]) maxScanpix <= rdat_i[21:16];
|
if (rsel_i[3]) por <= rdat_i[24];
|
if (rsel_i[3]) por <= rdat_i[24];
|
if (rsel_i[4]) controller_enable <= rdat_i[32];
|
if (rsel_i[4]) controller_enable <= rdat_i[32];
|
if (rsel_i[6]) yscroll <= rdat_i[53:48];
|
if (rsel_i[6]) yscroll <= rdat_i[53:48];
|
if (rsel_i[7]) xscroll <= rdat_i[61:56];
|
if (rsel_i[7]) xscroll <= rdat_i[61:56];
|
end
|
end
|
4'd2: // Color Control
|
4'd2: // Color Control
|
begin
|
begin
|
if (rsel_i[0]) txtTcCode[7:0] <= rdat_i[7:0];
|
if (rsel_i[0]) txtTcCode[7:0] <= rdat_i[7:0];
|
if (rsel_i[1]) txtTcCode[15:8] <= rdat_i[15:8];
|
if (rsel_i[1]) txtTcCode[15:8] <= rdat_i[15:8];
|
if (rsel_i[2]) txtTcCode[20:16] <= rdat_i[20:16];
|
if (rsel_i[2]) txtTcCode[20:16] <= rdat_i[20:16];
|
if (rsel_i[4]) bdrColor[7:0] <= dat_i[39:32];
|
if (rsel_i[4]) bdrColor[7:0] <= dat_i[39:32];
|
if (rsel_i[5]) bdrColor[15:8] <= dat_i[47:40];
|
if (rsel_i[5]) bdrColor[15:8] <= dat_i[47:40];
|
if (rsel_i[6]) bdrColor[23:16] <= dat_i[55:48];
|
if (rsel_i[6]) bdrColor[23:16] <= dat_i[55:48];
|
if (rsel_i[7]) bdrColor[31:24] <= dat_i[63:56];
|
if (rsel_i[7]) bdrColor[31:24] <= dat_i[63:56];
|
end
|
end
|
4'd3: // Cursor Control
|
4'd3: // Cursor Control
|
begin
|
begin
|
if (rsel_i[0]) begin
|
if (rsel_i[0]) begin
|
cursorEnd <= rdat_i[4:0]; // scan line sursor starts on
|
cursorEnd <= rdat_i[4:0]; // scan line sursor starts on
|
rBlink <= rdat_i[7:5];
|
rBlink <= rdat_i[7:5];
|
end
|
end
|
if (rsel_i[1]) begin
|
if (rsel_i[1]) begin
|
cursorStart <= rdat_i[12:8]; // scan line cursor ends on
|
cursorStart <= rdat_i[12:8]; // scan line cursor ends on
|
cursorType <= rdat_i[15:14];
|
cursorType <= rdat_i[15:14];
|
end
|
end
|
if (rsel_i[4]) cursorPos[7:0] <= rdat_i[39:32];
|
if (rsel_i[4]) cursorPos[7:0] <= rdat_i[39:32];
|
if (rsel_i[5]) cursorPos[15:8] <= rdat_i[47:40];
|
if (rsel_i[5]) cursorPos[15:8] <= rdat_i[47:40];
|
end
|
end
|
4'd4: // Page flipping / scrolling
|
4'd4: // Page flipping / scrolling
|
begin
|
begin
|
if (rsel_i[0]) startAddress[7:0] <= rdat_i[7:0];
|
if (rsel_i[0]) startAddress[7:0] <= rdat_i[7:0];
|
if (rsel_i[1]) startAddress[15:8] <= rdat_i[15:8];
|
if (rsel_i[1]) startAddress[15:8] <= rdat_i[15:8];
|
end
|
end
|
4'd5:
|
4'd5:
|
begin
|
begin
|
if (rsel_i[0]) fontAddress[7:0] <= rdat_i[7:0];
|
if (rsel_i[0]) fontAddress[7:0] <= rdat_i[7:0];
|
if (rsel_i[1]) fontAddress[15:8] <= rdat_i[15:8];
|
if (rsel_i[1]) fontAddress[15:8] <= rdat_i[15:8];
|
end
|
end
|
default: ;
|
default: ;
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
|
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
|
|
// "Box" cursor bitmap
|
// "Box" cursor bitmap
|
(* ram_style="block" *)
|
(* ram_style="block" *)
|
reg [31:0] curram [0:511];
|
reg [31:0] curram [0:511];
|
reg [31:0] curout, curout1;
|
reg [31:0] curout, curout1;
|
initial begin
|
initial begin
|
// Box cursor
|
// Box cursor
|
curram[0] = 8'b11111110;
|
curram[0] = 8'b11111110;
|
curram[1] = 8'b10000010;
|
curram[1] = 8'b10000010;
|
curram[2] = 8'b10000010;
|
curram[2] = 8'b10000010;
|
curram[3] = 8'b10000010;
|
curram[3] = 8'b10000010;
|
curram[4] = 8'b10000010;
|
curram[4] = 8'b10000010;
|
curram[5] = 8'b10000010;
|
curram[5] = 8'b10000010;
|
curram[6] = 8'b10010010;
|
curram[6] = 8'b10010010;
|
curram[7] = 8'b11111110;
|
curram[7] = 8'b11111110;
|
// vertical bar cursor
|
// vertical bar cursor
|
curram[32] = 8'b11000000;
|
curram[32] = 8'b11000000;
|
curram[33] = 8'b10000000;
|
curram[33] = 8'b10000000;
|
curram[34] = 8'b10000000;
|
curram[34] = 8'b10000000;
|
curram[35] = 8'b10000000;
|
curram[35] = 8'b10000000;
|
curram[36] = 8'b10000000;
|
curram[36] = 8'b10000000;
|
curram[37] = 8'b10000000;
|
curram[37] = 8'b10000000;
|
curram[38] = 8'b10000000;
|
curram[38] = 8'b10000000;
|
curram[39] = 8'b11000000;
|
curram[39] = 8'b11000000;
|
// underline cursor
|
// underline cursor
|
curram[64] = 8'b00000000;
|
curram[64] = 8'b00000000;
|
curram[65] = 8'b00000000;
|
curram[65] = 8'b00000000;
|
curram[66] = 8'b00000000;
|
curram[66] = 8'b00000000;
|
curram[67] = 8'b00000000;
|
curram[67] = 8'b00000000;
|
curram[68] = 8'b00000000;
|
curram[68] = 8'b00000000;
|
curram[69] = 8'b00000000;
|
curram[69] = 8'b00000000;
|
curram[70] = 8'b00000000;
|
curram[70] = 8'b00000000;
|
curram[71] = 8'b11111111;
|
curram[71] = 8'b11111111;
|
// Asterisk
|
// Asterisk
|
curram[96] = 8'b00000000;
|
curram[96] = 8'b00000000;
|
curram[97] = 8'b00000000;
|
curram[97] = 8'b00000000;
|
curram[98] = 8'b00100100;
|
curram[98] = 8'b00100100;
|
curram[99] = 8'b00011000;
|
curram[99] = 8'b00011000;
|
curram[100] = 8'b01111110;
|
curram[100] = 8'b01111110;
|
curram[101] = 8'b00011000;
|
curram[101] = 8'b00011000;
|
curram[102] = 8'b00100100;
|
curram[102] = 8'b00100100;
|
curram[103] = 8'b00000000;
|
curram[103] = 8'b00000000;
|
end
|
end
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (ld_shft)
|
if (ld_shft)
|
curout1 <= curram[{cursorType,rowscan}];
|
curout1 <= curram[{cursorType,rowscan}];
|
always @(posedge vclk)
|
always @(posedge vclk)
|
curout <= curout1;
|
curout <= curout1;
|
|
|
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
// Video Stuff
|
// Video Stuff
|
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
|
|
wire pe_hsync;
|
wire pe_hsync;
|
wire pe_vsync;
|
wire pe_vsync;
|
edge_det edh1
|
edge_det edh1
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(vclk),
|
.clk(vclk),
|
.ce(1'b1),
|
.ce(1'b1),
|
.i(hsync_i),
|
.i(hsync_i),
|
.pe(pe_hsync),
|
.pe(pe_hsync),
|
.ne(),
|
.ne(),
|
.ee()
|
.ee()
|
);
|
);
|
|
|
edge_det edv1
|
edge_det edv1
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(vclk),
|
.clk(vclk),
|
.ce(1'b1),
|
.ce(1'b1),
|
.i(vsync_i),
|
.i(vsync_i),
|
.pe(pe_vsync),
|
.pe(pe_vsync),
|
.ne(),
|
.ne(),
|
.ee()
|
.ee()
|
);
|
);
|
|
|
// Horizontal counter:
|
// Horizontal counter:
|
//
|
//
|
/*
|
/*
|
HVCounter uhv1
|
HVCounter uhv1
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.vclk(vclk),
|
.vclk(vclk),
|
.pixcce(1'b1),
|
.pixcce(1'b1),
|
.sync(hsync_i),
|
.sync(hsync_i),
|
.cnt_offs(windowLeft),
|
.cnt_offs(windowLeft),
|
.pixsz(pixelWidth),
|
.pixsz(pixelWidth),
|
.maxpix(maxScanpix),
|
.maxpix(maxScanpix),
|
.nxt_pix(nhp),
|
.nxt_pix(nhp),
|
.pos(col),
|
.pos(col),
|
.nxt_pos(nxt_col),
|
.nxt_pos(nxt_col),
|
.ctr(hctr)
|
.ctr(hctr)
|
);
|
);
|
*/
|
*/
|
|
|
// Vertical counter:
|
// Vertical counter:
|
//
|
//
|
/*
|
/*
|
HVCounter uhv2
|
HVCounter uhv2
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.vclk(vclk),
|
.vclk(vclk),
|
.pixcce(pe_hsync),
|
.pixcce(pe_hsync),
|
.sync(vsync_i),
|
.sync(vsync_i),
|
.cnt_offs(windowTop),
|
.cnt_offs(windowTop),
|
.pixsz(pixelHeight),
|
.pixsz(pixelHeight),
|
.maxpix(maxRowScan),
|
.maxpix(maxRowScan),
|
.nxt_pix(),
|
.nxt_pix(),
|
.pos(row),
|
.pos(row),
|
.nxt_pos(nxt_row),
|
.nxt_pos(nxt_row),
|
.ctr(scanline)
|
.ctr(scanline)
|
);
|
);
|
*/
|
*/
|
|
|
// We generally don't care about the exact reset point, unless debugging in
|
// 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
|
// simulation. The counters will eventually cycle to a proper state. A little
|
// bit of logic / routing can be avoided by omitting the reset.
|
// bit of logic / routing can be avoided by omitting the reset.
|
`ifdef SIM
|
`ifdef SIM
|
wire sym_rst = rst_i;
|
wire sym_rst = rst_i;
|
`else
|
`else
|
wire sym_rst = 1'b0;
|
wire sym_rst = 1'b0;
|
`endif
|
`endif
|
|
|
// Raw scanline counter
|
// Raw scanline counter
|
vid_counter #(12) u_vctr (.rst(sym_rst), .clk(vclk), .ce(pe_hsync), .ld(pe_vsync), .d(windowTop), .q(scanline), .tc());
|
vid_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());
|
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 #0
|
// Vertical pixel height counter, synchronized to scanline #0
|
reg [3:0] vpx;
|
reg [3:0] vpx;
|
wire nvp = vpx==pixelHeight;
|
wire nvp = vpx==pixelHeight;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
vpx <= 4'b0;
|
vpx <= 4'b0;
|
else begin
|
else begin
|
if (pe_hsync) begin
|
if (pe_hsync) begin
|
if (scanline==12'd0)
|
if (scanline==12'd0)
|
vpx <= 4'b0;
|
vpx <= 4'b0;
|
else if (nvp)
|
else if (nvp)
|
vpx <= 4'd0;
|
vpx <= 4'd0;
|
else
|
else
|
vpx <= vpx + 4'd1;
|
vpx <= vpx + 4'd1;
|
end
|
end
|
end
|
end
|
|
|
reg [3:0] hpx;
|
reg [3:0] hpx;
|
assign nhp = hpx==pixelWidth;
|
assign nhp = hpx==pixelWidth;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
hpx <= 4'b0;
|
hpx <= 4'b0;
|
else begin
|
else begin
|
if (hctr==12'd0)
|
if (hctr==12'd0)
|
hpx <= 4'b0;
|
hpx <= 4'b0;
|
else if (nhp)
|
else if (nhp)
|
hpx <= 4'd0;
|
hpx <= 4'd0;
|
else
|
else
|
hpx <= hpx + 4'd1;
|
hpx <= hpx + 4'd1;
|
end
|
end
|
|
|
// The scanline row within a character bitmap
|
// The scanline row within a character bitmap
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
rowscan <= 6'd0;
|
rowscan <= 6'd0;
|
else begin
|
else begin
|
if (pe_hsync & nvp) begin
|
if (pe_hsync & nvp) begin
|
if (scanline==12'd0)
|
if (scanline==12'd0)
|
rowscan <= yscroll;
|
rowscan <= yscroll;
|
else if (rowscan==maxRowScan)
|
else if (rowscan==maxRowScan)
|
rowscan <= 6'd0;
|
rowscan <= 6'd0;
|
else
|
else
|
rowscan <= rowscan + 1'd1;
|
rowscan <= rowscan + 1'd1;
|
end
|
end
|
end
|
end
|
|
|
assign nxt_col = colscan==maxScanpix;
|
assign nxt_col = colscan==maxScanpix;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
colscan <= 6'd0;
|
colscan <= 6'd0;
|
else begin
|
else begin
|
if (nhp) begin
|
if (nhp) begin
|
if (hctr==12'd0)
|
if (hctr==12'd0)
|
colscan <= xscroll;
|
colscan <= xscroll;
|
else if (nxt_col)
|
else if (nxt_col)
|
colscan <= 6'd0;
|
colscan <= 6'd0;
|
else
|
else
|
colscan <= colscan + 1'd1;
|
colscan <= colscan + 1'd1;
|
end
|
end
|
end
|
end
|
|
|
// The screen row
|
// The screen row
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
row <= 8'd0;
|
row <= 8'd0;
|
else begin
|
else begin
|
if (pe_hsync & nvp) begin
|
if (pe_hsync & nvp) begin
|
if (scanline==12'd0)
|
if (scanline==12'd0)
|
row <= 8'd0;
|
row <= 8'd0;
|
else if (rowscan==maxRowScan)
|
else if (rowscan==maxRowScan)
|
row <= row + 8'd1;
|
row <= row + 8'd1;
|
end
|
end
|
end
|
end
|
|
|
// The screen column
|
// The screen column
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
col <= 8'd0;
|
col <= 8'd0;
|
else begin
|
else begin
|
if (hctr==12'd0)
|
if (hctr==12'd0)
|
col <= 8'd0;
|
col <= 8'd0;
|
else if (nhp) begin
|
else if (nhp) begin
|
if (nxt_col)
|
if (nxt_col)
|
col <= col + 8'd1;
|
col <= col + 8'd1;
|
end
|
end
|
end
|
end
|
|
|
// More useful, the offset of the start of the text display on a line.
|
// More useful, the offset of the start of the text display on a line.
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
rowcol <= 16'd0;
|
rowcol <= 16'd0;
|
else begin
|
else begin
|
if (pe_hsync & nvp) begin
|
if (pe_hsync & nvp) begin
|
if (scanline==12'd0)
|
if (scanline==12'd0)
|
rowcol <= 8'd0;
|
rowcol <= 8'd0;
|
else if (rowscan==maxRowScan)
|
else if (rowscan==maxRowScan)
|
rowcol <= rowcol + numCols;
|
rowcol <= rowcol + numCols;
|
end
|
end
|
end
|
end
|
|
|
// Takes 3 clock for scanline to become stable, but should be stable before any
|
// Takes 3 clock for scanline to become stable, but should be stable before any
|
// chars are displayed.
|
// chars are displayed.
|
reg [13:0] rxmslp1;
|
reg [13:0] rxmslp1;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
maxScanlinePlusOne <= maxRowScan + 1'd1;
|
maxScanlinePlusOne <= maxRowScan + 1'd1;
|
//always @(posedge vclk)
|
//always @(posedge vclk)
|
// rxmslp1 <= row * maxScanlinePlusOne;
|
// rxmslp1 <= row * maxScanlinePlusOne;
|
//always @(posedge vclk)
|
//always @(posedge vclk)
|
// scanline <= scanline - rxmslp1;
|
// scanline <= scanline - rxmslp1;
|
|
|
|
|
// Blink counter
|
// Blink counter
|
//
|
//
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (sym_rst)
|
if (sym_rst)
|
bcnt <= 6'd0;
|
bcnt <= 6'd0;
|
else begin
|
else begin
|
if (pe_vsync)
|
if (pe_vsync)
|
bcnt <= bcnt + 6'd1;
|
bcnt <= bcnt + 6'd1;
|
end
|
end
|
|
|
reg blink_en;
|
reg blink_en;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
blink_en <= (cursorPos+3==txtAddr) && (rowscan >= cursorStart) && (rowscan <= cursorEnd);
|
blink_en <= (cursorPos+3==txtAddr) && (rowscan >= cursorStart) && (rowscan <= cursorEnd);
|
|
|
VT151 ub2
|
VT151 ub2
|
(
|
(
|
.e_n(!blink_en),
|
.e_n(!blink_en),
|
.s(rBlink),
|
.s(rBlink),
|
.i0(1'b1), .i1(1'b0), .i2(bcnt[4]), .i3(bcnt[5]),
|
.i0(1'b1), .i1(1'b0), .i2(bcnt[4]), .i3(bcnt[5]),
|
.i4(1'b1), .i5(1'b0), .i6(bcnt[4]), .i7(bcnt[5]),
|
.i4(1'b1), .i5(1'b0), .i6(bcnt[4]), .i7(bcnt[5]),
|
.z(blink),
|
.z(blink),
|
.z_n()
|
.z_n()
|
);
|
);
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (ld_shft)
|
if (ld_shft)
|
bkColor32 <= {txtZorder1,2'b00,txtBkCode1[20:14],1'b0,txtBkCode1[13:7],1'b0,txtBkCode1[6:0],1'b0};
|
bkColor32 <= {txtZorder1,2'b00,txtBkCode1[20:14],1'b0,txtBkCode1[13:7],1'b0,txtBkCode1[6:0],1'b0};
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (nhp)
|
if (nhp)
|
bkColor32d <= bkColor32;
|
bkColor32d <= bkColor32;
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (ld_shft)
|
if (ld_shft)
|
fgColor32 <= {txtZorder1,2'b00,txtFgCode1[20:14],1'b0,txtFgCode1[13:7],1'b0,txtFgCode1[6:0],1'b0};
|
fgColor32 <= {txtZorder1,2'b00,txtFgCode1[20:14],1'b0,txtFgCode1[13:7],1'b0,txtFgCode1[6:0],1'b0};
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (nhp)
|
if (nhp)
|
fgColor32d <= fgColor32;
|
fgColor32d <= fgColor32;
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (ld_shft)
|
if (ld_shft)
|
bgt <= txtBkCode1==txtTcCode;
|
bgt <= txtBkCode1==txtTcCode;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (nhp)
|
if (nhp)
|
bgtd <= bgt;
|
bgtd <= bgt;
|
|
|
reg [63:0] charout1;
|
reg [63:0] charout1;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
charout1 <= blink ? (char_bmp ^ curout) : char_bmp;
|
charout1 <= blink ? (char_bmp ^ curout) : char_bmp;
|
|
|
// Convert parallel to serial
|
// Convert parallel to serial
|
ParallelToSerial ups1
|
ParallelToSerial ups1
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(vclk),
|
.clk(vclk),
|
.ce(nhp),
|
.ce(nhp),
|
.ld(ld_shft),
|
.ld(ld_shft),
|
.a(maxScanpix[5:3]),
|
.a(maxScanpix[5:3]),
|
.qin(1'b0),
|
.qin(1'b0),
|
.d(charout1),
|
.d(charout1),
|
.qh(pix)
|
.qh(pix)
|
);
|
);
|
|
|
// Pipelining Effect:
|
// Pipelining Effect:
|
// - character output is delayed by 2 or 3 character times relative to the video counters
|
// - character output is delayed by 2 or 3 character times relative to the video counters
|
// depending on the resolution selected
|
// depending on the resolution selected
|
// - this means we must adapt the blanking signal by shifting the blanking window
|
// - this means we must adapt the blanking signal by shifting the blanking window
|
// two or three character times.
|
// two or three character times.
|
always @(posedge vclk)
|
always @(posedge vclk)
|
if (nhp)
|
if (nhp)
|
iblank <= (row >= numRows) || (col >= numCols + charOutDelay) || (col < charOutDelay);
|
iblank <= (row >= numRows) || (col >= numCols + charOutDelay) || (col < charOutDelay);
|
|
|
wire bpix = hctr[2] ^ rowscan[4];// ^ blink;
|
wire bpix = hctr[2] ^ rowscan[4];// ^ blink;
|
|
|
// Choose between input RGB and controller generated RGB
|
// Choose between input RGB and controller generated RGB
|
// Select between foreground and background colours.
|
// Select between foreground and background colours.
|
// Note the ungated dot clock must be used here, or output from other
|
// Note the ungated dot clock must be used here, or output from other
|
// controllers would not be visible if the clock were gated off.
|
// controllers would not be visible if the clock were gated off.
|
always @(posedge dot_clk_i)
|
always @(posedge dot_clk_i)
|
casez({controller_enable&xonoff_i,blank_i,iblank,border_i,bpix,pix})
|
casez({controller_enable&xonoff_i,blank_i,iblank,border_i,bpix,pix})
|
6'b?1????: zrgb_o <= 32'h00000000;
|
6'b?1????: zrgb_o <= 32'h00000000;
|
6'b1001??: zrgb_o <= bdrColor;
|
6'b1001??: zrgb_o <= bdrColor;
|
//6'b10010?: zrgb_o <= 32'hFFBF2020;
|
//6'b10010?: zrgb_o <= 32'hFFBF2020;
|
//6'b10011?: zrgb_o <= 32'hFFDFDFDF;
|
//6'b10011?: zrgb_o <= 32'hFFDFDFDF;
|
6'b1000?0: zrgb_o <= ((zrgb_i[31:24] <= bkColor32d[31:24]) || bgtd) ? zrgb_i : bkColor32d;
|
6'b1000?0: zrgb_o <= ((zrgb_i[31:24] <= bkColor32d[31:24]) || bgtd) ? zrgb_i : bkColor32d;
|
6'b1000?1: zrgb_o <= fgColor32d; // ToDo: compare z-order
|
6'b1000?1: zrgb_o <= fgColor32d; // ToDo: compare z-order
|
// 6'b1010?0: zrgb_o <= bgtd ? zrgb_i : bkColor32d;
|
// 6'b1010?0: zrgb_o <= bgtd ? zrgb_i : bkColor32d;
|
// 6'b1010?1: zrgb_o <= fgColor32d;
|
// 6'b1010?1: zrgb_o <= fgColor32d;
|
default: zrgb_o <= zrgb_i;
|
default: zrgb_o <= zrgb_i;
|
endcase
|
endcase
|
|
|
endmodule
|
endmodule
|
|
|
|
|