feat(saolei): 显存扩成每格 2 字节 + 内置 A-Z 字模;开始界面加文字、难度选择和黑背景
显示(RTL) - cpu21_vga.v:显存从"每格 1 字节"改成"每格 2 字节"(第 1 字节是 6 位字形、 第 2 字节是 3 位颜色),字地址由 cidx[10:2] 改为 cidx[10:1](1 字 = 2 格); 字模表由 4 位扩到 6 位(0..63),新增 A-Z 大写字母(16..41),原 0..15 的 数字/雷/旗/问号/横线/实心字形不变 - cpu21_mmio.v:显存窗口 0x2000-0x27FF -> 0x2000-0x2FFF(300 -> 600 字), fb_widx 相应取 addr_i[11:2] - cpu21_board_top.v:FB_WORDS 300 -> 600(1200 -> 2400 字节) 软件 - mmio.h:fb_write() -> fb_write_cell(idx, glyph, color)(一格写两个 sb); 删掉 CELL(),新增 G_A..G_Z 字形常量 - saolei.c:draw_cell / clear_screen 改用 fb_write_cell;开始界面显示 MINES / EASY / NORMAL / HARD / START 文字(START 直接写在绿色按钮条上), 不再是"两排雷图案 + 纯色条" - 难度选择:新增 g_difficulty / g_mines,三档 20 / 40 / 60 雷;place_mines、 胜利用的 opened_cnt 比较、toggle_flag 的剩余雷数都改读 g_mines;点难度那一行 即切换并重画菜单,点 START 才把雷数交给关卡 - 全部索引运算仍只用移位/掩码(棋盘固定 16x16),没有引入除法 配色(修"数字 1 看不见") - 数字 1 用 C_BLUE、游戏背景原来也是 C_BLUE,调色板里是同一个深蓝,所以数字 1 完全看不见;现在菜单与关卡背景统一改成 C_BLACK,胜负闪动仍是绿/红/黑, 数字本身的配色不动 工具与文档 - build.ps1:Python 启动器兼容 —— 有 py 用 py,没有就回退到 python (本机只有 python,之前 check_isa.py / elf2hex.py 两处都会中断) - saolei/README.md:显存表(0x2000-0x2FFF、每格 2 字节)、格子编码(6 位字形、 16..41 是 A-Z)、难度说明同步更新 - README.md / cpu21_board_top.v:仅格式化工具重排(Markdown 表格对齐、 if/else 合并成一行),无语义变化 验证:build.ps1 全流程通过(972 条指令 ISA 检查全过;text=3888 B / data=0 / bss=1444 B;入口 _start=0x0、isr1/2/3=0x100/0x200/0x300);xvlog 不带宏与带 SAOLEI_ROM 两种配置编译均无错;tools/check_rtl_text.ps1 体检 OK。 未验证:未跑行为仿真、未上板。
This commit is contained in:
+264
-174
@@ -4,7 +4,7 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// cpu21_vga —— 640x480@60 的"格子"显示控制器(显存端口接板级顶层的双口 RAM)。
|
||||
//
|
||||
// CPU 不直接操作像素:它只通过 MMIO 往显示缓冲区里写"每格 1 字节"(字形 + 颜色),
|
||||
// CPU 不直接操作像素:它只通过 MMIO 往显示缓冲区里写"每格 2 字节"(字形 + 颜色),
|
||||
// 本模块按像素扫描把格子展开成画面(8x8 字模放大 2 倍填满 16x16 的格子)。
|
||||
// 这样一格只要 1 次字节写,刷屏开销极小。
|
||||
//
|
||||
@@ -18,218 +18,308 @@
|
||||
// (CTRL[0] 控制显示与否)。缓冲区字节的 bit7 在本模块中不使用(保留)。
|
||||
// -----------------------------------------------------------------------------
|
||||
module cpu21_vga #(
|
||||
parameter integer H_VISIBLE = 640,
|
||||
parameter integer H_FP = 16,
|
||||
parameter integer H_SYNC = 96,
|
||||
parameter integer H_BP = 48,
|
||||
parameter integer V_VISIBLE = 480,
|
||||
parameter integer V_FP = 10,
|
||||
parameter integer V_SYNC = 2,
|
||||
parameter integer V_BP = 33,
|
||||
parameter integer COLS = 40,
|
||||
parameter integer ROWS = 30
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
input wire tick, // 25 MHz 像素使能(每 2 个 clk 一拍)
|
||||
// 显示缓冲区读端口
|
||||
output wire [ 9:0] fb_raddr_o,
|
||||
input wire [31:0] fb_word_i,
|
||||
// 控制
|
||||
input wire [31:0] ctrl_i,
|
||||
input wire [31:0] cursor_i,
|
||||
// VGA 输出
|
||||
output reg [ 3:0] vga_r,
|
||||
output reg [ 3:0] vga_g,
|
||||
output reg [ 3:0] vga_b,
|
||||
output reg vga_hs,
|
||||
output reg vga_vs,
|
||||
output reg frame_tick_o
|
||||
);
|
||||
parameter integer H_VISIBLE = 640,
|
||||
parameter integer H_FP = 16,
|
||||
parameter integer H_SYNC = 96,
|
||||
parameter integer H_BP = 48,
|
||||
parameter integer V_VISIBLE = 480,
|
||||
parameter integer V_FP = 10,
|
||||
parameter integer V_SYNC = 2,
|
||||
parameter integer V_BP = 33,
|
||||
parameter integer COLS = 40,
|
||||
parameter integer ROWS = 30
|
||||
) (
|
||||
input wire clk,
|
||||
input wire reset,
|
||||
input wire tick, // 25 MHz 像素使能(每 2 个 clk 一拍)
|
||||
// 显示缓冲区读端口
|
||||
output wire [ 9:0] fb_raddr_o,
|
||||
input wire [31:0] fb_word_i,
|
||||
// 控制
|
||||
input wire [31:0] ctrl_i,
|
||||
input wire [31:0] cursor_i,
|
||||
// VGA 输出
|
||||
output reg [ 3:0] vga_r,
|
||||
output reg [ 3:0] vga_g,
|
||||
output reg [ 3:0] vga_b,
|
||||
output reg vga_hs,
|
||||
output reg vga_vs,
|
||||
output reg frame_tick_o
|
||||
);
|
||||
|
||||
localparam integer H_TOTAL = H_VISIBLE + H_FP + H_SYNC + H_BP; // 800
|
||||
localparam integer V_TOTAL = V_VISIBLE + V_FP + V_SYNC + V_BP; // 525
|
||||
localparam integer H_TOTAL = H_VISIBLE + H_FP + H_SYNC + H_BP; // 800
|
||||
localparam integer V_TOTAL = V_VISIBLE + V_FP + V_SYNC + V_BP; // 525
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 扫描计数
|
||||
// ---------------------------------------------------------------------------
|
||||
reg [9:0] hx, vy;
|
||||
// ---------------------------------------------------------------------------
|
||||
// 扫描计数
|
||||
// ---------------------------------------------------------------------------
|
||||
reg [9:0] hx, vy;
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
hx <= 10'd0;
|
||||
vy <= 10'd0;
|
||||
end
|
||||
else if (tick) begin
|
||||
if (hx == H_TOTAL - 1) begin
|
||||
hx <= 10'd0;
|
||||
vy <= (vy == V_TOTAL - 1) ? 10'd0 : (vy + 10'd1);
|
||||
end
|
||||
else begin
|
||||
hx <= hx + 10'd1;
|
||||
end
|
||||
end
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
hx <= 10'd0;
|
||||
vy <= 10'd0;
|
||||
end else if (tick) begin
|
||||
if (hx == H_TOTAL - 1) begin
|
||||
hx <= 10'd0;
|
||||
vy <= (vy == V_TOTAL - 1) ? 10'd0 : (vy + 10'd1);
|
||||
end else begin
|
||||
hx <= hx + 10'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire de = (hx < H_VISIBLE) && (vy < V_VISIBLE);
|
||||
wire de = (hx < H_VISIBLE) && (vy < V_VISIBLE);
|
||||
|
||||
// 同步信号在 tick 上寄存输出
|
||||
wire hs_n = ~((hx >= (H_VISIBLE + H_FP)) && (hx < (H_VISIBLE + H_FP + H_SYNC)));
|
||||
wire vs_n = ~((vy >= (V_VISIBLE + V_FP)) && (vy < (V_VISIBLE + V_FP + V_SYNC)));
|
||||
// 同步信号在 tick 上寄存输出
|
||||
wire hs_n = ~((hx >= (H_VISIBLE + H_FP)) && (hx < (H_VISIBLE + H_FP + H_SYNC)));
|
||||
wire vs_n = ~((vy >= (V_VISIBLE + V_FP)) && (vy < (V_VISIBLE + V_FP + V_SYNC)));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 格子索引与缓冲区读出
|
||||
// ---------------------------------------------------------------------------
|
||||
wire [5:0] ccol = hx[9:4]; // 0..39
|
||||
wire [4:0] crow = vy[8:4]; // 0..29
|
||||
wire [10:0] cidx = (crow << 5) + (crow << 3) + ccol; // row*40 + col
|
||||
// ---------------------------------------------------------------------------
|
||||
// 格子索引与缓冲区读出
|
||||
// ---------------------------------------------------------------------------
|
||||
wire [5:0] ccol = hx[9:4]; // 0..39
|
||||
wire [4:0] crow = vy[8:4]; // 0..29
|
||||
wire [10:0] cidx = (crow << 5) + (crow << 3) + ccol; // row*40 + col
|
||||
|
||||
assign fb_raddr_o = cidx[10:2]; // 字地址(1 字 = 4 格)
|
||||
assign fb_raddr_o = cidx[10:1]; // 字地址(1 字 = 2 格)
|
||||
|
||||
wire [1:0] lane = cidx[1:0];
|
||||
wire [31:0] cell_word = fb_word_i;
|
||||
wire [7:0] cell_byte = cell_word >> {lane, 3'b000};
|
||||
wire [ 1:0] lane = {cidx[0], 1'b0};
|
||||
wire [ 1:0] color_lane = lane + 2'd1;
|
||||
wire [31:0] cell_word = fb_word_i;
|
||||
wire [ 7:0] glyph_byte = cell_word >> {lane, 3'b000};
|
||||
wire [ 7:0] color_byte = cell_word >> {color_lane, 3'b000};
|
||||
|
||||
wire [3:0] glyph = cell_byte[3:0];
|
||||
wire [2:0] gcolor = cell_byte[6:4];
|
||||
// 全局背景色(字模点为 0 时显示的颜色)
|
||||
wire [2:0] bgcolor = ctrl_i[7:4];
|
||||
wire [ 5:0] glyph = glyph_byte[5:0];
|
||||
wire [ 2:0] gcolor = color_byte[2:0];
|
||||
// 全局背景色(字模点为 0 时显示的颜色)
|
||||
wire [ 2:0] bgcolor = ctrl_i[7:4];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 8x8 字模(bit7 = 最左像素),放大 2 倍填满 16x16 的格子
|
||||
// ---------------------------------------------------------------------------
|
||||
wire [2:0] fx = hx[3:1];
|
||||
wire [2:0] fy = vy[3:1];
|
||||
// ---------------------------------------------------------------------------
|
||||
// 8x8 字模(bit7 = 最左像素),放大 2 倍填满 16x16 的格子;字形编号 0..63。
|
||||
// ---------------------------------------------------------------------------
|
||||
wire [ 2:0] fx = hx[3:1];
|
||||
wire [ 2:0] fy = vy[3:1];
|
||||
|
||||
function [7:0] font_row;
|
||||
input [3:0] g;
|
||||
input [2:0] r;
|
||||
begin
|
||||
case (g)
|
||||
4'd0:
|
||||
font_row = 8'h00; // 空白
|
||||
4'd1:
|
||||
font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h38 : (r == 3'd2) ? 8'h18 :
|
||||
function [7:0] font_row;
|
||||
input [5:0] g;
|
||||
input [2:0] r;
|
||||
begin
|
||||
case (g)
|
||||
6'd0: font_row = 8'h00; // 空白
|
||||
6'd1:
|
||||
font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h38 : (r == 3'd2) ? 8'h18 :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 :
|
||||
(r == 3'd6) ? 8'h7E : 8'h00; // 1
|
||||
4'd2:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
6'd2:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
(r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h30 :
|
||||
(r == 3'd6) ? 8'h7E : 8'h00; // 2
|
||||
4'd3:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
6'd3:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
(r == 3'd3) ? 8'h1C : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // 3
|
||||
4'd4:
|
||||
font_row = (r == 3'd0) ? 8'h0C : (r == 3'd1) ? 8'h1C : (r == 3'd2) ? 8'h3C :
|
||||
6'd4:
|
||||
font_row = (r == 3'd0) ? 8'h0C : (r == 3'd1) ? 8'h1C : (r == 3'd2) ? 8'h3C :
|
||||
(r == 3'd3) ? 8'h6C : (r == 3'd4) ? 8'h7E : (r == 3'd5) ? 8'h0C :
|
||||
(r == 3'd6) ? 8'h0C : 8'h00; // 4
|
||||
4'd5:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h7C :
|
||||
6'd5:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h7C :
|
||||
(r == 3'd3) ? 8'h06 : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // 5
|
||||
4'd6:
|
||||
font_row = (r == 3'd0) ? 8'h1C : (r == 3'd1) ? 8'h30 : (r == 3'd2) ? 8'h60 :
|
||||
6'd6:
|
||||
font_row = (r == 3'd0) ? 8'h1C : (r == 3'd1) ? 8'h30 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // 6
|
||||
4'd7:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h0C :
|
||||
6'd7:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h0C :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 :
|
||||
(r == 3'd6) ? 8'h18 : 8'h00; // 7
|
||||
4'd8:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
6'd8:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h3C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // 8
|
||||
4'd9:
|
||||
font_row = (r == 3'd0) ? 8'hFF : (r == 3'd1) ? 8'h81 : (r == 3'd2) ? 8'hBD :
|
||||
6'd9:
|
||||
font_row = (r == 3'd0) ? 8'hFF : (r == 3'd1) ? 8'h81 : (r == 3'd2) ? 8'hBD :
|
||||
(r == 3'd3) ? 8'hA5 : (r == 3'd4) ? 8'hA5 : (r == 3'd5) ? 8'hBD :
|
||||
(r == 3'd6) ? 8'h81 : 8'hFF; // 未揭开的方块
|
||||
4'd10:
|
||||
font_row = (r == 3'd0) ? 8'h40 : (r == 3'd1) ? 8'h70 : (r == 3'd2) ? 8'h78 :
|
||||
6'd10:
|
||||
font_row = (r == 3'd0) ? 8'h40 : (r == 3'd1) ? 8'h70 : (r == 3'd2) ? 8'h78 :
|
||||
(r == 3'd3) ? 8'h70 : (r == 3'd4) ? 8'h40 : (r == 3'd5) ? 8'h40 :
|
||||
(r == 3'd6) ? 8'h40 : 8'h00; // 旗
|
||||
4'd11:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h7E : (r == 3'd2) ? 8'hFF :
|
||||
6'd11:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h7E : (r == 3'd2) ? 8'hFF :
|
||||
(r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : (r == 3'd5) ? 8'hFF :
|
||||
(r == 3'd6) ? 8'h7E : 8'h3C; // 雷
|
||||
4'd12:
|
||||
font_row = (r == 3'd0) ? 8'h81 : (r == 3'd1) ? 8'h42 : (r == 3'd2) ? 8'h24 :
|
||||
6'd12:
|
||||
font_row = (r == 3'd0) ? 8'h81 : (r == 3'd1) ? 8'h42 : (r == 3'd2) ? 8'h24 :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h24 :
|
||||
(r == 3'd6) ? 8'h42 : 8'h81; // 爆炸
|
||||
4'd13:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
6'd13:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h06 :
|
||||
(r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h00 :
|
||||
(r == 3'd6) ? 8'h18 : 8'h00; // 问号
|
||||
4'd14:
|
||||
font_row = (r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : 8'h00; // 横线
|
||||
4'd15:
|
||||
font_row = 8'hFF; // 实心
|
||||
default:
|
||||
font_row = 8'h00;
|
||||
endcase
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire [7:0] frow = font_row(glyph, fy);
|
||||
wire glyph_px = frow[3'd7 - fx]; // 1 = 画字模点
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 光标框:黄色、常亮、2 像素宽
|
||||
// 原来是 1 像素浅灰 + 闪动(blink 周期约 1.3 s):在白色未揭开格上几乎看不清,
|
||||
// 而且截图有一半概率正好截到"灭"的那个相位。改成黄色常亮 2 像素后,
|
||||
// VGA 上和图里都能一眼看到指针。想改回闪动:把 blink_q 加回来,
|
||||
// 再在 cursor_box 里与上 blink 即可。
|
||||
// ---------------------------------------------------------------------------
|
||||
wire cursor_here = (cursor_i[4:0] == ccol) && (cursor_i[12:8] == crow);
|
||||
wire on_border = (hx[3:0] < 4'd2) || (hx[3:0] > 4'd13) ||
|
||||
(vy[3:0] < 4'd2) || (vy[3:0] > 4'd13);
|
||||
wire cursor_box = cursor_here && ctrl_i[0] && on_border;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 颜色(3 位调色板 -> 4:4:4 RGB)
|
||||
// ---------------------------------------------------------------------------
|
||||
function [11:0] pal;
|
||||
input [2:0] c;
|
||||
begin
|
||||
case (c)
|
||||
3'd0:
|
||||
pal = {4'h0, 4'h0, 4'h0}; // 黑
|
||||
3'd1:
|
||||
pal = {4'h0, 4'h0, 4'hA}; // 深蓝
|
||||
3'd2:
|
||||
pal = {4'h0, 4'hA, 4'h0}; // 绿
|
||||
3'd3:
|
||||
pal = {4'h0, 4'hA, 4'hA}; // 青
|
||||
3'd4:
|
||||
pal = {4'hA, 4'h0, 4'h0}; // 红
|
||||
3'd5:
|
||||
pal = {4'hA, 4'h0, 4'hA}; // 洋红
|
||||
3'd6:
|
||||
pal = {4'hA, 4'hA, 4'h0}; // 黄
|
||||
default:
|
||||
pal = {4'hA, 4'hA, 4'hA}; // 浅灰
|
||||
endcase
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire [2:0] px_color = glyph_px ? gcolor : bgcolor;
|
||||
wire [2:0] px_final = cursor_box ? 3'd6 : px_color; // 6 = 黄,光标框
|
||||
wire [11:0] px_rgb = de ? pal(px_final) : 12'h000;
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
{vga_r, vga_g, vga_b} <= 12'h000;
|
||||
vga_hs <= 1'b1;
|
||||
vga_vs <= 1'b1;
|
||||
frame_tick_o <= 1'b0;
|
||||
end
|
||||
else if (tick) begin
|
||||
{vga_r, vga_g, vga_b} <= px_rgb;
|
||||
vga_hs <= hs_n;
|
||||
vga_vs <= vs_n;
|
||||
frame_tick_o <= (hx == H_TOTAL - 1) && (vy == V_TOTAL - 1);
|
||||
end
|
||||
6'd14: font_row = (r == 3'd3) ? 8'hFF : (r == 3'd4) ? 8'hFF : 8'h00; // 横线
|
||||
6'd15: font_row = 8'hFF; // 实心
|
||||
6'd16:
|
||||
font_row = (r == 3'd0) ? 8'h18 : (r == 3'd1) ? 8'h3C : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h7E : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // A
|
||||
6'd17:
|
||||
font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h7C : 8'h00; // B
|
||||
6'd18:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h60 : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // C
|
||||
6'd19:
|
||||
font_row = (r == 3'd0) ? 8'h78 : (r == 3'd1) ? 8'h6C : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h6C :
|
||||
(r == 3'd6) ? 8'h78 : 8'h00; // D
|
||||
6'd20:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 :
|
||||
(r == 3'd6) ? 8'h7E : 8'h00; // E
|
||||
6'd21:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 :
|
||||
(r == 3'd6) ? 8'h60 : 8'h00; // F
|
||||
6'd22:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h6E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3E : 8'h00; // G
|
||||
6'd23:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h7E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // H
|
||||
6'd24:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h18 : (r == 3'd2) ? 8'h18 :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // I
|
||||
6'd25:
|
||||
font_row = (r == 3'd0) ? 8'h1E : (r == 3'd1) ? 8'h0C : (r == 3'd2) ? 8'h0C :
|
||||
(r == 3'd3) ? 8'h0C : (r == 3'd4) ? 8'h0C : (r == 3'd5) ? 8'h6C :
|
||||
(r == 3'd6) ? 8'h38 : 8'h00; // J
|
||||
6'd26:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h6C : (r == 3'd2) ? 8'h78 :
|
||||
(r == 3'd3) ? 8'h70 : (r == 3'd4) ? 8'h78 : (r == 3'd5) ? 8'h6C :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // K
|
||||
6'd27:
|
||||
font_row = (r == 3'd0) ? 8'h60 : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h60 : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 :
|
||||
(r == 3'd6) ? 8'h7E : 8'h00; // L
|
||||
6'd28:
|
||||
font_row = (r == 3'd0) ? 8'h63 : (r == 3'd1) ? 8'h77 : (r == 3'd2) ? 8'h7F :
|
||||
(r == 3'd3) ? 8'h6B : (r == 3'd4) ? 8'h63 : (r == 3'd5) ? 8'h63 :
|
||||
(r == 3'd6) ? 8'h63 : 8'h00; // M
|
||||
6'd29:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h76 : (r == 3'd2) ? 8'h7E :
|
||||
(r == 3'd3) ? 8'h6E : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // N
|
||||
6'd30:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // O
|
||||
6'd31:
|
||||
font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h60 : (r == 3'd5) ? 8'h60 :
|
||||
(r == 3'd6) ? 8'h60 : 8'h00; // P
|
||||
6'd32:
|
||||
font_row = (r == 3'd0) ? 8'h3C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h6E : (r == 3'd5) ? 8'h3C :
|
||||
(r == 3'd6) ? 8'h0E : 8'h00; // Q
|
||||
6'd33:
|
||||
font_row = (r == 3'd0) ? 8'h7C : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h7C : (r == 3'd4) ? 8'h78 : (r == 3'd5) ? 8'h6C :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // R
|
||||
6'd34:
|
||||
font_row = (r == 3'd0) ? 8'h3E : (r == 3'd1) ? 8'h60 : (r == 3'd2) ? 8'h60 :
|
||||
(r == 3'd3) ? 8'h3C : (r == 3'd4) ? 8'h06 : (r == 3'd5) ? 8'h06 :
|
||||
(r == 3'd6) ? 8'h7C : 8'h00; // S
|
||||
6'd35:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h18 : (r == 3'd2) ? 8'h18 :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 :
|
||||
(r == 3'd6) ? 8'h18 : 8'h00; // T
|
||||
6'd36:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h3C : 8'h00; // U
|
||||
6'd37:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h66 :
|
||||
(r == 3'd3) ? 8'h66 : (r == 3'd4) ? 8'h66 : (r == 3'd5) ? 8'h3C :
|
||||
(r == 3'd6) ? 8'h18 : 8'h00; // V
|
||||
6'd38:
|
||||
font_row = (r == 3'd0) ? 8'h63 : (r == 3'd1) ? 8'h63 : (r == 3'd2) ? 8'h63 :
|
||||
(r == 3'd3) ? 8'h6B : (r == 3'd4) ? 8'h7F : (r == 3'd5) ? 8'h77 :
|
||||
(r == 3'd6) ? 8'h63 : 8'h00; // W
|
||||
6'd39:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h3C :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h3C : (r == 3'd5) ? 8'h66 :
|
||||
(r == 3'd6) ? 8'h66 : 8'h00; // X
|
||||
6'd40:
|
||||
font_row = (r == 3'd0) ? 8'h66 : (r == 3'd1) ? 8'h66 : (r == 3'd2) ? 8'h3C :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h18 : (r == 3'd5) ? 8'h18 :
|
||||
(r == 3'd6) ? 8'h18 : 8'h00; // Y
|
||||
6'd41:
|
||||
font_row = (r == 3'd0) ? 8'h7E : (r == 3'd1) ? 8'h06 : (r == 3'd2) ? 8'h0C :
|
||||
(r == 3'd3) ? 8'h18 : (r == 3'd4) ? 8'h30 : (r == 3'd5) ? 8'h60 :
|
||||
(r == 3'd6) ? 8'h7E : 8'h00; // Z
|
||||
default: font_row = 8'h00;
|
||||
endcase
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire [7:0] frow = font_row(glyph, fy);
|
||||
wire glyph_px = frow[3'd7-fx]; // 1 = 画字模点
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 光标框:黄色、常亮、2 像素宽
|
||||
// 原来是 1 像素浅灰 + 闪动(blink 周期约 1.3 s):在白色未揭开格上几乎看不清,
|
||||
// 而且截图有一半概率正好截到"灭"的那个相位。改成黄色常亮 2 像素后,
|
||||
// VGA 上和图里都能一眼看到指针。想改回闪动:把 blink_q 加回来,
|
||||
// 再在 cursor_box 里与上 blink 即可。
|
||||
// ---------------------------------------------------------------------------
|
||||
wire cursor_here = (cursor_i[4:0] == ccol) && (cursor_i[12:8] == crow);
|
||||
wire on_border = (hx[3:0] < 4'd2) || (hx[3:0] > 4'd13) || (vy[3:0] < 4'd2) || (vy[3:0] > 4'd13);
|
||||
wire cursor_box = cursor_here && ctrl_i[0] && on_border;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 颜色(3 位调色板 -> 4:4:4 RGB)
|
||||
// ---------------------------------------------------------------------------
|
||||
function [11:0] pal;
|
||||
input [2:0] c;
|
||||
begin
|
||||
case (c)
|
||||
3'd0: pal = {4'h0, 4'h0, 4'h0}; // 黑
|
||||
3'd1: pal = {4'h0, 4'h0, 4'hA}; // 深蓝
|
||||
3'd2: pal = {4'h0, 4'hA, 4'h0}; // 绿
|
||||
3'd3: pal = {4'h0, 4'hA, 4'hA}; // 青
|
||||
3'd4: pal = {4'hA, 4'h0, 4'h0}; // 红
|
||||
3'd5: pal = {4'hA, 4'h0, 4'hA}; // 洋红
|
||||
3'd6: pal = {4'hA, 4'hA, 4'h0}; // 黄
|
||||
default: pal = {4'hA, 4'hA, 4'hA}; // 浅灰
|
||||
endcase
|
||||
end
|
||||
endfunction
|
||||
|
||||
wire [ 2:0] px_color = glyph_px ? gcolor : bgcolor;
|
||||
wire [ 2:0] px_final = cursor_box ? 3'd6 : px_color; // 6 = 黄,光标框
|
||||
wire [11:0] px_rgb = de ? pal(px_final) : 12'h000;
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
{vga_r, vga_g, vga_b} <= 12'h000;
|
||||
vga_hs <= 1'b1;
|
||||
vga_vs <= 1'b1;
|
||||
frame_tick_o <= 1'b0;
|
||||
end else if (tick) begin
|
||||
{vga_r, vga_g, vga_b} <= px_rgb;
|
||||
vga_hs <= hs_n;
|
||||
vga_vs <= vs_n;
|
||||
frame_tick_o <= (hx == H_TOTAL - 1) && (vy == V_TOTAL - 1);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
Reference in New Issue
Block a user