204 lines
4.7 KiB
C++
204 lines
4.7 KiB
C++
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_image.h>
|
|
#include <nvboard.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <assert.h>
|
|
#include <string>
|
|
#include <stdarg.h>
|
|
|
|
#define FPS 60
|
|
|
|
static uint64_t boot_time = 0;
|
|
|
|
static uint64_t get_time_internal() {
|
|
struct timeval now;
|
|
gettimeofday(&now, NULL);
|
|
uint64_t us = now.tv_sec * 1000000 + now.tv_usec;
|
|
return us;
|
|
}
|
|
|
|
static uint64_t get_time() {
|
|
uint64_t now = get_time_internal();
|
|
return now - boot_time;
|
|
}
|
|
|
|
static void calculate_clock_frequency() {
|
|
static int update_count = 0, last_count = 0;
|
|
static time_t begin = 0;
|
|
|
|
update_count ++;
|
|
if(!begin) time(&begin), last_count = update_count;
|
|
else {
|
|
time_t end;
|
|
time(&end);
|
|
if(end - begin >= CALCULATE_CLOCK_FREQUENCY_INTERVAL) {
|
|
printf("Clock frequency: %ld cycles/s\n", (update_count - last_count) / (end - begin) / 2);
|
|
begin = end;
|
|
last_count = update_count;
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct PinMap {
|
|
int len;
|
|
bool is_output;
|
|
union {
|
|
uint16_t pin;
|
|
uint16_t *pins;
|
|
};
|
|
void *signal;
|
|
PinMap *next;
|
|
} PinMap;
|
|
|
|
static PinMap *pin_map = NULL;
|
|
static PinMap *rt_pin_map = NULL; // real-time pins
|
|
|
|
static SDL_Window *main_window = nullptr;
|
|
static SDL_Renderer *main_renderer = nullptr;
|
|
uint64_t input_map[NR_INPUT_PINS] = {0};
|
|
uint64_t output_map[NR_OUTPUT_PINS] = {0};
|
|
std::string nvboard_home;
|
|
|
|
int read_event();
|
|
|
|
static void nvboard_update_input(PinMap *p) {
|
|
void *ptr = p->signal;
|
|
if (p->len == 1) {
|
|
uint8_t val = input_map[p->pin];
|
|
*(uint8_t *)ptr = val;
|
|
return;
|
|
}
|
|
|
|
int len = p->len;
|
|
uint64_t val = 0;
|
|
for (int i = 0; i < len; i ++) {
|
|
val <<= 1;
|
|
val |= input_map[p->pins[i]];
|
|
}
|
|
if (len <= 8) { *(uint8_t *)ptr = val; }
|
|
else if (len <= 16) { *(uint16_t *)ptr = val; }
|
|
else if (len <= 32) { *(uint32_t *)ptr = val; }
|
|
else if (len <= 64) { *(uint64_t *)ptr = val; }
|
|
}
|
|
|
|
static void nvboard_update_output(PinMap *p) {
|
|
void *ptr = p->signal;
|
|
if (p->len == 1) {
|
|
uint8_t val = *(uint8_t *)ptr;
|
|
output_map[p->pin] = val & 1;
|
|
return;
|
|
}
|
|
|
|
int len = p->len;
|
|
uint64_t val = 0;
|
|
if (len <= 8) { val = *(uint8_t *)ptr; }
|
|
else if (len <= 16) { val = *(uint16_t *)ptr; }
|
|
else if (len <= 32) { val = *(uint32_t *)ptr; }
|
|
else if (len <= 64) { val = *(uint64_t *)ptr; }
|
|
for (int i = 0; i < len; i ++) {
|
|
output_map[p->pins[i]] = val & 1;
|
|
val >>= 1;
|
|
}
|
|
}
|
|
|
|
void nvboard_update() {
|
|
#ifdef DEBUG
|
|
calculate_clock_frequency();
|
|
#endif
|
|
|
|
for (auto p = rt_pin_map; p != NULL; p = p->next) {
|
|
if (p->is_output) nvboard_update_output(p);
|
|
else nvboard_update_input(p);
|
|
}
|
|
|
|
update_rt_components(main_renderer);
|
|
|
|
static uint64_t last = 0;
|
|
uint64_t now = get_time();
|
|
if (now - last > 1000000 / FPS) {
|
|
last = now;
|
|
|
|
for (auto p = pin_map; p != NULL; p = p->next) {
|
|
if (p->is_output) nvboard_update_output(p);
|
|
else nvboard_update_input(p);
|
|
}
|
|
|
|
int ev = read_event();
|
|
if (ev == -1) { exit(0); }
|
|
|
|
update_components(main_renderer);
|
|
SDL_RenderPresent(main_renderer);
|
|
}
|
|
}
|
|
|
|
void nvboard_init() {
|
|
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);
|
|
init_gui(main_renderer);
|
|
|
|
update_components(main_renderer);
|
|
update_rt_components(main_renderer);
|
|
|
|
boot_time = get_time_internal();
|
|
}
|
|
|
|
void nvboard_quit(){
|
|
delete_components();
|
|
SDL_DestroyWindow(main_window);
|
|
SDL_DestroyRenderer(main_renderer);
|
|
IMG_Quit();
|
|
SDL_Quit();
|
|
}
|
|
|
|
void nvboard_bind_pin(void *signal, bool is_rt, bool is_output, int len, ...) {
|
|
PinMap *p = new PinMap;
|
|
p->is_output = is_output;
|
|
p->len = len;
|
|
assert(len < 64);
|
|
|
|
va_list ap;
|
|
va_start(ap, len);
|
|
if (len == 1) { p->pin = (uint16_t)va_arg(ap, int); }
|
|
else {
|
|
p->pins = new uint16_t[p->len];
|
|
for (int i = 0; i < len; i ++) {
|
|
uint16_t pin = va_arg(ap, int);
|
|
if (is_output) p->pins[len - 1 - i] = pin;
|
|
else p->pins[i] = pin;
|
|
}
|
|
}
|
|
va_end(ap);
|
|
|
|
p->signal = signal;
|
|
if (is_rt) { p->next = rt_pin_map; rt_pin_map = p; }
|
|
else { p->next = pin_map; pin_map = p; }
|
|
}
|
|
|
|
int vga_cycles = 1;
|
|
|
|
void nvboard_set_vga_cycles(int cycles) {
|
|
vga_cycles = cycles;
|
|
}
|