Starting work on PPU -> display -> VGA
This commit is contained in:
BIN
src/vgasim
Executable file
BIN
src/vgasim
Executable file
Binary file not shown.
210
src/vgasim.c
Normal file
210
src/vgasim.c
Normal file
@@ -0,0 +1,210 @@
|
||||
#include <SDL.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#define RBUF_SIZE 256
|
||||
|
||||
#define DEF_SCREEN_W 640
|
||||
#define DEF_SCREEN_H 480
|
||||
|
||||
unsigned int pixel_x;
|
||||
unsigned int pixel_y;
|
||||
unsigned int screen_w;
|
||||
unsigned int screen_h;
|
||||
SDL_Window* sdl_window;
|
||||
SDL_Renderer* sdl_renderer;
|
||||
SDL_Texture* sdl_texture;
|
||||
|
||||
Uint32* screen;
|
||||
|
||||
#define VGASIM_CMD_INIT 0x01
|
||||
#define VGASIM_CMD_RESET 0x02
|
||||
#define VGASIM_CMD_TICK 0x03
|
||||
|
||||
void vgasim_init(int new_screen_h, int new_screen_w, int bpp) {
|
||||
printf("vgasim_init: %d x %d x %d\n", new_screen_w, new_screen_h, bpp);
|
||||
pixel_x = 0;
|
||||
pixel_y = 0;
|
||||
|
||||
if (screen_h != new_screen_h || screen_w != new_screen_w) {
|
||||
printf("Need to resize\n");
|
||||
}
|
||||
|
||||
screen_h = new_screen_h;
|
||||
screen_w = new_screen_w;
|
||||
}
|
||||
|
||||
void vgasim_reset() {
|
||||
printf("vgasim_reset\n");
|
||||
pixel_x = 0;
|
||||
pixel_y = 0;
|
||||
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(sdl_renderer);
|
||||
SDL_RenderPresent(sdl_renderer);
|
||||
}
|
||||
|
||||
void vgasim_tick(int r, int g, int b, int hsync, int vsync) {
|
||||
//printf("vgasim_tick: %X, %X, %X (%s%s)\n", r, g, b, hsync ? "h" : "", vsync ? "v" : "");
|
||||
|
||||
screen[screen_w * pixel_y + pixel_x] = ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0);
|
||||
pixel_x++;
|
||||
if (hsync || pixel_x > screen_w) {
|
||||
pixel_x = 0;
|
||||
pixel_y++;
|
||||
//printf("vgasim_tick: vsync\n");
|
||||
SDL_UpdateTexture(sdl_texture, NULL, screen, screen_w * sizeof (Uint32));
|
||||
SDL_RenderClear(sdl_renderer);
|
||||
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
|
||||
SDL_RenderPresent(sdl_renderer);
|
||||
}
|
||||
if (vsync || pixel_y > screen_h) {
|
||||
pixel_y = 0;
|
||||
// printf("vgasim_tick: hsync\n");
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t cmd_parse(char *buf, ssize_t bufsize) {
|
||||
uint8_t *p8;
|
||||
uint16_t *p16;
|
||||
uint16_t cmd;
|
||||
uint8_t r, g, b, hvsync;
|
||||
uint16_t h, w, bpp;
|
||||
|
||||
if (bufsize < sizeof(uint16_t))
|
||||
return 0;
|
||||
|
||||
p16 = (uint16_t*)buf;
|
||||
cmd = *p16++;
|
||||
p8 = (uint8_t*)p16;
|
||||
switch (cmd) {
|
||||
case VGASIM_CMD_INIT:
|
||||
if (bufsize < 4 * sizeof(uint16_t))
|
||||
return 0;
|
||||
h = *p16++;
|
||||
w = *p16++;
|
||||
bpp = *p16++;
|
||||
vgasim_init(h, w, bpp);
|
||||
return 4 * sizeof(uint16_t);
|
||||
|
||||
case VGASIM_CMD_RESET:
|
||||
vgasim_reset();
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case VGASIM_CMD_TICK:
|
||||
if (bufsize < sizeof(uint16_t) + 4 * sizeof(uint8_t))
|
||||
return 0;
|
||||
r = *p8++;
|
||||
g = *p8++;
|
||||
b = *p8++;
|
||||
hvsync = *p8++;
|
||||
vgasim_tick(r, g, b, (hvsync & 0x01), ((hvsync & 0x02) >> 1));
|
||||
|
||||
return sizeof(uint16_t) + 4 * sizeof(uint8_t);
|
||||
|
||||
default:
|
||||
printf("Unsupported command packet received: %X\n", cmd);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
int fifo_fd;
|
||||
char rbuf[RBUF_SIZE];
|
||||
ssize_t bytes_read, bytes_read_total;
|
||||
ssize_t bytes_parsed, bytes_parsed_total;
|
||||
int ret = mkfifo("/tmp/vgasim", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
if (ret == -1 && errno != EEXIST) {
|
||||
perror(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = SDL_Init(SDL_INIT_VIDEO);
|
||||
if (ret < 0) {
|
||||
printf("SDL_Init failed: %d\n", ret);
|
||||
return 2;
|
||||
}
|
||||
|
||||
sdl_window = SDL_CreateWindow("vgasim", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, DEF_SCREEN_W, DEF_SCREEN_H, 0);
|
||||
if (sdl_window == NULL) {
|
||||
printf("SDL_CreateWindow failed\n");
|
||||
return 3;
|
||||
}
|
||||
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, 0);
|
||||
if (sdl_renderer == NULL) {
|
||||
printf("SDL_CreateRenderer failed\n");
|
||||
return 4;
|
||||
}
|
||||
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, DEF_SCREEN_W, DEF_SCREEN_H);
|
||||
if (sdl_texture == NULL) {
|
||||
printf("SDL_CreateTexture failed\n");
|
||||
return 5;
|
||||
}
|
||||
SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(sdl_renderer);
|
||||
SDL_RenderPresent(sdl_renderer);
|
||||
|
||||
screen = malloc(DEF_SCREEN_H * DEF_SCREEN_W * sizeof(Uint32));
|
||||
if (screen == NULL) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
printf("Listening for incoming connections...\n");
|
||||
ret = open("/tmp/vgasim", O_RDONLY);
|
||||
if (ret == -1) {
|
||||
perror(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
fifo_fd = ret;
|
||||
|
||||
bytes_read_total = 0;
|
||||
do {
|
||||
|
||||
// Read as much bytes as we can into our buffer
|
||||
bytes_read = read(fifo_fd, rbuf + bytes_read_total, RBUF_SIZE - bytes_read_total);
|
||||
bytes_read_total += bytes_read;
|
||||
|
||||
bytes_parsed_total = 0;
|
||||
if (bytes_read > 0) {
|
||||
do {
|
||||
|
||||
// Parse as many bytes as we can
|
||||
bytes_parsed = cmd_parse(rbuf + bytes_parsed_total, bytes_read_total - bytes_parsed_total);
|
||||
bytes_parsed_total += bytes_parsed;
|
||||
} while (bytes_parsed > 0);
|
||||
}
|
||||
|
||||
// If there's any data left unparsed, it's the start of a new incomplete packet.
|
||||
// Copy it to the front of the buffer and restart from there.
|
||||
// Otherwise we cleared our entire buffer and can start again from the beginning.
|
||||
if (bytes_read_total > bytes_parsed_total) {
|
||||
memcpy(rbuf, rbuf + bytes_parsed_total, (bytes_read_total - bytes_parsed_total));
|
||||
bytes_read_total = bytes_read_total - bytes_parsed_total;
|
||||
} else {
|
||||
bytes_read_total = 0;
|
||||
}
|
||||
} while (bytes_read > 0);
|
||||
|
||||
if (bytes_read < 0) {
|
||||
perror(argv[0]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
free(screen);
|
||||
SDL_DestroyTexture(sdl_texture);
|
||||
SDL_DestroyRenderer(sdl_renderer);
|
||||
SDL_DestroyWindow(sdl_window);
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user