- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发操作系统作为个人爱好,以便我可以学习软件工程和计算机体系结构。
当文本到达底部或 VGA_HEIGHT 时,我试图让 VGA 终端“滚动”。我将 OSDev wiki 中的代码与我自己的代码混合使用。
我的目标是复制每一行,然后将其写入其正上方的行。
这是我正在使用的代码:
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(c, color);
}
void terminal_putchar(char c) {
unsigned char uc = c;
switch(c) {
case NEWLINE:
terminal_row++;
terminal_column = 0;
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
update_cursor(terminal_column + 1, terminal_row);
break;
case '\t':
/* TODO: Implement tab */
terminal_column += 4;
break;
default:
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
update_cursor(terminal_column + 1, terminal_row);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
terminal_row = 0;
}
}
if(terminal_row >= VGA_HEIGHT) {
terminal_print_error();
terminal_buffer[(15 * VGA_WIDTH) + 15] = terminal_buffer[(0 * VGA_WIDTH) + 4];
size_t i, j;
for(i = 0; i < VGA_WIDTH-1; i++) {
for(j = VGA_HEIGHT-2; j > 0; j--)
terminal_buffer[(j * VGA_WIDTH) + i] = terminal_buffer[((j+1) * VGA_WIDTH) + i];
}
}
}
if(terminal_row >= VGA_HEIGHT) {
terminal_print_error();
terminal_buffer[(15 * VGA_WIDTH) + 15] = terminal_buffer[(0 * VGA_WIDTH) + 4];
size_t i, j;
for(i = 0; i < VGA_WIDTH-1; i++) {
for(j = VGA_HEIGHT-2; j > 0; j--)
terminal_buffer[(j * VGA_WIDTH) + i] = terminal_buffer[((j+1) * VGA_WIDTH) + i];
}
}
/*
* This is the screen driver. It contains functions which print
* characters and colors to the screen
* using the VGA controller.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <kernel/tty.h>
#include "vga.h"
#define REG_SCREEN_CTRL 0x3D4
#define REG_SCREEN_DATA 0x3D5
#define NEWLINE 0x0A
#define TAB 0x09
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
static uint16_t *const VGA_MEMORY = (uint16_t *)0xC03FF000;
static size_t terminal_row;
static size_t terminal_column;
static uint8_t terminal_color;
static uint16_t *terminal_buffer;
int get_offset(int col, int row) {
return 2 * (row * VGA_WIDTH + col);
}
int get_offset_row(int offset) {
return offset / (2 * VGA_WIDTH);
}
int get_offset_col(int offset) {
return (offset - (get_offset_row(offset) * 2 * VGA_WIDTH)) / 2;
}
static void scroll() {
if(terminal_row >= VGA_HEIGHT) {
}
}
void terminal_print_error(void) {
if(terminal_row >= VGA_HEIGHT) {
terminal_row = 0;
/* print white/red E to bottom right corner of screen */
terminal_putentryat('E', vga_entry_color(VGA_COLOR_RED, VGA_COLOR_WHITE),
VGA_WIDTH - 1, VGA_HEIGHT - 1);
}
}
void terminal_initialize(void) {
terminal_row = 0;
terminal_column = 0;
terminal_color = vga_entry_color(VGA_COLOR_BLACK, VGA_COLOR_CYAN);
terminal_buffer = VGA_MEMORY;
for (size_t y = 0; y < VGA_HEIGHT; y++) {
for (size_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(' ', terminal_color);
}
}
}
void terminal_setcolor(uint8_t color) {
terminal_color = color;
}
void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y) {
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = vga_entry(c, color);
}
void terminal_putchar(char c) {
unsigned char uc = c;
switch(c) {
case NEWLINE:
terminal_row++;
terminal_column = 0;
terminal_putentryat(' ', terminal_color, terminal_column, terminal_row);
update_cursor(terminal_column + 1, terminal_row);
break;
case '\t':
/* TODO: Implement tab */
terminal_column += 4;
break;
default:
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
update_cursor(terminal_column + 1, terminal_row);
if (++terminal_column == VGA_WIDTH) {
terminal_column = 0;
if (++terminal_row == VGA_HEIGHT)
terminal_row = 0;
}
}
if(terminal_row >= VGA_HEIGHT) {
terminal_print_error();
terminal_buffer[(15 * VGA_WIDTH) + 15] = terminal_buffer[(0 * VGA_WIDTH) + 4];
size_t i, j;
for(i = 0; i < VGA_WIDTH-1; i++) {
for(j = VGA_HEIGHT-2; j > 0; j--)
terminal_buffer[(j * VGA_WIDTH) + i] = terminal_buffer[((j+1) * VGA_WIDTH) + i];
}
}
}
void terminal_write(const char *data, size_t size) {
for (size_t i = 0; i < size; i++)
terminal_putchar(data[i]);
}
void terminal_writestring(const char *data) {
terminal_write(data, strlen(data));
}
/* inb */
unsigned char port_byte_in(unsigned short port) {
unsigned char result;
asm ("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
void port_byte_out(unsigned short port, unsigned char data) {
asm ("out %%al, %%dx" : : "a" (data), "d" (port));
}
int get_cursor_offset() {
/* Use the VGA ports to get the current cursor position
* 1. Ask for high byte of the cursor offset (data 14)
* 2. Ask for low byte (data 15)
*/
port_byte_out(REG_SCREEN_CTRL, 14);
int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
port_byte_out(REG_SCREEN_CTRL, 15);
offset += port_byte_in(REG_SCREEN_DATA);
return offset * 2; /* Position * size of character cell */
}
void set_cursor_offset(int offset) {
/* Similar to get_cursor_offset, but instead of reading we write data */
offset /= 2;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
}
void update_cursor(int x, int y) {
uint16_t pos = y * VGA_WIDTH + x;
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (uint8_t)(pos & 0xFF));
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (uint8_t)(pos >> 8) & 0xFF);
}
/*
void enable_cursor(uint8_t cursor_start, uint8_t cursor_end) {
outb(0x3D4, 0x0A);
outb(0x3D, (inb(0x3D5) & 0xC0) | cursor_start);
outb(0x3D4, 0x0B);
outb(0x3D5, (inb(0x3D5) & 0xE0) | cursor_end);
}
*/
最佳答案
我相信循环滚动的工作大部分是正确的,但是在它导致您遇到的一些错误之前有很多代码。
当光标宽度超过屏幕右边缘时,switch 语句中的默认情况是增加光标行。 if (++terminal_row == VGA_HEIGHT)
如果行增量超过屏幕的底部边缘,则将光标行重置为 0。这可以防止滚动代码永远运行。您应该删除 if (++terminal_row == VGA_HEIGHT) terminal_row = 0;
并替换为 terminal_row++;
因为紧跟在 switch 之后的逻辑处理终端行变量。
我建议分离修改 terminal_row
的逻辑和 terminal_column
来自验证、重置和滚动这些变量的逻辑。例如,您对 '\t' 字符的处理,如果放在一行的最后 3 个字符内,会将字符溢出到下一行而不更新 terminal_row
和 terminal_column
vars 到他们应该在的地方。
terminal_putentryat
在将光标修改为换行符之后,而不是之前。事实上,你不应该这样做terminal_putentryat
对于任何换行符,因为明显没有字符改变,只有光标位置。 \t
的处理方式调用 terminal_write(' ');
而不是直接修改列变量。这简化了实际更新终端的逻辑。上面的第二段详细介绍了此更改解决的一些问题。 update_cursor()
应该只调用一次,在 terminal_putchar()
结束时因为你输入的每个字符都应该更新游标。如果您愿意,这可能会改变 terminal_putchar()
处理 0 宽度的字符,但这对我来说似乎违反直觉,因为此函数专门用于处理显示的字符。 terminal_row >= VGA_HEIGHT
从不将 terminal_row 重置为有效值。它确实调用了 terminal_print_error()
但是当您想将行保留在底部时,此函数会将您的行重置为 0。void terminal_putchar(char c) {
unsigned char uc = c;
// Handle character output and terminal_row/column modification
switch(c) {
case NEWLINE:
terminal_row++;
terminal_column = 0;
break;
case '\t':
terminal_write(' ');
break;
default:
terminal_putentryat(uc, terminal_color, terminal_column, terminal_row);
terminal_column++;
}
// Handle validation on terminal_column before terminal_row, since the logic in terminal_column can update terminal_row
if(terminal_column >= VGA_WIDTH) {
terminal_column = 0;
terminal_row++;
}
// Handle validating terminal_row, and scrolling the screen upwards if necessary.
if(terminal_row >= VGA_HEIGHT) {
// You shouldn't need terminal_print_error() since you are handling the case where terminal_row >= VGA_HEIGHT
// terminal_print_error();
// What does this line do? Appears to set the 16th character of the 16th row to the same value as the 5th character of the 1st row.
// terminal_buffer[(15 * VGA_WIDTH) + 15] = terminal_buffer[(0 * VGA_WIDTH) + 4];
size_t i, j;
for(i = 0; i < VGA_WIDTH-1; i++) {
for(j = VGA_HEIGHT-2; j > 0; j--) {
terminal_buffer[(j * VGA_WIDTH) + i] = terminal_buffer[((j+1) * VGA_WIDTH) + i];
}
}
// Also clear out the bottom row
for(i = 0; i < VGA_WIDTH-1; i++) {
terminal_putentryat(' ', terminal_color, i, VGA_HEIGHT-1);
}
terminal_row = VGA_HEIGHT-1;
}
update_cursor(terminal_column, terminal_row);
}
关于gcc - OSDev:为什么我的 VGA 终端滚动不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53128322/
我有一个简单的函数,可以在 DOS 框中使用 djgpp 和 256 VGA 在 c 中使用内联汇编来绘制像素: byte *VGA = (byte *)0xA0000; void plot_pi
我正在尝试使用 C 在 256 色 VGA 上创建一个简单的图像编辑器(如绘画)。现在我正在努力在屏幕上绘制圆圈。我遇到的问题是,当圆圈比屏幕大时,不应该绘制的部分出现在屏幕的另一侧。我有一个 if
我正在尝试在 DOSBox 的汇编程序中设置 VGA(640x480x16) 调色板,但特别是颜色 6、8-F 不会改变。我试过使用中断和直接通过端口都适用于其他颜色但不适用于那些颜色。我在默认配置上
是否可以通过 VGA 连接器镜像屏幕?找不到任何关于此的内容。 最佳答案 我一直在寻找和你一样的东西。上周末我写了一个小的 UIApplication 类别来添加镜像支持。我在 Google Code
我正在用 rltk 构建一个简单的游戏。 8x8 简单字体可以正常工作,但是当我尝试将其更改为内置 8x16 VGA 字体时,它会像这样拉伸(stretch)和移动字体: 我像这样初始化窗口: fn
我目前正在为 x86 开发内核(只是为了好玩)。我正在尝试实现一个相当有用的早期控制台,以报告驱动程序的加载情况,并允许我在需要时在引导期间使用内存,使用位于 0xB8000 的 80x25 字符 V
有没有一种方法可以使用 Python 脚本检测外接显示器何时插入 Ubuntu Linux 中的 VGA 端口?我应该使用 xrandr 还是 monitor a UDEV message 进行轮询?
我正在尝试编写一个函数,使用 VGA 文本模式缓冲区将消息打印到屏幕上。这是打印单个字符的函数: void putc(uint8_t c, enum Color term_color) { u
我正在开发一个操作系统作为一个业余项目。我使用地址 0xB8000 连接 VGA 显示器,行数设置为 25,列数设置为 80。我使用了以下清屏功能: void vga_init(void) {
我正在开发一种功能,可以在 256 VGA 模式的视频模式下绘制角色。我使用 6x7 字体,该字体集仅包含大写字母、数字和符号。这是数据: uint8_t characters[455] = {
我正在开发操作系统作为个人爱好,以便我可以学习软件工程和计算机体系结构。 当文本到达底部或 VGA_HEIGHT 时,我试图让 VGA 终端“滚动”。我将 OSDev wiki 中的代码与我自己的代码
我做了简单的代码,应该写入VGA内存。 org 07c00h mov eax,0xb8000 mov bx,msg call printstr printstr: mov al,byt
我使用了所有示例和源代码来将应用程序内容显示到外部 VGA 显示器。在应用程序内部播放视频时,外部设备中出现以下情况。有什么建议......我错过了一些东西......但在设备中它以良好的方式显示实际
1我在 DosBox 0.74 上用 TASM 3.0 写,我想用 Mode x 写(Tweaked 13h, unchained mode 13 ),我遇到了一个问题,你如何在图像中看到,每一行都被
就是这样,我想知道是否有人拔掉显示器插头并采取一些行动,知道吗?谢谢 最佳答案 我自己没有尝试过,但我认为您可以监听 WM_DEVICECHANGE 并检查 System.Windows.Forms.
我正在使用 NASM 来学习 x86 汇编,在 linux 上的 qemu 中运行我的代码。 我正在尝试在屏幕上绘制一个像素。 为什么是这样 mov bx,0xA000 mov byte [b
早在 199[456] 年,我就在使用 Linux 和 Matrox 图形适配器。对于编程,我经常使用 text mode 并且懒得启动到 X11。这些图形卡允许非常高的文本分辨率,并且仍然具有非常易
我正在寻找“Linux VGA 捕获卡”,它可以从远程计算机捕获 VGA 输入,这样我就可以使用 V4L2 捕获源。请推荐一些。 最佳答案 Datapath 声誉良好,并且支持 Linux: http
我正在尝试获得一个简单的 Hello World!内核启动。每当我打开我的虚拟机时,我都会看到 GRUB 加载,选择我的操作系统,然后在屏幕上出现一个随机字符,并因三重故障而崩溃。我认为问题出在我的
因此,我们得到了一些图形技巧,需要在没有真正视频卡的情况下在服务器环境中运行。它真正需要的只是帧缓冲区对象和一些矢量/字体抗锯齿。它会很慢,我知道。它只需要输出单帧。 我看到 this发布有关如何强制
我是一名优秀的程序员,十分优秀!