Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
console.c
Go to the documentation of this file.
1 /* RC2014 and generic Z80 SBC emulator
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2020,2021 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 #include "xemu/emutools.h"
20 #include "xemu/emutools_hid.h"
21 #include "console.h"
22 //#include "hardware.h"
23 #include <string.h>
24 
25 
26 static struct {
27  int x,y;
28  int visible;
29  int phase;
31  int blinking;
32  int escape;
34  Uint8 cursor_color; // only low 4 bits!
35 } cursor;
36 static int console_width, console_height;
37 static Uint8 *video_ram;
38 static Uint8 *color_ram;
39 static Uint32 palette[16];
40 #define CHARACTER_SET_DEFINER_8X16 static const Uint8 chargen[]
41 #include "xemu/vgafonts.c"
42 #undef CHARACTER_SET_DEFINER_8X16
43 static const Uint8 console_colors[3*16] = { // FIXME
44  0x00, 0x00, 0x00, // black
45  0xFF, 0xFF, 0xFF, // white
46  0xF0, 0x00, 0x00, // red
47  0x00, 0xF0, 0xF0, // cyan
48  0x60, 0x00, 0x60, // purple
49  0x00, 0xA0, 0x00, // green
50  0x00, 0x00, 0xF0, // blue
51  0xD0, 0xD0, 0x00, // yellow
52  0xC0, 0xA0, 0x00, // orange
53  0xFF, 0xA0, 0x00, // light orange
54  0xF0, 0x80, 0x80, // pink
55  0x00, 0xFF, 0xFF, // light cyan
56  0xFF, 0x00, 0xFF, // light purple
57  0x00, 0xFF, 0x00, // light green
58  0x00, 0xA0, 0xFF, // light blue
59  0xFF, 0xFF, 0x00 // light yellow
60 };
61 static int serial_delay;
62 static Uint8 kbd_queue[16];
63 static int kbd_queue_len;
64 static int kbd_waiting = 0; // just an indicator [different cursor if we sense console input waiting from program]
65 static int input_waiting;
67 
68 
69 
70 static void conraw_clear ( void )
71 {
72  memset(video_ram, 0x20, console_width * console_height);
73  memset(color_ram, cursor.text_color, console_width * console_height);
74  cursor.x = 0;
75  cursor.y = 0;
76 }
77 
78 static void conraw_scroll ( void )
79 {
80  memmove(video_ram, video_ram + console_width, console_width * (console_height - 1));
81  memmove(color_ram, color_ram + console_width, console_width * (console_height - 1));
82  memset(video_ram + console_width * (console_height - 1), 0x20, console_width);
83  memset(color_ram + console_width * (console_height - 1), cursor.text_color, console_width);
84 }
85 
86 static void conraw_down ( void )
87 {
88  if (cursor.y == console_height - 1)
89  conraw_scroll();
90  else
91  cursor.y++;
92 }
93 
94 static void conraw_putch ( Uint8 data )
95 {
96  video_ram[cursor.y * console_width + cursor.x] = data;
97  color_ram[cursor.y * console_width + cursor.x] = cursor.text_color;
98  if (cursor.x == console_width - 1) {
99  cursor.x = 0;
100  conraw_down();
101  } else
102  cursor.x++;
103 }
104 
105 
107 {
108  static char escape_buffer[100];
109  // CRLF?
110 // cursor.x = 0;
111 // if (cursor.y == console_height - 1)
112 
113  if (cursor.escape) {
114  int l = strlen(escape_buffer);
115  escape_buffer[l++] = data;
116  escape_buffer[l] = 0;
117  } else if (data == 27) {
118  // start of some ESCAPE sequence ...
119  cursor.escape = 1;
120  escape_buffer[0] = 0;
121  } else if (data == 13) {
122  cursor.x = 0;
123  } else if (data == 10) {
124  conraw_down();
125  } else if (data == 8) {
126  if (cursor.x)
127  cursor.x--;
128  } else if (data < 32) {
129  conraw_putch('^');
130  conraw_putch('A' + data);
131  } else {
132  conraw_putch(data);
133  }
134  // All output should make cursor phase 'shown' to avoid blinking during longer changes (ie, moving cursor around)
135  cursor.phase = 1;
136  cursor.phase_counter = 0;
138 }
139 
140 void conputs ( const char *s )
141 {
142  while (*s)
143  console_output(*s++);
144 }
145 
146 
147 // 0=no char ready, ottherwise there is (actual BIOS implementation should have 0xFF for having character)
148 int console_status ( void )
149 {
150  kbd_waiting = 1;
151  return kbd_queue_len ? 0xFF : 0;
152 }
153 
154 // Unlike CP/M BIOS console input, this can't wait here, since we have to give the control back
155 // Thus in case of no character is read, 0 is given back. It's the task of the caller to emulate
156 // the right BIOS functionality with this.
157 int console_input ( void )
158 {
159  if (console_status()) {
160  int ret = kbd_queue[0];
161  if (--kbd_queue_len)
162  memmove(kbd_queue, kbd_queue + 1, kbd_queue_len);
164  return ret;
165  } else {
166  input_waiting = 1;
167  return 0;
168  }
169 }
170 
171 
172 void console_cursor_blink ( int delay )
173 {
174  if (cursor.blinking) {
175  if (cursor.phase_counter >= delay) {
176  cursor.phase = !cursor.phase;
177  cursor.phase_counter = 0;
178  } else
179  cursor.phase_counter++;
180  } else
181  cursor.phase = 1;
182 }
183 
184 // This will render our screen, also calls SDL event loop ...
185 void console_iteration ( void )
186 {
187  int vp = 0;
188  int cursor_line = (cursor.phase && cursor.visible) ? cursor.y : -1;
189  int tail;
190  Uint32 *pixel = xemu_start_pixel_buffer_access(&tail);
191  for (int y = 0; y < console_height; y++) {
192  for (int row = 0; row < FONT_HEIGHT; row++) {
193  for (int x = 0; x < console_width; x++) {
194  Uint32 fg = palette[color_ram[vp + x] & 0xF];
195  Uint32 bg = palette[color_ram[vp + x] >> 4];
196  Uint8 chln = chargen[video_ram[vp + x] * FONT_HEIGHT + row];
197  if (XEMU_UNLIKELY(cursor_line == y && cursor.x == x)) {
198  //Uint32 temp = fg;
199  //fg = bg;
200  //bg = temp;
201  if (row > 12 || kbd_waiting) {
202  chln = 0xFF;
203  fg = palette[cursor.cursor_color];
204  }
205  }
206  for (int bpos = 0; bpos < 8; bpos++, chln <<= 1)
207  *pixel++ = (chln & 0x80) ? fg : bg;
208  *pixel++ = bg; // the 9th pixel is always blank for now
209  }
210  pixel += tail;
211  }
212  vp += console_width;
213  }
216  kbd_waiting = 0;
217 }
218 
219 
220 void clear_emu_events ( void )
221 {
222  hid_reset_events(1);
223 }
224 
225 // HID needs this to be defined, it's up to the emulator if it uses or not ...
226 int emu_callback_key ( int pos, SDL_Scancode key, int pressed, int handled )
227 {
228  return 0;
229 }
230 
231 
232 
233 static void queue_key ( Uint8 k )
234 {
235  if (k == 8)
236  k = 127;
237  if (kbd_queue_len < sizeof kbd_queue)
238  kbd_queue[kbd_queue_len++] = k;
239  else
240  DEBUGPRINT("KBD: keyboard queue is full :(" NL);
241 }
242 
243 
244 
245 
246 // We uses this actually. it needs global macro set: CONFIG_KBD_ALSO_RAW_SDL_CALLBACK
247 void emu_callback_key_raw_sdl ( SDL_KeyboardEvent *ev )
248 {
249  if (ev->state == SDL_PRESSED) {
250  int k = ev->keysym.sym;
251  DEBUGPRINT("KEY: %d [%c]\n", k, (k >= 0x20 && k < 127) ? k : '?');
252  // FIXME: we want to use text edit even instead, so we don't mess with the modifier keys / layouts ...
253  // ... that would need though some Xemu core HID modifications to allow that.
254  if (k < 32 || k == 127) { // push key event
255  queue_key(k);
256  }
257  }
258 }
259 
260 #if 0
261 void emu_callback_key_texteditng_sdl ( SDL_TextEditingEvent *ev )
262 {
263  DEBUGPRINT("TEXTEDITING: \"%s\"" NL, ev->text);
264 }
265 #endif
266 
267 void emu_callback_key_textinput_sdl ( SDL_TextInputEvent *ev )
268 {
269  DEBUGPRINT("TEXTINPUT: \"%s\"" NL, ev->text);
270  Uint8 *p = (Uint8*)ev->text;
271  while (*p) {
272  if (*p >= 0x20 && *p < 127)
273  queue_key(*p);
274  p++;
275  }
276 }
277 
278 
279 int console_init ( int width, int height, int zoom_percent, Uint8 *video_mapped, Uint8 *color_mapped, int sdlrenderquality )
280 {
281  int screen_width = width * 9;
282  int screen_height = height * FONT_HEIGHT;
283  int window_width = screen_width * zoom_percent / 100;
284  int window_height = screen_height * zoom_percent / 100;
285  static const struct KeyMappingDefault matrix_key_map_def[] = {
287  { 0, -1 }
288  };
289  if (xemu_post_init(
290  TARGET_DESC APP_DESC_APPEND, // window title
291  1, // resizable window
292  screen_width, screen_height, // texture sizes
293  screen_width, screen_height, // logical size
294  window_width, window_height, // window size
295  SCREEN_FORMAT, // pixel format
296  16, // we have 16 colours
297  console_colors, // initialize palette from this constant array
298  palette, // initialize palette into this stuff
299  sdlrenderquality, // render scaling quality
300  USE_LOCKED_TEXTURE, // 1 = locked texture access
301  rc_shutdown_callback // shutdown function
302  ))
303  return 1;
304  hid_init(
305  matrix_key_map_def,
306  0, // virtual shift position for matrix emulation, but we don't use matrix stuff in re-CP/M
307  SDL_DISABLE // joystick events are not used in CP/M emu, currently
308  );
309  video_ram = video_mapped ? video_mapped : xemu_malloc(width * height);
310  color_ram = color_mapped ? color_mapped : xemu_malloc(width * height);
311  console_width = width;
312  console_height = height;
313  DEBUGPRINT("CONSOLE: %dx%d characters, %dx%d pixels, serial delay is %d usecs" NL, width, height, screen_width, screen_height, serial_delay);
314  kbd_queue_len = 0;
315  cursor.text_color = 1;
316  conraw_clear();
317  cursor.visible = 1;
318  cursor.blinking = 1;
319  cursor.phase = 1;
320  cursor.phase_counter = 0;
321  cursor.cursor_color = 2;
322  cursor.escape = 0;
323  SDL_StartTextInput();
324  return 0;
325 }
USE_LOCKED_TEXTURE
#define USE_LOCKED_TEXTURE
Definition: commodore_65.h:26
TARGET_DESC
#define TARGET_DESC
Definition: xemu-target.h:2
console_input
int console_input(void)
Definition: console.c:157
console_status
int console_status(void)
Definition: console.c:148
console_io_traffic
int console_io_traffic
Definition: console.c:66
emutools.h
sdlrenderquality
int sdlrenderquality
Definition: commodore_geos.c:150
xemu_update_screen
void xemu_update_screen(void)
Definition: emutools.c:1184
phase_counter
int phase_counter
Definition: console.c:30
hid_handle_all_sdl_events
void hid_handle_all_sdl_events(void)
Definition: emutools_hid.c:613
clear_emu_events
void clear_emu_events(void)
Definition: console.c:220
escape
int escape
Definition: console.c:32
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
Uint32
uint32_t Uint32
Definition: fat32.c:49
hid_init
void hid_init(const struct KeyMappingDefault *key_map_in, Uint8 virtual_shift_pos_in, int joy_enable)
Definition: emutools_hid.c:300
hid_reset_events
void hid_reset_events(int burn)
Definition: emutools_hid.c:170
Uint8
uint8_t Uint8
Definition: fat32.c:51
palette
Uint32 * palette
Definition: vic4_palette.c:33
xemu_malloc
void * xemu_malloc(size_t size)
Definition: emutools.c:226
x
int x
Definition: console.c:27
STD_XEMU_SPECIAL_KEYS
#define STD_XEMU_SPECIAL_KEYS
Definition: emutools_hid.h:108
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
rc_shutdown_callback
void rc_shutdown_callback(void)
Definition: rc2014.c:85
xemu_start_pixel_buffer_access
Uint32 * xemu_start_pixel_buffer_access(int *texture_tail)
Definition: emutools.c:1153
video_ram
Uint8 video_ram[0x10000]
Definition: tvc.c:54
NL
#define NL
Definition: fat32.c:37
blinking
int blinking
Definition: console.c:31
FONT_HEIGHT
#define FONT_HEIGHT
Definition: console.h:22
KeyMappingDefault
Definition: emutools_hid.h:24
xemu_post_init
int xemu_post_init(const char *window_title, int is_resizable, int texture_x_size, int texture_y_size, int logical_x_size, int logical_y_size, int win_x_size, int win_y_size, Uint32 pixel_format, int n_colours, const Uint8 *colours, Uint32 *store_palette, int render_scale_quality, int locked_texture_update, void(*shutdown_callback)(void))
Definition: emutools.c:908
emu_callback_key_textinput_sdl
void emu_callback_key_textinput_sdl(SDL_TextInputEvent *ev)
Definition: console.c:267
text_color
Uint8 text_color
Definition: console.c:33
cursor_color
Uint8 cursor_color
Definition: console.c:34
console_init
int console_init(int width, int height, int zoom_percent, Uint8 *video_mapped, Uint8 *color_mapped, int sdlrenderquality)
Definition: console.c:279
SCREEN_FORMAT
#define SCREEN_FORMAT
Definition: commodore_65.h:25
emu_callback_key_raw_sdl
void emu_callback_key_raw_sdl(SDL_KeyboardEvent *ev)
Definition: console.c:247
console.h
y
int y
Definition: console.c:27
APP_DESC_APPEND
#define APP_DESC_APPEND
Definition: emutools.h:52
emutools_hid.h
console_iteration
void console_iteration(void)
Definition: console.c:185
vgafonts.c
emu_callback_key
int emu_callback_key(int pos, SDL_Scancode key, int pressed, int handled)
Definition: console.c:226
conputs
void conputs(const char *s)
Definition: console.c:140
console_output
void console_output(Uint8 data)
Definition: console.c:106
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
phase
int phase
Definition: console.c:29
console_cursor_blink
void console_cursor_blink(int delay)
Definition: console.c:172
visible
int visible
Definition: console.c:28