378 lines
10 KiB
C
378 lines
10 KiB
C
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
#include "device.h"
|
|
|
|
#include <SDL.h>
|
|
|
|
#define BPP 4
|
|
|
|
#define CHAR_W 4
|
|
#define CHAR_H 8
|
|
|
|
#define TEXT_ROWS 12
|
|
#define TEXT_COLS 32
|
|
|
|
#define BORDER_L 16
|
|
#define BORDER_R 16
|
|
#define BORDER_T 16
|
|
#define BORDER_B 16
|
|
|
|
#define ZOOM 8
|
|
|
|
#define KBUF_SIZE 16
|
|
|
|
#define COLORS (1<<BPP)
|
|
|
|
#define SCREEN_W (TEXT_COLS*CHAR_W)
|
|
#define SCREEN_H (TEXT_ROWS*CHAR_H)
|
|
|
|
#define SURFACE_W (BORDER_L+SCREEN_W+BORDER_R)
|
|
#define SURFACE_H (BORDER_T+SCREEN_H+BORDER_B)
|
|
|
|
#define WINDOW_W (SURFACE_W*ZOOM)
|
|
#define WINDOW_H (SURFACE_H*ZOOM)
|
|
|
|
uint16_t screen_iptr;
|
|
uint16_t font_iptr;
|
|
uint16_t palette_iptr;
|
|
uint16_t border;
|
|
|
|
#define PALETTE(x) (palette_iptr ? ram[(palette_iptr+(x))&0xffff] : default_palette[x])
|
|
#define FONT(x) (font_iptr ? ram[(font_iptr+(x))&0xffff] : default_font[x])
|
|
#define SCREEN(x) (ram[(screen_iptr+(x))&0xffff])
|
|
|
|
#include "font.c"
|
|
#include "palette.c"
|
|
|
|
SDL_Window *window = NULL;
|
|
SDL_Surface *screenSurface = NULL;
|
|
SDL_Surface *glyph_shapes = NULL;
|
|
SDL_Surface *glyph_tiles = NULL;
|
|
SDL_Palette *palette = NULL;
|
|
|
|
struct timeval poweron_time;
|
|
|
|
uint8_t kbuf[KBUF_SIZE];
|
|
uint8_t khead, klen;
|
|
uint16_t kint;
|
|
|
|
bool ignore_modifiers = false;
|
|
|
|
void update_glyph_tiles()
|
|
{
|
|
SDL_SetSurfacePalette(glyph_shapes, palette);
|
|
SDL_BlitSurface(glyph_shapes, NULL, glyph_tiles, NULL);
|
|
}
|
|
|
|
void update_font()
|
|
{
|
|
int x, y, i, j;
|
|
uint8_t fg, bg;
|
|
bool pixel;
|
|
uint8_t *raster;
|
|
|
|
printf("update_font()\n");
|
|
|
|
SDL_LockSurface(glyph_shapes);
|
|
raster = (uint8_t *)(glyph_shapes->pixels);
|
|
for (i=0; i<sizeof(default_font)/sizeof(default_font[0]); i++) {
|
|
for (j=0; j<16; j++) {
|
|
x = i*2+(1-j/8);
|
|
y = j%8;
|
|
pixel = ((FONT(i)>>j) & 1) != 0;
|
|
// raster[x+y*glyph_shapes->w] = (pixel ? 1 : 0);
|
|
for (fg=0; fg<COLORS; fg++)
|
|
for (bg=0; bg<COLORS; bg++)
|
|
raster[x+(y+(fg<<4|bg)*CHAR_H)*glyph_shapes->w] = (pixel ? fg : bg);
|
|
}
|
|
}
|
|
SDL_UnlockSurface(glyph_shapes);
|
|
|
|
update_glyph_tiles();
|
|
|
|
printf("update_font() completed\n");
|
|
}
|
|
|
|
void update_palette()
|
|
{
|
|
int i;
|
|
|
|
printf("update_palette()\n");
|
|
|
|
// if (palette == NULL)
|
|
// palette = SDL_AllocPalette(256);
|
|
|
|
for (i=0; i<COLORS; i++) {
|
|
palette->colors[i].r = ((PALETTE(i)>>8)&0xf)*0xff/0xf;
|
|
palette->colors[i].g = ((PALETTE(i)>>4)&0xf)*0xff/0xf;
|
|
palette->colors[i].b = ((PALETTE(i))&0xf)*0xff/0xf;
|
|
palette->colors[i].a = 255;
|
|
// printf("%2d %02x%02x%02x\n", i, palette->colors[i].r, palette->colors[i].g, palette->colors[i].b);
|
|
}
|
|
|
|
update_glyph_tiles();
|
|
|
|
printf("update_palette() completed\n");
|
|
}
|
|
|
|
void lem1802_init()
|
|
{
|
|
screen_iptr = font_iptr = palette_iptr = border = 0;
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
|
}
|
|
palette = SDL_AllocPalette(256);
|
|
glyph_shapes = SDL_CreateRGBSurface(0, CHAR_W*128, CHAR_H*COLORS*COLORS, 8, 0, 0, 0, 0);
|
|
if (glyph_shapes == NULL) {
|
|
SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
|
|
}
|
|
// SDL_SetSurfacePalette(glyph_shapes, palette);
|
|
glyph_tiles = SDL_CreateRGBSurface(0, glyph_shapes->w, glyph_shapes->h, 32, 0, 0, 0, 0);
|
|
if (glyph_tiles == NULL) {
|
|
SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
|
|
}
|
|
update_font();
|
|
update_palette();
|
|
}
|
|
|
|
void keyboard_init()
|
|
{
|
|
khead = klen = 0;
|
|
kint = 0;
|
|
}
|
|
|
|
void lem1802_free()
|
|
{
|
|
if (window)
|
|
SDL_DestroyWindow(window);
|
|
window = NULL;
|
|
if (palette)
|
|
SDL_FreePalette(palette);
|
|
palette = NULL;
|
|
if (glyph_tiles)
|
|
SDL_FreeSurface(glyph_tiles);
|
|
glyph_tiles = NULL;
|
|
if (glyph_shapes)
|
|
SDL_FreeSurface(glyph_shapes);
|
|
glyph_shapes = NULL;
|
|
// SDL_Quit();
|
|
}
|
|
|
|
void process_key(SDL_Event *e)
|
|
{
|
|
uint8_t k=0;
|
|
|
|
if ((e->type == SDL_TEXTINPUT) && (e->text.text[0] >= 0x20) && (e->text.text[0] <= 0x7f))
|
|
k = e->text.text[0];
|
|
else if (e->type == SDL_KEYDOWN) {
|
|
switch (e->key.keysym.sym) {
|
|
case SDLK_BACKSPACE:
|
|
k = 0x10;
|
|
break;
|
|
case SDLK_RETURN:
|
|
case SDLK_RETURN2:
|
|
k = 0x11;
|
|
break;
|
|
case SDLK_INSERT:
|
|
k = 0x12;
|
|
break;
|
|
case SDLK_DELETE:
|
|
k = 0x13;
|
|
break;
|
|
case SDLK_UP:
|
|
k = 0x80;
|
|
break;
|
|
case SDLK_DOWN:
|
|
k = 0x81;
|
|
break;
|
|
case SDLK_LEFT:
|
|
k = 0x82;
|
|
break;
|
|
case SDLK_RIGHT:
|
|
k = 0x83;
|
|
break;
|
|
case SDLK_LSHIFT:
|
|
case SDLK_RSHIFT:
|
|
if (!ignore_modifiers)
|
|
k = 0x90;
|
|
break;
|
|
case SDLK_LCTRL:
|
|
case SDLK_RCTRL:
|
|
if (!ignore_modifiers)
|
|
k = 0x91;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (k != 0) {
|
|
kbuf[khead] = k;
|
|
khead = (khead + 1) % KBUF_SIZE;
|
|
if (klen < KBUF_SIZE) {
|
|
klen++;
|
|
}
|
|
if (kint != 0)
|
|
intq_push(kint);
|
|
}
|
|
}
|
|
|
|
void lem1802_tick()
|
|
{
|
|
uint16_t i;
|
|
uint16_t cell;
|
|
uint8_t ch, fg, bg;
|
|
bool bl;
|
|
SDL_Rect src, dst;
|
|
SDL_Event e;
|
|
static struct timeval last_frame = {0,0};
|
|
|
|
if (screen_iptr != 0) {
|
|
// printf("Update\n");
|
|
|
|
while (SDL_PollEvent(&e)) {
|
|
if (e.type == SDL_QUIT)
|
|
running = false;
|
|
if (e.type == SDL_KEYDOWN) {
|
|
if (e.key.keysym.sym == SDLK_F12)
|
|
running = false;
|
|
else if (e.key.keysym.sym == SDLK_F11) {
|
|
update_font();
|
|
update_palette();
|
|
} else if (e.key.keysym.sym == SDLK_F10) {
|
|
ignore_modifiers = !ignore_modifiers;
|
|
} else
|
|
process_key(&e);
|
|
}
|
|
if (e.type == SDL_TEXTINPUT) {
|
|
// printf("Text input: %s\n", &e.text.text);
|
|
process_key(&e);
|
|
}
|
|
}
|
|
|
|
// gettimeofday(&t, NULL);
|
|
|
|
if ((time.tv_sec - poweron_time.tv_sec)*100 + (time.tv_usec - poweron_time.tv_usec)/10000 < 100)
|
|
return;
|
|
|
|
if ((time.tv_sec - last_frame.tv_sec)*100 + (time.tv_usec - last_frame.tv_usec)/10000 < 2)
|
|
return;
|
|
|
|
last_frame.tv_sec = time.tv_sec;
|
|
last_frame.tv_usec = time.tv_usec;
|
|
|
|
src.x = 0;
|
|
src.y = CHAR_H*((border&0xf)<<4|(border&0xf));
|
|
src.w = CHAR_W;
|
|
src.h = CHAR_H;
|
|
if (SDL_BlitScaled(glyph_tiles, &src, screenSurface, NULL) != 0)
|
|
printf("BlitScaled() failed! SDL_Error: %s\n", SDL_GetError());
|
|
|
|
for (i=0; i<TEXT_ROWS*TEXT_COLS; i++) {
|
|
cell = ram[(screen_iptr+i) & 0xffff];
|
|
ch = cell & 0x7f;
|
|
bl = (cell & 0x80) != 0;
|
|
bg = (cell >> 8) & 0xf;
|
|
fg = (bl && time.tv_usec>500000 ? bg : (cell >> 12) & 0xf);
|
|
src.x = ch*CHAR_W;
|
|
src.y = CHAR_H*(fg<<4|bg);
|
|
src.w = CHAR_W;
|
|
src.h = CHAR_H;
|
|
dst.x = (BORDER_L+CHAR_W*(i%TEXT_COLS))*ZOOM;
|
|
dst.y = (BORDER_T+CHAR_H*(i/TEXT_COLS))*ZOOM;
|
|
dst.w = CHAR_W*ZOOM;
|
|
dst.h = CHAR_H*ZOOM;
|
|
if (SDL_BlitScaled(glyph_tiles, &src, screenSurface, &dst) != 0)
|
|
printf("BlitScaled() failed! SDL_Error: %s\n", SDL_GetError());
|
|
}
|
|
SDL_UpdateWindowSurface(window);
|
|
}
|
|
}
|
|
|
|
void lem1802_irqh()
|
|
{
|
|
int i;
|
|
|
|
switch (ra) {
|
|
case 0: /* MEM_MAP_SCREEN */
|
|
if (screen_iptr == 0) {
|
|
if (rb != 0) {
|
|
/* LEM1802 power up */
|
|
poweron_time.tv_sec = time.tv_sec; poweron_time.tv_usec = time.tv_usec;
|
|
window = SDL_CreateWindow("LEM1802", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN);
|
|
if(window == NULL) {
|
|
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
|
|
} else {
|
|
screenSurface = SDL_GetWindowSurface(window);
|
|
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x80, 0x80, 0x80));
|
|
SDL_UpdateWindowSurface(window);
|
|
}
|
|
}
|
|
} else {
|
|
if (rb == 0) {
|
|
/* LEM1802 power down */
|
|
SDL_DestroyWindow(window);
|
|
window = NULL;
|
|
}
|
|
}
|
|
screen_iptr = rb;
|
|
break;
|
|
case 1: /* MEM_MAP_FONT */
|
|
font_iptr = rb;
|
|
update_font();
|
|
break;
|
|
case 2: /* MEM_MAP_PALETTE */
|
|
palette_iptr = rb;
|
|
update_palette();
|
|
break;
|
|
case 3: /* SET_BORDER_COLOR */
|
|
border = rb;
|
|
break;
|
|
case 4: /* MEM_DUMP_FONT */
|
|
printf("Dumping default font to 0x%04x\n", rb);
|
|
for (i=0; i<sizeof(default_font)/sizeof(default_font[0]); i++)
|
|
ram[(rb+i)&0xffff] = default_font[i];
|
|
break;
|
|
case 5: /* MEM_DUMP_PALETTE */
|
|
printf("Dumping default palette to 0x%04x\n", rb);
|
|
for (i=0; i<sizeof(default_palette)/sizeof(default_palette[0]); i++)
|
|
ram[(rb+i)&0xffff] = default_palette[i];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void keyboard_irqh()
|
|
{
|
|
switch (ra) {
|
|
case 0: /* Clear buffer */
|
|
khead = klen = 0;
|
|
break;
|
|
case 1: /* Get next key */
|
|
if (klen > 0) {
|
|
rc = kbuf[(khead+KBUF_SIZE-klen)%KBUF_SIZE];
|
|
klen--;
|
|
} else
|
|
rc = 0;
|
|
break;
|
|
case 2: /* Check key */
|
|
printf("Check if key 0x%04x is pressed\n", rb);
|
|
rc = 0;
|
|
break;
|
|
case 3: /* Set interrupt message */
|
|
printf("Keyboard interrupt message: 0x%04x\n", rb);
|
|
kint = rb;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct dev_entry lem1802_dev = { 0x1c6c8b36, 0x7349f615, 0x1802, lem1802_irqh, lem1802_init, lem1802_free, lem1802_tick }; /* LEM1802 */
|
|
struct dev_entry keyboard_dev = { 0x6d53647c, 0x30cf7406, 1, keyboard_irqh, keyboard_init, NULL, NULL }; /* Generic keyboard */
|