前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VM技术(二)从CHIP8入手CPU的模拟(三)

VM技术(二)从CHIP8入手CPU的模拟(三)

作者头像
Pulsar-V
发布2019-08-02 09:34:13
6010
发布2019-08-02 09:34:13
举报
文章被收录于专栏:Pulsar-VPulsar-V

显示器的实现

前面提到CHIP8的显示器是64x32黑白像素的显示器,所以我们在QT中定义一个OpenGL的Wedgit显示到窗口中,同时把keymap和游戏循环设置在主窗体的timmer循环中。

Monitor64x32.h

代码语言:javascript
复制
//
// Created by Pulsar on 2019/7/18.
//

#ifndef EASYMVM_MONITOR16X16_H
#define EASYMVM_MONITOR16X16_H

#include <sys/time.h>
#include <iostream>
#include <QtWidgets>
#include <QMainWindow>
#include <QtCore>
#include <QTimer>
#include <CHIP8.h>
#include "Monitor64x32GL.h"
#include "ui_Monitor64x32.h"

namespace Ui {
    class Monitor64x32;
}
class Monitor64x32 : public QMainWindow {
Q_OBJECT
public:
    struct timeval clock_prev;

    Monitor64x32(QWidget *parent = 0);

    void link_cpu(CHIP8 &chip8);
    int keymap(unsigned char k);

    void keyPressEvent(QKeyEvent *event);


    int timediff_ms(struct timeval *end, struct timeval *start);


    void keyReleaseEvent(QKeyEvent *event);


    ~Monitor64x32();

private  slots:

    void paint_screen();


    void timeout_sc();

signals:
    void draw_pixel(int row, int col, float color);
    void repaint_screen();

private:
    CHIP8 cpu;
    Monitor64x32GL *glwindow;
    void paint_pixel(int row, int col, unsigned char color);
    void paint_cell(int row, int col, unsigned char color);

};

Monitor64x32.cpp

代码语言:javascript
复制
//
// Created by Pulsar on 2019/7/18.
//

#include <Monitor64x32.h>

void Monitor64x32::link_cpu(CHIP8 &cip8) {
    this->cpu = cip8;
}

Monitor64x32::Monitor64x32(QWidget *parent) : QMainWindow(parent) {
    QTimer *timer = new QTimer(this); //定时器
    timer->start(10);


    glwindow = new Monitor64x32GL(this);//设置绘制界面
    setCentralWidget(glwindow);//设置OpenGL界面到主窗体
    glwindow->setMinimumSize(640, 320);//设置屏幕最大值
    this->setMaximumSize(640, 320);////设置主窗体大小最小值

    connect(timer, SIGNAL(timeout()), this, SLOT(timeout_sc()));
    connect(glwindow, SIGNAL(paintGL()), this, SLOT(paint_screen()));
    connect(this, SIGNAL(repaint_screen()), glwindow, SLOT(repaint()));
    connect(this, SIGNAL(draw_pixel(int, int, float)), glwindow,
            SLOT(paint_pixel(int, int, float))); // 链接绘制函数和OpenGL界面的绘制函数
}
//绘制像素
void Monitor64x32::paint_cell(int row, int col, unsigned char color) {
    int pixel_row = row * PIXEL_SIZE;
    int pixel_col = col * PIXEL_SIZE;
    int drow, dcol;

    for (drow = 0; drow < PIXEL_SIZE; drow++) {
        for (dcol = 0; dcol < PIXEL_SIZE; dcol++) {
            paint_pixel(pixel_row + drow, pixel_col + dcol, color);
        }
    }
}
//绘制像素到屏幕
void Monitor64x32::paint_pixel(int row, int col, unsigned char color) {
    row = cpu.screen_rows - 1 - row;
    cpu.screen[row][col][0] = cpu.screen[row][col][1] = cpu.screen[row][col][2] = color;
}
//绘图函数
void Monitor64x32::paint_screen() {
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    for (int row = 0; row < GFX_ROWS; row++) {
        for (int col = 0; col < GFX_COLS; col++) {
            paint_cell(row, col, cpu.gfx[row][col] ? WHITE : BLACK);
        }
    }

    glDrawPixels(SCREEN_COLS, SCREEN_ROWS, GL_RGB, GL_UNSIGNED_BYTE,
                 (void *) cpu.screen);
    glPixelZoom(2, 2);
}
//按键按下事件
void Monitor64x32::keyPressEvent(QKeyEvent *event) {
    unsigned char k = event->key();
    int index = keymap(k);
    if (index >= 0) cpu.setkeys(index, 1);
}

int Monitor64x32::keymap(unsigned char k) {
    switch (k) {
        case '1':
            return 0x1;
        case '2':
            return 0x2;
        case '3':
            return 0x3;
        case '4':
            return 0xc;

        case 'Q':
            return 0x4;
        case 'W':
            return 0x5;
        case 'E':
            return 0x6;
        case 'R':
            return 0xd;

        case 'A':
            return 0x7;
        case 'S':
            return 0x8;
        case 'D':
            return 0x9;
        case 'F':
            return 0xe;

        case 'Z':
            return 0xa;
        case 'X':
            return 0x0;
        case 'C':
            return 0xb;
        case 'V':
            return 0xf;

        default:
            return -1;
    }
}
//按键释放事件
void Monitor64x32::keyReleaseEvent(QKeyEvent *event) {
    unsigned char k = event->key();

    int index = keymap(k);
    if (index >= 0) cpu.setkeys(index, 0);
}


Monitor64x32::~Monitor64x32() {
    delete glwindow;
}
//定时器超时事件
void Monitor64x32::timeout_sc() {
    struct timeval clock_now;
    gettimeofday(&clock_now, NULL);

    cpu.runCycle();

    if (cpu.draw_flag) {
        repaint_screen();
        cpu.draw_flag = false;
    }
    if (timediff_ms(&clock_now, &clock_prev) >= cpu.clock_rate_ms) {
        cpu.tick();
        clock_prev = clock_now;
    }
};

//分频器
int Monitor64x32::timediff_ms(struct timeval *end, struct timeval *start) {
    int diff = (end->tv_sec - start->tv_sec) * 1000 +
               (end->tv_usec - start->tv_usec) / 1000;
    //printf("timediff = %d\n", diff);
    return diff;
}

接下来是OpenGL显示器

Monitor64x32GL.h

代码语言:javascript
复制
//
// Created by Pulsar on 2019/7/18.
//

#ifndef EASYMVM_MONITOR64X32GL_H
#define EASYMVM_MONITOR64X32GL_H

#include <GL/gl.h>
#include <GL/glu.h>
#include<QOpenGLWidget>
#include <QWidget>
#include <QtCore/qglobal.h>


class   Monitor64x32GL : public QOpenGLWidget {
    Q_OBJECT
public:
    Monitor64x32GL(QWidget *parent = nullptr);

    void initializeGL();



    void paint_cell(int row, int col, unsigned char color);


    void resizeGL(int width, int height);

    virtual ~Monitor64x32GL();

signals:
    void paintGL();


public slots:
    void paint_pixel(int row, int col, float color);


private:
    int PIXEL_SIZE_SC;//像素大小
    int SCREEN_ROWS_SC;//屏幕行数
    int SCREEN_COLS_SC;//屏幕列数
};
#endif //EASYMVM_MONITOR64X32_GL_H

Monitor64x32GL.cpp

代码语言:javascript
复制
//
// Created by Pulsar on 2019/7/18.
//

#ifndef EASYMVM_MONITOR64X32_GL_H
#define EASYMVM_MONITOR64X32_GL_H

#include <GL/gl.h>
#include <GL/glu.h>
#include<QOpenGLWidget>
#include <iostream>
#include <Monitor64x32GL.h>

#endif //EASYMVM_MONITOR64X32_GL_H

Monitor64x32GL::Monitor64x32GL(QWidget *parent) : QOpenGLWidget(parent) {

}
//清屏
void Monitor64x32GL::initializeGL() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
}



void Monitor64x32GL::resizeGL(int width, int height) {
    gluPerspective(45.0, (GLfloat) width / (GLfloat) height, 0.1, 100);
    glLoadIdentity();
}

//绘制像素点
void Monitor64x32GL::paint_pixel(int row, int col, float color) {
    float screen_row_width = 1.0 / 64.0 * 2;
    float screen_col_width = 1.0 / 32.0 * 2;
    glColor3f(color / 255.0, color / 255.0, color / 255.0);
    glBegin(GL_QUADS);
    glVertex2f(screen_row_width * col, -screen_col_width * row);
    glVertex2f(screen_row_width * col, -screen_col_width * (row + 1.0));
    glVertex2f(screen_row_width * (col + 1.0), -screen_col_width * (row + 1.0));
    glVertex2f(screen_row_width * (col + 1.0), -screen_col_width * row);
    glEnd();
}

void Monitor64x32GL::paint_cell(int row, int col, unsigned char color) {
    int pixel_row = row * PIXEL_SIZE_SC;
    int pixel_col = col * PIXEL_SIZE_SC;
    int drow, dcol;
//下面这段注释的过程用来观察对像素的绘制是否正常
//    for (drow = 0; drow < PIXEL_SIZE_SC; drow++) {
//        for (dcol = 0; dcol < PIXEL_SIZE_SC; dcol++) {
//            paint_pixel(pixel_row + drow, pixel_col + dcol, color);
//        }
//    }
}

Monitor64x32GL::~Monitor64x32GL() {

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Monitor64x32.h
  • Monitor64x32.cpp
  • Monitor64x32GL.h
  • Monitor64x32GL.cpp
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档