qidao123.com技术社区-IT企服评测·应用市场

标题: 30天自制操作系统day5(vram和显存)(GDT和IDT)(c语言结构体)(汇编-c)(ai辅助整理) [打印本页]

作者: 铁佛    时间: 3 天前
标题: 30天自制操作系统day5(vram和显存)(GDT和IDT)(c语言结构体)(汇编-c)(ai辅助整理)
day5

harib02d


c语言结构体的一些表明

  1. struct BOOTINFO {
  2. char cyls, leds, vmode, reserve;
  3. short scrnx, scrny;
  4. char *vram;
  5. };
  6. //最开始的struct命令只是把一串变量声明集中起来,统一叫做“struct BOOTINFO”。
  7. //最初是1字节的变量cyls,接着是1字节的变量leds,照此下去,最后是vram。这一
  8. //串变量一共是12字节。
  9. //定义一个结构体指针
  10. struct BOOTINFO *binfo;
  11. //为结构体指针赋初始值
  12. binfo = (struct BOOTINFO *)0x0ff0;
  13. //为结构体指针里的变量赋值
  14. xsize = (*binfo).scrnx;//必须要写括号
  15. //要不然会认为是(*binfo.scrnx)
  16. //xsize = (*binfo).scrnx;”写成“xsize = binfo—>scrnx;
复制代码

harib02e

关于汇编中变量内存地址到c语言结构体变量的连接

  1. ; 内存地址定义
  2. CYLS    EQU     0x0ff0      ; 柱面数
  3. LEDS    EQU     0x0ff1      ; 键盘LED状态
  4. VMODE   EQU     0x0ff2      ; 显示模式
  5. SCRNX   EQU     0x0ff4      ; 屏幕X分辨率
  6. SCRNY   EQU     0x0ff6      ; 屏幕Y分辨率
  7. VRAM    EQU     0x0ff8      ; 显存地址
复制代码
  1. struct BOOTINFO { // 严格对应汇编中的内存布局
  2.     char  cyls;   // 0x0ff0
  3.     char  leds;   // 0x0ff1
  4.     char  vmode;  // 0x0ff2
  5.     char  reserve;// 0x0ff3 (填充字节)
  6.     short scrnx;  // 0x0ff4-0x0ff5
  7.     short scrny;  // 0x0ff6-0x0ff7
  8.     char* vram;   // 0x0ff8-0x0ffb (32位指针)
  9. }; // 共占用16字节 (0x0ff0-0x0fff)
复制代码
  1. #define ADR_BOOTINFO 0x00000ff0
  2. // 通过强制类型转换将物理地址映射为结构体指针
  3. struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
复制代码
这种硬编码的内存结构是早期操作系统开辟中常见的硬件信息通报方式,通过汇编代码收集硬件参数后,C代码直接访问固定内存地址来获取信息。
重要就是地址强制映射
这个vram中的地址空间填入的数据和表现的关系

在这个代码中,vram 是显存的起始地址,显存用于存储屏幕上每个像素的颜色值。显存中的数据与屏幕上的表现内容直接相干,详细关系如下:
总结
显存中的数据直接决定屏幕上表现的内容。通过操作显存,可以控制屏幕上每个像素的颜色,从而实现图形绘制和字符表现等功能。
怎样实现像素颜色更新

在这个代码中,像素颜色的更新是通过直接操作显存 (vram) 来实现的。以下是实现像素颜色更新的步骤:

1. 确定像素的显存地址
显存是一个线性数组,每个字节对应屏幕上的一个像素。要更新某个像素的颜色,须要计算该像素在显存中的地址。
公式:
vram_address = vram + y * xsize + x;


2. 设置像素的颜色值
显存中的每个字节存储一个颜色索引值,该值对应调色板中的颜色。通过将颜色索引写入显存,可以更新像素的颜色。
示例代码:
vram[y * xsize + x] = color_index;


3. 示例:更新单个像素
假设要将屏幕上 (100, 50) 坐标的像素设置为白色:
vram[50 * scrnx + 100] = COL8_FFFFFF;

4. 示例:更新矩形地区
通过遍历矩形地区的每个像素,可以更新整个地区的颜色。例如,boxfill8 函数实现了矩形填充:
  1. void boxfill8(unsigned char *vram, int xsize, unsigned char c,
  2. int x0, int y0, int x1, int y1)
  3. {
  4. int x, y;
  5. for (y = y0; y <= y1; y++) {
  6. for (x = x0; x <= x1; x++) {
  7. vram[y * xsize + x] = c; // 更新像素颜色
  8. }
  9. }
  10. }
复制代码


5. 示例:更新字符表现
通过点阵数据更新多个像素,可以表现字符。例如,putfont8 函数根据点阵数据逐行更新像素:
  1. void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
  2. {
  3. int i;
  4. char *p, d;
  5. for (i = 0; i < 16; i++) { // 遍历字符的16行
  6. p = vram + (y + i) * xsize + x; // 计算当前行的显存地址
  7. d = font[i]; // 获取点阵数据
  8. if ((d & 0x80) != 0) p[0] = c; // 更新每个像素
  9. if ((d & 0x40) != 0) p[1] = c;
  10. if ((d & 0x20) != 0) p[2] = c;
  11. if ((d & 0x10) != 0) p[3] = c;
  12. if ((d & 0x08) != 0) p[4] = c;
  13. if ((d & 0x04) != 0) p[5] = c;
  14. if ((d & 0x02) != 0) p[6] = c;
  15. if ((d & 0x01) != 0) p[7] = c;
  16. }
  17. }
复制代码

总结
像素颜色更新的核心是通过计算显存地址并写入颜色索引值来实现的。可以更新单个像素、矩形地区,甚至通过点阵数据更新字符表现。
找到具有 1 个许可证类型的类似代码 - 查看匹配项
(y + i) * xsize + x

在代码中,(y + i) * xsize + x 是用来计算显存中某个像素的地址偏移量的。以下是详细表明:

显存(vram)是一个一维数组,但它实际上表示屏幕上的一个二维像素网格。

显存的结构可以看作是一个二维数组,像素 (x, y) 的地址在显存中可以通过以下公式计算:
  1. 地址偏移量 = y * xsize + x
复制代码
此中:


在 putfont8 函数中,字符的点阵数据是逐行绘制的:
  1. for (i = 0; i < 16; i++) {
  2.     p = vram + (y + i) * xsize + x;
  3.     d = font[i];
  4.     ...
  5. }
复制代码


(y + i) * xsize + x 的作用是将二维坐标 (x, y + i) 转换为显存中的一维地址偏移量:

显存的地址是线性分列的,因此须要通过行号乘以屏幕宽度(xsize)来跳过前面的行,再加上列号(x)来定位详细的像素。

假设屏幕宽度 xsize = 320,字符起始位置 (x, y) = (8, 8),当前绘制到字符的第 5 行(i = 4):
  1. (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 标准库中的格式化输出函数,但它们的用途和行为有所差别:




特性printfsprintf输出位置标准输出(屏幕)字符数组返回值输出的字符数写入的字符数(不包罗 \\0)用途用于直接表现信息用于生成字符串供后续处置惩罚安全性不涉及缓冲区溢出须要确保目标数组有充足的空间


总结

自个总结
就是sprintf可以写入内存,然后背面自己决定怎样处置惩罚


harib02i


GDT和IDT

分段和GDT

一共8个字节

所以这些段要8192*865536个字节64kB
这个64kb存到内存里,称为GDT,是“global(segment)descriptor table”的缩写,意思是全局段号记录表
然后将这个内存的起始地址和有用设定个数放在CPU内称作GDTR(global (segment) descriptor table register)的特别寄存器中
GDT 的用途

IDT
IDT是“interrupt descriptor table”的缩写,中断记录表
IDT记录了0-255的中断号码和调用函数的对应关系,好比发生了123号中断,就调用0x函数
IDT 的用途


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4