30天自制操作系统day5(vram和显存)(GDT和IDT)(c语言结构体)(汇编-c)(ai辅助整理)
day5
harib02d
c语言结构体的一些解释
struct BOOTINFO {
char cyls, leds, vmode, reserve;
short scrnx, scrny;
char *vram;
};
//最开始的struct命令只是把一串变量声明集中起来,统一叫做“struct BOOTINFO”。
//最初是1字节的变量cyls,接着是1字节的变量leds,照此下去,最后是vram。这一
//串变量一共是12字节。
//定义一个结构体指针
struct BOOTINFO *binfo;
//为结构体指针赋初始值
binfo = (struct BOOTINFO *)0x0ff0;
//为结构体指针里的变量赋值
xsize = (*binfo).scrnx;//必须要写括号
//要不然会认为是(*binfo.scrnx)
//xsize = (*binfo).scrnx;”写成“xsize = binfo—>scrnx;
harib02e
关于汇编中变量内存地址到c语言结构体变量的连接
- 汇编代码设置内存布局 (
asmhead.nas
):
; 内存地址定义
CYLS EQU 0x0ff0 ; 柱面数
LEDS EQU 0x0ff1 ; 键盘LED状态
VMODE EQU 0x0ff2 ; 显示模式
SCRNX EQU 0x0ff4 ; 屏幕X分辨率
SCRNY EQU 0x0ff6 ; 屏幕Y分辨率
VRAM EQU 0x0ff8 ; 显存地址
- C代码对应结构体 (
bootpack.h
):
struct BOOTINFO { // 严格对应汇编中的内存布局char cyls; // 0x0ff0char leds; // 0x0ff1char vmode; // 0x0ff2char reserve;// 0x0ff3 (填充字节)short scrnx; // 0x0ff4-0x0ff5short scrny; // 0x0ff6-0x0ff7char* vram; // 0x0ff8-0x0ffb (32位指针)
}; // 共占用16字节 (0x0ff0-0x0fff)
- 地址强制映射:
#define ADR_BOOTINFO 0x00000ff0
// 通过强制类型转换将物理地址映射为结构体指针
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
这种硬编码的内存布局是早期操作系统开发中常见的硬件信息传递方式,通过汇编代码收集硬件参数后,C代码直接访问固定内存地址来获取信息。
主要就是地址强制映射
这个vram中的地址空间填入的数据和显示的关系
在这个代码中,vram
是显存的起始地址,显存用于存储屏幕上每个像素的颜色值。显存中的数据与屏幕上的显示内容直接相关,具体关系如下:
-
显存地址与屏幕像素的映射:
- 显存是一个线性地址空间,每个地址对应屏幕上的一个像素。
- 假设屏幕的分辨率为
scrnx x scrny
,显存的第一个字节(vram[0]
)对应屏幕左上角的第一个像素。 - 显存的第
y * scrnx + x
个字节对应屏幕上(x, y)
坐标的像素。
-
显存中的数据表示颜色:
- 每个字节存储一个颜色值,颜色值是一个索引,对应调色板中的颜色。
- 调色板通过
init_palette
和set_palette
函数初始化,将颜色索引映射到实际的 RGB 值。
-
绘制像素的过程:
-
通过直接操作显存,可以改变屏幕上对应像素的颜色。例如:这里,
c
是颜色索引,xsize
是屏幕的宽度,x
和y
是像素的坐标。vram[y * xsize + x] = c;
-
-
示例:绘制矩形:
boxfill8
函数通过遍历指定区域的像素坐标,将对应的显存地址填充为指定的颜色值,从而在屏幕上绘制矩形。
-
示例:显示字符:
putfont8
函数通过读取点阵字体数据,将字符的像素逐行写入显存,从而在屏幕上显示字符。
总结
显存中的数据直接决定屏幕上显示的内容。通过操作显存,可以控制屏幕上每个像素的颜色,从而实现图形绘制和字符显示等功能。
如何实现像素颜色更新
在这个代码中,像素颜色的更新是通过直接操作显存 (vram
) 来实现的。以下是实现像素颜色更新的步骤:
1. 确定像素的显存地址
显存是一个线性数组,每个字节对应屏幕上的一个像素。要更新某个像素的颜色,需要计算该像素在显存中的地址。
公式:
vram_address = vram + y * xsize + x;
vram
是显存的起始地址。xsize
是屏幕的宽度(像素数)。(x, y)
是像素的坐标。
2. 设置像素的颜色值
显存中的每个字节存储一个颜色索引值,该值对应调色板中的颜色。通过将颜色索引写入显存,可以更新像素的颜色。
示例代码:
vram[y * xsize + x] = color_index;
color_index
是颜色的索引值(如COL8_FFFFFF
表示白色)。
3. 示例:更新单个像素
假设要将屏幕上 (100, 50)
坐标的像素设置为白色:
vram[50 * scrnx + 100] = COL8_FFFFFF;
4. 示例:更新矩形区域
通过遍历矩形区域的每个像素,可以更新整个区域的颜色。例如,boxfill8
函数实现了矩形填充:
void boxfill8(unsigned char *vram, int xsize, unsigned char c,
int x0, int y0, int x1, int y1)
{
int x, y;
for (y = y0; y <= y1; y++) {
for (x = x0; x <= x1; x++) {
vram[y * xsize + x] = c; // 更新像素颜色
}
}
}
x0, y0
是矩形左上角坐标。x1, y1
是矩形右下角坐标。c
是颜色索引。
5. 示例:更新字符显示
通过点阵数据更新多个像素,可以显示字符。例如,putfont8
函数根据点阵数据逐行更新像素:
void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
int i;
char *p, d;
for (i = 0; i < 16; i++) { // 遍历字符的16行
p = vram + (y + i) * xsize + x; // 计算当前行的显存地址
d = font[i]; // 获取点阵数据
if ((d & 0x80) != 0) p[0] = c; // 更新每个像素
if ((d & 0x40) != 0) p[1] = c;
if ((d & 0x20) != 0) p[2] = c;
if ((d & 0x10) != 0) p[3] = c;
if ((d & 0x08) != 0) p[4] = c;
if ((d & 0x04) != 0) p[5] = c;
if ((d & 0x02) != 0) p[6] = c;
if ((d & 0x01) != 0) p[7] = c;
}
}
总结
像素颜色更新的核心是通过计算显存地址并写入颜色索引值来实现的。可以更新单个像素、矩形区域,甚至通过点阵数据更新字符显示。
找到具有 1 个许可证类型的类似代码 - 查看匹配项
(y + i) * xsize + x
在代码中,(y + i) * xsize + x
是用来计算显存中某个像素的地址偏移量的。以下是详细解释:
- 显存的二维布局
显存(vram
)是一个一维数组,但它实际上表示屏幕上的一个二维像素网格。
xsize
:屏幕的宽度(以像素为单位)。y
:当前字符的起始行位置(纵坐标)。x
:当前字符的起始列位置(横坐标)。
显存的布局可以看作是一个二维数组,像素 (x, y)
的地址在显存中可以通过以下公式计算:
地址偏移量 = y * xsize + x
其中:
y * xsize
表示第y
行的起始地址。x
表示第y
行中第x
列的偏移量。
- 逐行绘制字符
在 putfont8
函数中,字符的点阵数据是逐行绘制的:
for (i = 0; i < 16; i++) {p = vram + (y + i) * xsize + x;d = font[i];...
}
i
:当前绘制的行号(从 0 到 15,共 16 行)。y + i
:表示字符当前绘制的行在屏幕上的纵坐标。(y + i) * xsize
:计算当前行在显存中的起始地址。+ x
:加上横坐标x
,得到当前行中第一个像素的地址。
- 为什么表示像素坐标
(y + i) * xsize + x
的作用是将二维坐标 (x, y + i)
转换为显存中的一维地址偏移量:
y + i
:表示字符当前绘制的行在屏幕上的纵坐标。x
:表示字符在屏幕上的横坐标。xsize
:屏幕的宽度,用于将二维坐标映射到显存的一维地址。
显存的地址是线性排列的,因此需要通过行号乘以屏幕宽度(xsize
)来跳过前面的行,再加上列号(x
)来定位具体的像素。
- 示例
假设屏幕宽度 xsize = 320
,字符起始位置 (x, y) = (8, 8)
,当前绘制到字符的第 5 行(i = 4
):
(y + i) * xsize + x = (8 + 4) * 320 + 8 = 12 * 320 + 8 = 3848
显存中偏移量为 3848
的位置就是字符第 5 行第一个像素的地址。
- 总结
(y + i) * xsize + x
是通过屏幕的宽度(xsize
)和字符的起始位置 (x, y)
计算显存中像素的地址偏移量。它将二维坐标 (x, y + i)
转换为显存的一维地址,用于正确绘制字符的点阵数据到屏幕上。
sprintf和printf的区别
printf
和 sprintf
都是 C 标准库中的格式化输出函数,但它们的用途和行为有所不同:
printf
-
功能:将格式化的字符串输出到标准输出(通常是屏幕)。
-
原型:
int printf(const char *format, ...);
-
参数:
format
:格式化字符串。...
:可变参数,用于替换格式化字符串中的占位符。
-
返回值:成功时返回输出的字符数,失败时返回负值。
-
示例:
输出到屏幕:Hello, Alice! You are 25 years old.
printf("Hello, %s! You are %d years old.\\n", "Alice", 25);
sprintf
-
功能:将格式化的字符串写入到指定的字符数组中,而不是输出到屏幕。
-
原型:
int sprintf(char *str, const char *format, ...);
-
参数:
str
:目标字符数组,用于存储格式化后的字符串。format
:格式化字符串。...
:可变参数,用于替换格式化字符串中的占位符。
-
返回值:成功时返回写入的字符数(不包括终止符
\\0
),失败时返回负值。 -
示例:
输出到屏幕:Hello, Alice! You are 25 years old.
(字符串先写入buffer
,然后通过printf
输出)char buffer[50]; sprintf(buffer, "Hello, %s! You are %d years old.", "Alice", 25); printf("%s\\n", buffer);
- 主要区别
特性 | printf | sprintf |
---|---|---|
输出位置 | 标准输出(屏幕) | 字符数组 |
返回值 | 输出的字符数 | 写入的字符数(不包括 \\0 ) |
用途 | 用于直接显示信息 | 用于生成字符串供后续处理 |
安全性 | 不涉及缓冲区溢出 | 需要确保目标数组有足够的空间 |
- 注意事项
-
使用
sprintf
时,必须确保目标数组足够大以容纳格式化后的字符串,否则可能导致缓冲区溢出。 -
如果需要更安全的版本,可以使用
snprintf
,它允许指定目标数组的最大长度,避免溢出:snprintf(buffer, sizeof(buffer), "Hello, %s!", "Alice");
总结
printf
:直接输出到屏幕,适合显示信息。sprintf
:将格式化字符串写入数组,适合需要进一步处理字符串的场景。
自个总结
就是sprintf可以写入内存,然后后面自己决定如何处理
harib02i
GDT和IDT
分段和GDT
- 表示一个段
- 段的大小
- 段的起始地址
- 段的管理属性(禁止写入,禁止执行,系统专用等)
一共8个字节
- 段寄存器
- 低3位不可以用
- 一共13位,可以表示有8192个段
所以这些段要8192*865536个字节64kB
这个64kb存到内存里,称为GDT,是“global(segment)descriptor table”的缩写,意思是全局段号记录表
然后将这个内存的起始地址和有效设定个数放在CPU内称作GDTR(global (segment) descriptor table register)的特殊寄存器中
GDT 的用途
- 切换任务时加载不同的段。
- 定义内核和用户模式的分段。
- 配合 TSS(Task State Segment)实现任务切换。
IDT
IDT是“interrupt descriptor table”的缩写,中断记录表
IDT记录了0-255的中断号码和调用函数的对应关系,比如发生了123号中断,就调用0x函数
IDT 的用途
- 硬件中断:如键盘输入、鼠标移动、定时器中断。
- 软件中断:通过
int
指令触发。 - 异常处理:如非法指令、页错误等
相关文章:
30天自制操作系统day5(vram和显存)(GDT和IDT)(c语言结构体)(汇编-c)(ai辅助整理)
day5 harib02d c语言结构体的一些解释 struct BOOTINFO { char cyls, leds, vmode, reserve; short scrnx, scrny; char *vram; }; //最开始的struct命令只是把一串变量声明集中起来,统一叫做“struct BOOTINFO”。 //最初是1字节的变量cyls,接着是1字…...
【音频】drc 限幅器、多带限幅器、压缩器、多带压缩器
以下是关于 DRC 限幅器、多带限幅器、压缩器、多带压缩器的详细解释,它们均为音频处理领域的动态范围控制设备,主要用于调整音频信号的动态范围(即最大音量与最小音量的差值),以优化音质或满足特定播放需求: 一、DRC 限幅器(Dynamic Range Compression Limiter) 核心功…...

leetcode hot100刷题日记——12.反转链表
解答: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(n…...
osgEarth中视角由跟随模式切换到漫游模式后没有鼠标拖拽功能问题分析及解决方法
遇到了一个棘手的问题,就是在由跟随模式切换到漫游模式的时候,鼠标无法实现拖拽功能。后来发现是前面给自己挖的坑。 因为要实现鼠标点选某个模型后,模型需要变红色显示,所以添加了一个事件处理程序。 // 创建 场景中模型的点选功能 事件处理程序 ModelSelectionHandler* …...
STM32中断优先级分组有哪几种?
STM32中断优先级分组主要有以下5种: 分组0:所有16位用于子优先级,没有抢占优先级。此时可配置的子优先级为0~15,共16级,适用于系统中对中断实时性要求不高,且中断源较多,需要更多子优先级来区分不同中断的情况。分组1:最高1位用于抢占优先级,最低3位用于子优先级。可配…...

《Python语言程序设计》第4章第8题3个个位数之间比大小。‘a小于b而b大于c’这是最有漏洞的一个对比,请问我如何判断a和c
升序来做这个题 比如123就变成321 需要比对3个数 这不是比对2个数。a和b比对 我们可以直接写 if a>b: print(ab) else print(ba) 但是现在是3个数abc 如果进行if比对呢 if a > b >c: print(a,b,c) elif a < b >c: print(bca) … 简洁的代码变成了复杂的代码段。…...

Selenium 测试框架 - Python
🚀Selenium Python 实战指南:从入门到进阶 Selenium 是 Web 自动化测试中最受欢迎的工具之一,支持多种浏览器和语言。本文将从环境搭建到多浏览器兼容、测试框架集成、元素定位方式、常用操作、浏览器配置等多个方面进行详细讲解,并分享常见的最佳实践建议。 📦一、环境…...

RNN GRU LSTM 模型理解
一、RNN 1. 在RNN中, 二、GRU 1. GRU是为了解决RNN 梯度消失引入的改良模型, 2. GRU 通过门控 Gamma_r Gamma_u 两个变量,实现了对于过往记忆的筛选:这种机制使得GRU能够灵活地决定何时“忘记”过去的信息以及何时“记住”新的…...
AutoCompose - 携程自动编排原理 -【编排关系DAG的构建】
AutoCompose - 携程自动编排原理 -【编排关系DAG的构建】 前言一. Spring / SpringBoot 的兼容✅ spring.factories 文件🧩 特点📄 示例 ✅ META-INF/spring/ 目录下的文件(Spring Boot 2.4 新特性)🧩 特点Ὄ…...

【MC】红石比较器
在《我的世界》(Minecraft)中,红石比较器(Redstone Comparator) 是一种高级红石元件,主要用于 检测、比较或处理信号强度,同时还能与容器、特定方块互动。 红石比较器有两种模式: 比…...
危化品经营单位安全生产管理人员考试主要内容
危化品经营单位安全生产人员考试主要测试从业人员对危险化学品安全管理的专业知识和法规掌握程度。考试内容涵盖以下重点: 法律法规(30%) 重点考查《安全生产法》《危险化学品安全管理条例》等核心法规,以及经营许可、重大危险源…...
get_the_category() 和 get_the_terms() 的区别
get_the_category() 和 get_the_terms() 是WordPress中用于获取文章分类的两个函数,但它们之间存在一些关键差异: get_the_category() 特定于分类:get_the_category() 函数专门用于获取文章的分类(category)。它返回一个包含所有分类对象的…...

红黑树简单模拟实现
定义成员变量旋转insert以234树的角度来待插入操作具体代码 完整代码 我们前面实现了 二叉搜索树和 AVL树。 其中AVL树是二叉搜索树的改进,但是有些人觉得二叉树搜索的插入调整太频繁了,或者说平衡条件过于苛刻。 于是人们放松了左右子树高度差的限制&…...

豪越科技:消防应急装备智能仓储管理新变革
在消防救援工作中,消防装备无疑是消防员们与火灾等灾害顽强对抗的关键“武器”。然而,传统的消防装备管理模式长期以来饱受诸多痛点的困扰,严重影响着消防工作的高效开展和救援效果。 在过去,装备丢失的情况时有发生。由于缺乏有效…...

如何设计Agent的记忆系统
最近看了一张画Agent记忆分类的图 我觉得分类分的还可以,但是太浅了,于是就着它的逻辑,仔细得写了一下在不同的记忆层,该如何设计和选型 先从流程,作用,实力和持续时间的这4个维度来解释一下这几种记忆&am…...

毕业论文格式(Word)
目录 Word目录怎么自动生成?快速生成试试这3个方法! - 知乎https://zhuanlan.zhihu.com/p/692056836目录生成需要先设置标题样式,这个不仅是目录生成需要,和后续的图表也有关系。 最好不要自己创建新的样式,而是在现有…...

学习STC51单片机14(芯片为STC89C52RC)
接下来我们进入学会了HC—SR04 还有舵机那么现在我们将他们融合在一起,用超声波来引导舵机的转动 我们这个最后的成果是做一个智能垃圾桶 成品是这样的,是不是可有意思了 成品视频 现在我们将舵机的代码和超声波测距模块的代码整合到一起,实…...

基于CodeBuddy实现本地网速的实时浏览小工具
本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 在数字化浪潮席卷全球的今天,网络已成为人们生活和工作中不可或缺的基础设施。无论是在线办公、学习、娱乐,还是进行大数据传输和云计算&…...

stable diffusion论文解读
High-Resolution Image Synthesis with Latent Diffusion Models 论文背景 LDM是Stable Diffusion模型的奠基性论文 于2022年6月在CVPR上发表 传统生成模型具有局限性: 扩散模型(DM)通过逐步去噪生成图像,质量优于GAN&#x…...

计算机网络(3)——传输层
1.概述 1.1 传输层的服务和协议 (1)传输层为允许在不同主机(Host)上的进程提供了一种逻辑通信机制 (2)端系统(如手机、电脑)运行传输层协议 发送方:将来自应用层的消息进行封装并向下提交给 网络层接收方:将接收到的Segment进行组装并向上提交给应用层 …...

LangChain构建RAG的对话应用
目录 Langchain是什么? LangSmith是什么? 编辑 使用Python构建并使用AI大模型 数据解析器 提示模版 部署 记忆功能 Chat History -- 记忆 代码执行流程: 流式输出 构建向量数据库和检索器 检索器 代码执行流程 LLM使用检索器…...

目标检测DN-DETR(2022)详细解读
文章目录 gt labels 和gt boxes加噪query的构造attention maskIS(InStability)指标 在DAB-Detr的基础上,进一步分析了Detr收敛速度慢的原因:二分图匹配的不稳定性(也就是说它的目标在频繁地切换,特别是在训…...

嵌入式培训之系统编程(四)进程
一、进程的基本概念 (一)定义 进程是一个程序执行的过程(也可以说是正在运行的程序),会去分配内存资 源,cpu的调度,它是并发的 (二)PCB块 1、PCB是一个结构体&#x…...

天文数据处理:基于CUDA的射电望远镜图像实时去噪算法(开源FAST望远镜数据处理代码解析)
一、射电天文数据处理的挑战与CUDA加速的必要性 作为全球最大的单口径射电望远镜,中国天眼(FAST)每秒产生38GB原始观测数据,经预处理后生成数千万张图像。这些数据中蕴含的脉冲星、中性氢等天体信号常被高斯白噪声、射频干扰&…...

VS编码访问Mysql数据库
安装 MySQL Connector/C 的开发包 libmysqlcppconn-dev是 MySQL Connector/C 的开发包,它的主要用途是让 C 开发者能够方便地在应用程序中与 MySQL 数据库进行交互。它提供了以下功能: 数据库连接:通过标准的 C 接口连接到 MySQL 数据库。S…...

一周学会Pandas2 Python数据处理与分析-Pandas2数据合并与对比-pd.merge():数据库风格合并
锋哥原创的Pandas2 Python数据处理与分析 视频教程: 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili pd.merge():数据库风格合并 **核心功能**:基于列值(类似 SQL JOIN)合…...
leetcode 862. 和至少为 K 的最短子数组
这段代码使用了前缀和单调队列的组合策略来高效解决"和至少为K的最短子数组"问题。我将从问题定义、核心思路到代码实现逐步拆解: 问题定义 给定数组 nums 和整数 k,找到和 ≥k 的最短非空子数组,返回其长度。 示例:n…...

CodeBuddy 实现图片转素描手绘工具
本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 最近在社交媒体上,各种素描风格的图片火得一塌糊涂,身边不少朋友都在分享自己的 “素描照”,看着那些黑白线条勾勒出的独特韵味&a…...

3.8.2 利用RDD计算总分与平均分
在本次实战中,我们利用Spark的RDD完成了成绩文件的总分与平均分计算任务。首先,准备了包含学生成绩的文件并上传至HDFS。接着,通过交互式方式逐步实现了成绩的读取、解析、总分计算与平均分计算,并最终输出结果。此外,…...

29-FreeRTOS事件标志组
一、概述 事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。 即一个任务可以等待多个事件的发生࿱…...