Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
console.c
Go to the documentation of this file.
1 /* Re-CP/M: CP/M-like own implementation + Z80 emulator
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2016-2019 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;
33  Uint8 cursor_color; // only low 4 bits!
34 } cursor;
35 static int console_width, console_height;
36 static Uint8 *video_ram;
37 static Uint8 *color_ram;
38 static Uint32 palette[16];
39 #define CHARACTER_SET_DEFINER_8X16 static const Uint8 chargen[]
40 #include "xemu/vgafonts.c"
41 #undef CHARACTER_SET_DEFINER_8X16
42 static const Uint8 console_colors[3*16] = { // FIXME
43  0x00, 0x00, 0x00, // black
44  0xFF, 0xFF, 0xFF, // white
45  0xF0, 0x00, 0x00, // red
46  0x00, 0xF0, 0xF0, // cyan
47  0x60, 0x00, 0x60, // purple
48  0x00, 0xA0, 0x00, // green
49  0x00, 0x00, 0xF0, // blue
50  0xD0, 0xD0, 0x00, // yellow
51  0xC0, 0xA0, 0x00, // orange
52  0xFF, 0xA0, 0x00, // light orange
53  0xF0, 0x80, 0x80, // pink
54  0x00, 0xFF, 0xFF, // light cyan
55  0xFF, 0x00, 0xFF, // light purple
56  0x00, 0xFF, 0x00, // light green
57  0x00, 0xA0, 0xFF, // light blue
58  0xFF, 0xFF, 0x00 // light yellow
59 };
60 static int serial_delay;
61 static Uint8 kbd_queue[16];
62 static int kbd_queue_len;
63 static int kbd_waiting = 0; // just an indicator [different cursor if we sense console input waiting from program]
64 static int input_waiting;
65 
66 
67 
68 static void conraw_clear ( void )
69 {
70  memset(video_ram, 0x20, console_width * console_height);
71  memset(color_ram, cursor.text_color, console_width * console_height);
72  cursor.x = 0;
73  cursor.y = 0;
74 }
75 
76 static void conraw_scroll ( void )
77 {
78  memmove(video_ram, video_ram + console_width, console_width * (console_height - 1));
79  memmove(color_ram, color_ram + console_width, console_width * (console_height - 1));
80  memset(video_ram + console_width * (console_height - 1), 0x20, console_width);
81  memset(color_ram + console_width * (console_height - 1), cursor.text_color, console_width);
82 }
83 
84 static void conraw_down ( void )
85 {
86  if (cursor.y == console_height - 1)
87  conraw_scroll();
88  else
89  cursor.y++;
90 }
91 
92 static void conraw_putch ( Uint8 data )
93 {
94  video_ram[cursor.y * console_width + cursor.x] = data;
95  color_ram[cursor.y * console_width + cursor.x] = cursor.text_color;
96  if (cursor.x == console_width - 1) {
97  cursor.x = 0;
98  conraw_down();
99  } else
100  cursor.x++;
101  emu_cost_usecs += serial_delay;
102 }
103 
104 
106 {
107  // CRLF?
108 // cursor.x = 0;
109 // if (cursor.y == console_height - 1)
110 
111  if (data == 13) {
112  cursor.x = 0;
113  } else if (data == 10) {
114  conraw_down();
115  } else if (data == 8) {
116  if (cursor.x)
117  cursor.x--;
118  } else if (data < 32) {
119  conraw_putch('^');
120  conraw_putch('A' + data);
121  } else {
122  conraw_putch(data);
123  }
124  // All output should make cursor phase 'shown' to avoid blinking during longer changes (ie, moving cursor around)
125  cursor.phase = 1;
126  cursor.phase_counter = 0;
127 }
128 
129 void conputs ( const char *s )
130 {
131  while (*s)
132  console_output(*s++);
133 }
134 
135 
136 // 0=no char ready, ottherwise there is (actual BIOS implementation should have 0xFF for having character)
137 int console_status ( void )
138 {
139  kbd_waiting = 1;
140  return kbd_queue_len ? 0xFF : 0;
141 }
142 
143 // Unlike CP/M BIOS console input, this can't wait here, since we have to give the control back
144 // Thus in case of no character is read, 0 is given back. It's the task of the caller to emulate
145 // the right BIOS functionality with this.
146 int console_input ( void )
147 {
148  if (console_status()) {
149  int ret = kbd_queue[0];
150  if (--kbd_queue_len)
151  memmove(kbd_queue, kbd_queue + 1, kbd_queue_len);
152  emu_cost_usecs += serial_delay;
153  return ret;
154  } else {
155  input_waiting = 1;
156  return 0;
157  }
158 }
159 
160 
161 void console_cursor_blink ( int delay )
162 {
163  if (cursor.blinking) {
164  if (cursor.phase_counter >= delay) {
165  cursor.phase = !cursor.phase;
166  cursor.phase_counter = 0;
167  } else
168  cursor.phase_counter++;
169  } else
170  cursor.phase = 1;
171 }
172 
173 // This will render our screen, also calls SDL event loop ...
174 void console_iteration ( void )
175 {
176  int vp = 0;
177  int cursor_line = (cursor.phase && cursor.visible) ? cursor.y : -1;
178  int tail;
179  Uint32 *pixel = xemu_start_pixel_buffer_access(&tail);
180  for (int y = 0; y < console_height; y++) {
181  for (int row = 0; row < FONT_HEIGHT; row++) {
182  for (int x = 0; x < console_width; x++) {
183  Uint32 fg = palette[color_ram[vp + x] & 0xF];
184  Uint32 bg = palette[color_ram[vp + x] >> 4];
185  Uint8 chln = chargen[video_ram[vp + x] * FONT_HEIGHT + row];
186  if (XEMU_UNLIKELY(cursor_line == y && cursor.x == x)) {
187  //Uint32 temp = fg;
188  //fg = bg;
189  //bg = temp;
190  if (row > 12 || kbd_waiting) {
191  chln = 0xFF;
192  fg = palette[cursor.cursor_color];
193  }
194  }
195  for (int bpos = 0; bpos < 8; bpos++, chln <<= 1)
196  *pixel++ = (chln & 0x80) ? fg : bg;
197  *pixel++ = bg; // the 9th pixel is always blank for now
198  }
199  pixel += tail;
200  }
201  vp += console_width;
202  }
205  kbd_waiting = 0;
206 }
207 
208 
209 void clear_emu_events ( void )
210 {
211  hid_reset_events(1);
212 }
213 
214 // HID needs this to be defined, it's up to the emulator if it uses or not ...
215 int emu_callback_key ( int pos, SDL_Scancode key, int pressed, int handled )
216 {
217  return 0;
218 }
219 
220 
221 
222 static void queue_key ( Uint8 k )
223 {
224  if (k == 8)
225  k = 127;
226  if (kbd_queue_len < sizeof kbd_queue)
227  kbd_queue[kbd_queue_len++] = k;
228  else
229  DEBUGPRINT("KBD: keyboard queue is full :(" NL);
230 }
231 
232 
233 
234 
235 // We uses this actually. it needs global macro set: CONFIG_KBD_ALSO_RAW_SDL_CALLBACK
236 void emu_callback_key_raw_sdl ( SDL_KeyboardEvent *ev )
237 {
238  if (ev->state == SDL_PRESSED) {
239  int k = ev->keysym.sym;
240  DEBUGPRINT("KEY: %d [%c]\n", k, (k >= 0x20 && k < 127) ? k : '?');
241  // FIXME: we want to use text edit even instead, so we don't mess with the modifier keys / layouts ...
242  // ... that would need though some Xemu core HID modifications to allow that.
243  if (k < 32 || k == 127) { // push key event
244  queue_key(k);
245  }
246  }
247 }
248 
249 #if 0
250 void emu_callback_key_texteditng_sdl ( SDL_TextEditingEvent *ev )
251 {
252  DEBUGPRINT("TEXTEDITING: \"%s\"" NL, ev->text);
253 }
254 #endif
255 
256 void emu_callback_key_textinput_sdl ( SDL_TextInputEvent *ev )
257 {
258  DEBUGPRINT("TEXTINPUT: \"%s\"" NL, ev->text);
259  Uint8 *p = (Uint8*)ev->text;
260  while (*p) {
261  if (*p >= 0x20 && *p < 127)
262  queue_key(*p);
263  p++;
264  }
265 }
266 
267 
268 int console_init ( int width, int height, int zoom_percent, int *map_to_ram, int baud_emu )
269 {
270  int screen_width = width * 9;
271  int screen_height = height * FONT_HEIGHT;
272  int window_width = screen_width * zoom_percent / 100;
273  int window_height = screen_height * zoom_percent / 100;
274  static const struct KeyMappingDefault matrix_key_map_def[] = {
276  { 0, -1 }
277  };
278  if (xemu_post_init(
279  TARGET_DESC APP_DESC_APPEND, // window title
280  1, // resizable window
281  screen_width, screen_height, // texture sizes
282  screen_width, screen_height, // logical size
283  window_width, window_height, // window size
284  SCREEN_FORMAT, // pixel format
285  16, // we have 16 colours
286  console_colors, // initialize palette from this constant array
287  palette, // initialize palette into this stuff
288  RENDER_SCALE_QUALITY, // render scaling quality
289  USE_LOCKED_TEXTURE, // 1 = locked texture access
290  recpm_shutdown_callback // shutdown function
291  ))
292  return 1;
293  hid_init(
294  matrix_key_map_def,
295  0, // virtual shift position for matrix emulation, but we don't use matrix stuff in re-CP/M
296  SDL_DISABLE // joystick events are not used in CP/M emu, currently
297  );
298  if (map_to_ram) {
299  color_ram = memory + 0x10000 - width * height;
300  video_ram = color_ram - width * height;
301  *map_to_ram = video_ram - memory;
302  } else {
303  video_ram = xemu_malloc(width * height);
304  color_ram = xemu_malloc(width * height);
305  }
306  if (baud_emu) {
307  // Assuming 11 bit communication (8 bit + start bit + stop bit + parity bit)
308  serial_delay = (11 * 1000000) / baud_emu;
309  } else {
310  serial_delay = 0;
311  }
312  console_width = width;
313  console_height = height;
314  DEBUGPRINT("CONSOLE: %dx%d characters, %dx%d pixels, serial delay is %d usecs" NL, width, height, screen_width, screen_height, serial_delay);
315  kbd_queue_len = 0;
316  cursor.text_color = 1;
317  conraw_clear();
318  cursor.visible = 1;
319  cursor.blinking = 1;
320  cursor.phase = 1;
321  cursor.phase_counter = 0;
322  cursor.cursor_color = 2;
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
emu_cost_usecs
int emu_cost_usecs
Definition: hardware.h:25
console_status
int console_status(void)
Definition: console.c:148
emutools.h
xemu_update_screen
void xemu_update_screen(void)
Definition: emutools.c:1184
phase_counter
int phase_counter
Definition: console.c:30
recpm_shutdown_callback
void recpm_shutdown_callback(void)
Definition: recpm.c:70
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
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
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
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
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
hardware.h
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
RENDER_SCALE_QUALITY
#define RENDER_SCALE_QUALITY
Definition: commodore_65.h:27
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.h
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