add support for NEMU

This commit is contained in:
Chen Lu 2022-02-19 19:43:01 +08:00 committed by Zihao Yu
parent 131f308ca1
commit 7f20619e00
9 changed files with 286 additions and 6 deletions

View File

@ -72,9 +72,11 @@ public:
virtual void update_gui();
virtual void update_state();
};
#ifdef MODE_NEMU
void init_components(SDL_Renderer *renderer, uint32_t* vmem, int MODE800x600);
#else
void init_components(SDL_Renderer *renderer);
#endif
void delete_components();
#define GET_SEGA(i) (output_pin(int(output_pin::SEG0A) + 8 * i))

View File

@ -34,4 +34,6 @@
//#define VSYNC
#define MODE_NEMU
#endif

View File

@ -32,6 +32,7 @@ class KEYBOARD : public Component{
KEYBOARD(SDL_Renderer *rend, int cnt, int init_val, int it, int ct);
~KEYBOARD();
void push_key(uint8_t scancode, bool is_keydown);
uint8_t pop_key(bool* succ);
virtual void update_state();
};

View File

@ -2,10 +2,43 @@
#define VFPGA_RENDER_H
#include <SDL2/SDL.h>
#include <vga.h>
#include <configs.h>
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#ifdef MODE_NEMU
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define SWITCH_X 100
#define SWITCH_Y 400
#define SWITCH_SEP 10
#define SWITCH_WIDTH 20
#define SWITCH_HEIGHT 40
#define BTNC_X 650
#define BTNC_Y 200
#define BTNC_SEP 20
#define BTNC_WIDTH 20
#define BTNC_HEIGHT 20
#define LED_X 105
#define LED_Y 360
#define LED_SEP 20
#define LED_WIDTH 10
#define LED_HEIGHT 4
#define SEG_X 100
#define SEG_Y 240
#define SEG_VER_WIDTH 2
#define SEG_VER_HEIGHT 40
#define SEG_HOR_WIDTH 40
#define SEG_HOR_HEIGHT 2
#define SEG_DOT_WIDTH SEG_VER_WIDTH
#define SEG_DOT_HEIGHT SEG_HOR_HEIGHT
#else
#define WINDOW_WIDTH VGA_DEFAULT_WIDTH
#define WINDOW_HEIGHT VGA_DEFAULT_HEIGHT
#define SWITCH_X 80
#define SWITCH_Y 400
#define SWITCH_SEP 10
@ -33,6 +66,8 @@
#define SEG_HOR_HEIGHT 2
#define SEG_DOT_WIDTH SEG_VER_WIDTH
#define SEG_DOT_HEIGHT SEG_HOR_HEIGHT
#endif
#define SEG_SEP 2

View File

@ -4,12 +4,13 @@
#include <component.h>
#include <constrs.h>
#include <SDL2/SDL.h>
#include <nvboard.h>
#define VGA_DEFAULT_WIDTH 640
#define VGA_DEFAULT_HEIGHT 480
enum { //VGA_MOD_ID
VGA_MODE_640_480, NR_VGA_MODE
VGA_MODE_640_480, VGA_MODE_800_600, NR_VGA_MODE
};
struct VGA_MODE{
@ -25,7 +26,11 @@ private:
int vga_pre_clk, vga_pre_vsync, vga_pre_hsync;
int vga_vaddr, vga_haddr;
public:
#ifdef MODE_NEMU
VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct, uint32_t* vmem, int MODE800x600);
#else
VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct);
#endif
~VGA();
virtual void update_gui();

View File

@ -157,6 +157,114 @@ SDL_Rect operator+(const SDL_Rect &A, const SDL_Rect &B) {
SDL_Texture *segs_texture(int index, int val);
#ifdef MODE_NEMU
void init_components(SDL_Renderer *renderer, uint32_t* vmem, int MODE800x600) {
Component *ptr = nullptr;
SDL_Rect *rect_ptr = nullptr;
// init buttons
for (int i = 0; i < 6; ++i) {
ptr = new Component(renderer, 2, 0, INPUT_TYPE, BUTTON_TYPE);
// off
rect_ptr = new SDL_Rect;
*rect_ptr = btn_rects[i];
ptr->set_rect(rect_ptr, 0);
ptr->set_texture(tbutton_off, 0);
// on
rect_ptr = new SDL_Rect;
*rect_ptr = btn_rects[i];
ptr->set_rect(rect_ptr, 1);
ptr->set_texture(tbutton_on, 1);
ptr->add_input(input_pin(int(input_pin::BTNC) + i));
components.push_back(ptr);
}
// init switches
for (int i = 0; i < 16; ++i) {
ptr = new Component(renderer, 2, 0, INPUT_TYPE, SWICTH_TYPE);
// off
rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){SWITCH_X + (15 - i) * (SWITCH_WIDTH + SWITCH_SEP), SWITCH_Y, SWITCH_WIDTH, SWITCH_HEIGHT};
ptr->set_rect(rect_ptr, 0);
ptr->set_texture(tswitch_off, 0);
// on
rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){SWITCH_X + (15 - i) * (SWITCH_WIDTH + SWITCH_SEP), SWITCH_Y, SWITCH_WIDTH, SWITCH_HEIGHT};
ptr->set_rect(rect_ptr, 1);
ptr->set_texture(tswitch_on, 1);
ptr->add_input(input_pin(int(input_pin::SW0) + i));
components.push_back(ptr);
}
// init naive leds
for (int i = 0; i < 16; ++i) {
ptr = new Component(renderer, 2, 0, OUTPUT_TYPE, NAIVE_LED_TYPE);
// off
rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){LED_X + (15 - i) * (LED_WIDTH + LED_SEP), LED_Y, LED_WIDTH, LED_HEIGHT};
ptr->set_rect(rect_ptr, 0);
ptr->set_texture(tled_off, 0);
// on
rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){LED_X + (15 - i) * (LED_WIDTH + LED_SEP), LED_Y, LED_WIDTH, LED_HEIGHT};
ptr->set_rect(rect_ptr, 1);
ptr->set_texture(tled_g, 1);
ptr->add_output(output_pin(int(output_pin::LD0) + i));
components.push_back(ptr);
}
// init 7-segment display
for (int i = 0; i < 8; ++i) {
SDL_Rect mv = {(7 - i) * (SEG_HOR_WIDTH + SEG_DOT_WIDTH + SEG_SEP * 4), 0, 0, 0};
ptr = new SEGS7(renderer, 16, 0x5555, OUTPUT_TYPE, SEGS7_TYPE);
for (int j = 0; j < 8; ++j) {
rect_ptr = new SDL_Rect;
*rect_ptr = mv + segs_rect[j];
ptr->set_texture(segs_texture(j, 0), j << 1 | 0);
ptr->set_rect(rect_ptr, j << 1 | 0);
rect_ptr = new SDL_Rect;
*rect_ptr = mv + segs_rect[j];
ptr->set_texture(segs_texture(j, 1), j << 1 | 1);
ptr->set_rect(rect_ptr, j << 1 | 1);
}
for (output_pin p = GET_SEGA(i); p <= GET_DECP(i); p = output_pin(int(p) + 1)) {
ptr->add_output(p);
}
components.push_back(ptr);
}
#ifdef VGA_ENA
// init vga
ptr = new VGA(renderer, 1, 0, OUTPUT_TYPE, VGA_TYPE, vmem, MODE800x600);
rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){WINDOW_WIDTH, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
ptr->set_rect(rect_ptr, 0);
for (output_pin p = output_pin::VGA_CLK; p <= output_pin::VGA_B7; p = output_pin(int(p) + 1)) {
ptr->add_output(p);
}
components.push_back(ptr);
#endif
// init keyboard
extern KEYBOARD* kb;
kb = new KEYBOARD(renderer, 0, 0, INPUT_TYPE, KEYBOARD_TYPE);
for (input_pin p = input_pin::PS2_CLK; p <= input_pin::PS2_DAT; p = input_pin(int(p) + 1)){
kb->add_input(p);
}
// components.push_back(kb);
}
#else
void init_components(SDL_Renderer *renderer) {
Component *ptr = nullptr;
SDL_Rect *rect_ptr = nullptr;
@ -263,6 +371,7 @@ void init_components(SDL_Renderer *renderer) {
// components.push_back(kb);
}
#endif
void delete_components() {
for (auto comp_ptr : components) {

View File

@ -31,6 +31,10 @@ KEYBOARD::KEYBOARD(SDL_Renderer *rend, int cnt, int init_val, int it, int ct):
void KEYBOARD::push_key(uint8_t sdl_key, bool is_keydown){
#ifdef MODE_NEMU
all_keys.push(sdl_key);
all_keys.push(is_keydown);
#else
uint8_t at_key = sdl2at(sdl_key, 1);
if(at_key == 0xe0){
all_keys.push(0xe0);
@ -38,8 +42,14 @@ void KEYBOARD::push_key(uint8_t sdl_key, bool is_keydown){
}
if(!is_keydown) all_keys.push(0x0f);
all_keys.push(at_key);
#endif
}
#ifdef MODE_NEMU
void KEYBOARD::update_state(){
}
#else
void KEYBOARD::update_state(){
if(cur_key == NOT_A_KEY){
if(all_keys.empty()) return;
@ -68,4 +78,16 @@ void KEYBOARD::update_state(){
else{
left_clk --;
}
}
#endif
uint8_t KEYBOARD::pop_key(bool* succ){
if(all_keys.empty()) {
*succ = false;
return 0;
}
*succ = true;
uint8_t top = all_keys.front();
all_keys.pop();
return top;
}

View File

@ -78,6 +78,73 @@ static void nvboard_update_all_output() {
}
}
#ifdef MODE_NEMU
extern "C" {
void nvboard_update() {
if(render_flag) {
update_components(main_renderer);
SDL_RenderPresent(main_renderer);
render_flag = false;
}
nvboard_event_handler();
}
uint8_t nvboard_get_key(bool* succ){
extern KEYBOARD* kb;
return kb->pop_key(succ);
}
void nvboard_init(uint32_t* vmem, int MODE800x600) {
printf("nvboard v0.2\n");
// init SDL and SDL_image
SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_EVENTS);
IMG_Init(IMG_INIT_PNG);
main_window = SDL_CreateWindow("nvboard", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH * 2, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
main_renderer = SDL_CreateRenderer(main_window, -1,
#ifdef VSYNC
SDL_RENDERER_PRESENTVSYNC |
#endif
#ifdef HARDWARE_ACC
SDL_RENDERER_ACCELERATED |
#else
SDL_RENDERER_SOFTWARE |
#endif
0
);
nvboard_home = getenv("NVBOARD_HOME");
load_background(main_renderer);
load_texture(main_renderer);
init_components(main_renderer, vmem, MODE800x600);
init_gui(main_renderer);
update_components(main_renderer);
struct sigaction s;
memset(&s, 0, sizeof(s));
s.sa_handler = alarm_sig_handler;
int ret = sigaction(SIGVTALRM, &s, NULL);
assert(ret == 0);
struct itimerval it = {};
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 1000000 / 60;
it.it_interval = it.it_value;
ret = setitimer(ITIMER_VIRTUAL, &it, NULL);
assert(ret == 0);
}
void nvboard_quit(){
delete_components();
SDL_DestroyWindow(main_window);
SDL_DestroyRenderer(main_renderer);
IMG_Quit();
SDL_Quit();
}
}
#else
void nvboard_update() {
nvboard_update_all_input();
nvboard_update_all_output();
@ -148,6 +215,7 @@ void nvboard_quit(){
IMG_Quit();
SDL_Quit();
}
#endif
void nvboard_bind_pin(vector<output_pin> &pin, void *signal) {
output_pin_map[signal] = pin;

View File

@ -2,7 +2,9 @@
#include <nvboard.h>
#include <macro.h>
#include <assert.h>
#include <configs.h>
// http://tinyvga.com/vga-timing/800x600@60Hz
VGA_MODE vga_mod_accepted[NR_VGA_MODE] = {
[VGA_MODE_640_480] = {
.h_frontporch = 96,
@ -14,9 +16,31 @@ VGA_MODE vga_mod_accepted[NR_VGA_MODE] = {
.v_backporch = 515,
.v_total = 525,
},
[VGA_MODE_800_600] = {
.h_frontporch = 128,
.h_active = 216,
.h_backporch = 1016,
.h_total = 1056,
.v_frontporch = 4,
.v_active = 27,
.v_backporch = 627,
.v_total = 628,
},
};
VGA::VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct):
#ifdef MODE_NEMU
VGA::VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct, uint32_t* vmem, int MODE800x600):
Component(rend, cnt, init_val, it, ct),
vga_screen_width(MODE800x600? 800: 400), vga_screen_height(MODE800x600? 600:300),
vga_pre_clk(0), vga_pre_hsync(0), vga_pre_vsync(0),
vga_pos(0), vga_vaddr(0), vga_haddr(0) {
SDL_Texture *temp_texture = SDL_CreateTexture(rend, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, vga_screen_width, vga_screen_height);
set_texture(temp_texture, 0);
pixels = vmem;
}
#else
VGA::VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct):
Component(rend, cnt, init_val, it, ct),
vga_screen_width(VGA_DEFAULT_WIDTH), vga_screen_height(VGA_DEFAULT_HEIGHT),
vga_pre_clk(0), vga_pre_hsync(0), vga_pre_vsync(0),
@ -27,16 +51,21 @@ VGA::VGA(SDL_Renderer *rend, int cnt, int init_val, int it, int ct):
pixels = new uint32_t[vga_screen_width * vga_screen_height];
memset(pixels, 0, vga_screen_width * vga_screen_height * sizeof(uint32_t));
}
#endif
VGA::~VGA() {
SDL_DestroyTexture(get_texture(0));
#ifndef MODE_NEMU
delete []pixels;
#endif
}
void VGA::update_gui() {
#ifndef MODE_NEMU
static int frames = 0;
frames ++;
printf("%d frames\n", frames);
#endif
SDL_Texture *temp_texture = get_texture(0);
SDL_Renderer *temp_renderer = get_renderer();
SDL_Rect *temp_rect = get_rect(0);
@ -45,6 +74,12 @@ void VGA::update_gui() {
SDL_RenderCopy(temp_renderer, temp_texture, NULL, temp_rect);
}
#ifdef MODE_NEMU
void VGA::update_state() {
update_gui();
}
#else
void VGA::update_state() {
int vga_clk = output_map[output_pin::VGA_CLK];
int vga_vsync = output_map[output_pin::VGA_VSYNC];
@ -91,3 +126,4 @@ void VGA::update_state() {
vga_pre_vsync = vga_vsync;
vga_pre_clk = vga_clk;
}
#endif