parent
76aeea1fa5
commit
fbcc4e37f0
34
README.md
34
README.md
|
@ -1,42 +1,40 @@
|
|||
# Vhex disassembler
|
||||
|
||||
Vhex is a GUI, Vim based, disassembler for fx9860g.
|
||||
The Casio's OS code is not open-source but we can read the binary for understand his working.
|
||||
The Casio's OS code is not open-source, but we can read the binary for understand his working.
|
||||
There are in particular the syscalls, OS's functions that can be called as a library since the add-ins, which are a gold mine of clues about the functioning of the material.
|
||||
|
||||
![](https://framapic.org/kMVBl2hbDXOo/PBd7D1FR0LF2.gif)
|
||||
|
||||
## features
|
||||
|
||||
* All SH3 instructions is traduced "on-the-fly".
|
||||
* All SH3 instructions traduced "on-the-fly".
|
||||
* Can handle 3 modes for movements.
|
||||
* Can handle commands.
|
||||
* Commands history.
|
||||
* Compatible with SH3 and SH4 architecture.
|
||||
|
||||
List of currently supported commands:
|
||||
### List of currently supported commands:
|
||||
|
||||
* `systab` jump to the syscall entry (Casio do not use `TRAPA` instruction, just jump into constant address).
|
||||
* `vbrjmp int` jump to the Casio interrupt handler.
|
||||
* `vbrjmp except` jump to the Casio exception handler.
|
||||
* `vbrjmp fault` jump to the Casio memory fault handlers.
|
||||
* `syscall <id>` jump to the syscall function.
|
||||
* `ram <zone>` jump to the ram mapped in zone (p0,p1,p2,p3,p4).
|
||||
* `jmp <address>` jump to the address.
|
||||
* `rom` jump to the start of the ROM.
|
||||
* `systab` jump into the Casio "syscall handler".
|
||||
* `vbrjmp <zone>` jump into the Casio interrupt, exception or tlb miss handlers.
|
||||
* `syscall <id>` jump into the syscall function.
|
||||
* `ram <zone>` jump into the RAM mapped at different parts of the Virtual Memory.
|
||||
* `jmp <address>` jump where you want.
|
||||
* `rom <zone>` jump into the ROM mapped at different parts of the Virtual Memory.
|
||||
* `help <cmd>` display command's help.
|
||||
|
||||
List of currently supported modes:
|
||||
### List of currently supported modes:
|
||||
|
||||
TODO WRITE DOC
|
||||
* `UNUSED`
|
||||
* `NORMAL`
|
||||
* `COMMAND`
|
||||
* `UNUSED` The session is unused.
|
||||
* `NORMAL` User can move freely where it wants.
|
||||
* `COMMAND` User can type some commands.
|
||||
|
||||
## Building
|
||||
|
||||
Before compiling for the first time, There are a few dependencies:
|
||||
Before compiling for the first time, There are few dependencies:
|
||||
* A suitable GCC toolchain in the `PATH`. You can absolutely *not* build Vhex
|
||||
with your system compiler!`sh3eb-elf` is strongly advised.
|
||||
with your system compiler! `sh3eb-elf` is strongly advised.
|
||||
* [g1a wrapper](https://bitbucket.org/Lephenixnoir/add-in-wrapper/src/master/) to generate the Casio header.
|
||||
* [P7](https://p7.planet-casio.com/) communication utilities.
|
||||
|
||||
|
|
|
@ -3,35 +3,35 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
/* Define session_s */
|
||||
#include <utils.h>
|
||||
|
||||
struct cmd_info
|
||||
/* cmd_block - data part of command block */
|
||||
struct cmd_block
|
||||
{
|
||||
char *name;
|
||||
void (*constructor)(int, char **, struct session_s *, char *);
|
||||
const char *man;
|
||||
};
|
||||
|
||||
|
||||
// CMDBLOCK()
|
||||
// Generate a "command block" stored in ".cmd.cahce" section.
|
||||
// We need to "hide" the block, so we generate anonyme name using
|
||||
// __COUNTER__ macros.
|
||||
#define gen_name(n) _##n
|
||||
#define anonym_name(n) gen_name(n)
|
||||
#define CMDBLOCK(cmd,callback,string) \
|
||||
__attribute__((section(".cmd.cache"))) \
|
||||
static const struct cmd_info anonym_name(__COUNTER__) = { \
|
||||
static const struct cmd_block anonym_name(__COUNTER__) = { \
|
||||
.name = cmd, \
|
||||
.constructor = callback, \
|
||||
.man = string \
|
||||
}
|
||||
|
||||
//TODO: write doc.
|
||||
/* command_entry() - parse and execute the user's command. */
|
||||
void command_entry(struct session_s *session, struct vhex_s *vhex);
|
||||
|
||||
/* cmd_cache_find() - find command in the cache section. */
|
||||
const struct cmd_info *cmd_cache_find(char const *name);
|
||||
/*void address_jump(int argc, char **argv, struct session_s *session, char *info);
|
||||
void syscall_jump(int argc, char **argv, struct session_s *session, char *info);
|
||||
void ram_jump(int argc, char **argv, struct session_s *session, char *info);
|
||||
void vbr_jump(int argc, char **argv, struct session_s *session, char *info);
|
||||
void quit_command(int argc, char **argv, struct session_s *session, char *info);
|
||||
void where_command(int argc, char **argv, struct session_s *session, char *info);
|
||||
void help_command(int argc, char **argv, struct session_s *session, char *info);
|
||||
*/
|
||||
|
||||
#endif /*__COMMANDS_H__*/
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#ifndef __KERNEL_ERRNO_H__
|
||||
# define __KERNEL_ERRNO_H__ 1
|
||||
#ifndef __ERRNO_H__
|
||||
# define __ERRNO_H__ 1
|
||||
|
||||
// Errno wrapped headers.
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
|
|
|
@ -1,21 +1,30 @@
|
|||
#ifndef __HISTORY_H__
|
||||
# define __HISTORY_H__
|
||||
|
||||
/* Define type. */
|
||||
#include <types.h>
|
||||
|
||||
/* node - history node data part.*/
|
||||
struct node
|
||||
{
|
||||
const char data[32];
|
||||
struct node *next;
|
||||
};
|
||||
|
||||
/* history_s - history data part. */
|
||||
struct history_s {
|
||||
struct node *list;
|
||||
off_t offset;
|
||||
size_t deep;
|
||||
};
|
||||
|
||||
/* history_update() - create new node into the history list. */
|
||||
int history_update(struct node **list, const char *data);
|
||||
|
||||
/* history_get() - get a node data. */
|
||||
const void *history_get(struct node *list, off_t offset);
|
||||
|
||||
/* history_quit() - free all allocated memory. */
|
||||
void history_quit(struct node **list);
|
||||
|
||||
#endif /*__HISTORY_H__*/
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdint.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* opcode - instruction data part. */
|
||||
struct opcode
|
||||
{
|
||||
const char *name;
|
||||
|
@ -13,7 +14,7 @@ struct opcode
|
|||
uint16_t arg_mask[ARGUMENTS_MAX];
|
||||
};
|
||||
|
||||
|
||||
// Define ALL SH3 instructions.
|
||||
static const struct opcode opcode[] = {
|
||||
{
|
||||
.name = "add #h'%x,r%d",
|
||||
|
|
|
@ -4,25 +4,43 @@
|
|||
#include <types.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
// Define weak symbols
|
||||
#define WEAK __attribute__((weak))
|
||||
|
||||
//#ifndef DEBUG
|
||||
/* memset() - fill memory with a constant byte. */
|
||||
WEAK void *memset(void *s, int c, size_t n);
|
||||
|
||||
#ifndef DEBUG
|
||||
WEAK void vsprintf(char *str, char const *format, va_list ap);
|
||||
WEAK void sprintf(char *str, char const *format, ...);
|
||||
/* vsprintf(), sprintf() - formatted output conversion. */
|
||||
void vsprintf(char *str, char const *format, va_list ap);
|
||||
void sprintf(char *str, char const *format, ...);
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* strcat() - concatenate two string */
|
||||
WEAK char *strcat(char *dest, char const *src);
|
||||
|
||||
/* strcmp() - compare two strings */
|
||||
WEAK int strcmp(const char *s1, const char *s2);
|
||||
|
||||
/* strcpy(), strncpy() - copy a string. */
|
||||
WEAK char *strncpy(char *dest, char const *str, size_t size);
|
||||
WEAK char *strcpy(char *dest, char const *src);
|
||||
|
||||
/* strlen - calculate the lenght of a string. */
|
||||
WEAK size_t strlen(char const *str);
|
||||
|
||||
// Custom functions
|
||||
|
||||
|
||||
//
|
||||
// Custom string function.
|
||||
//
|
||||
/* strtotab() - generate table of word and indicate the number of word. */
|
||||
int strtotab(int *argc, char ***argv, char const *str);
|
||||
|
||||
/* strtotab_quit() - free all allocated memory by strtotab function. */
|
||||
void strtotab_quit(int *argc, char ***argv);
|
||||
|
||||
/* atoi_base() - atoi wrapped function, but add the base number. */
|
||||
uint32_t atoi_base(char const *str, int base);
|
||||
//#endif /* DEBUG */
|
||||
|
||||
#endif /*__STRING_H__*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <types.h>
|
||||
|
||||
// Internal Casio datat structure
|
||||
struct rect
|
||||
{
|
||||
int left;
|
||||
|
@ -11,16 +12,34 @@ struct rect
|
|||
int bottom;
|
||||
};
|
||||
|
||||
|
||||
// Casio prototype.
|
||||
//
|
||||
// Casio prototypes.
|
||||
//
|
||||
/* GetKey() - display Casio's VRAM and wait keyboard input. */
|
||||
void casio_GetKey(unsigned int *key);
|
||||
|
||||
/* Bdisp_AllClr_VRAM() - clear entirely the Casio's VRAM */
|
||||
void casio_Bdisp_AllClr_VRAM(void);
|
||||
|
||||
/* Bdisp_AreaClr_VRAM() - clear only VRAM area. */
|
||||
void casio_Bdisp_AreaClr_VRAM(const struct rect *buf);
|
||||
|
||||
/* PrintMini() - print string in Casio's VRAM (and display on screen ?) */
|
||||
void casio_PrintMini(size_t x, size_t y, char const *str, int mode);
|
||||
|
||||
/* Bdisp_DrawLine_VRAM() - draw line in Casio's VRAM. */
|
||||
void casio_Bdisp_DrawLine_VRAM(int x1, int y1, int x2, int y2);
|
||||
|
||||
/* RestoreDisp() - restore saved screen. */
|
||||
void casio_RestoreDisp(unsigned char page);
|
||||
|
||||
/* SaveDisp() - save the content of the screen. */
|
||||
void casio_SaveDisp(unsigned char page);
|
||||
|
||||
/* Malloc() - malloc syscall */
|
||||
void *casio_Malloc(size_t size);
|
||||
|
||||
/* Free() - free syscall */
|
||||
void *casio_Free(void *ptr);
|
||||
|
||||
|
||||
|
|
|
@ -4,18 +4,19 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//TODO: write doc
|
||||
|
||||
// Define properly off_t type.
|
||||
# ifndef __off_t_defined
|
||||
typedef uint32_t off_t;
|
||||
# define __off_t_defined
|
||||
# endif
|
||||
|
||||
// Define properly ssize_t type.
|
||||
#ifndef __ssize_t_defined
|
||||
typedef int32_t ssize_t;
|
||||
# define __ssize_t_defined
|
||||
#endif
|
||||
|
||||
// Force inline function.
|
||||
#define INLINE __attribute__((always_inline)) inline
|
||||
|
||||
#endif /*__TYPES_H__*/
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
# define __UTILS_H__
|
||||
|
||||
#include <types.h>
|
||||
// Define history_s
|
||||
#include <history.h>
|
||||
|
||||
//
|
||||
// SCREEN AND FONT PART.
|
||||
//
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define FONT_WIDTH 4
|
||||
|
@ -11,6 +15,9 @@
|
|||
#define LINE_OFFSET ((SCREEN_HEIGHT / FONT_HEIGHT) - 1)
|
||||
#define COLUMN_OFFSET (SCREEN_WIDTH / FONT_WIDTH)
|
||||
|
||||
//
|
||||
// KEYS'S ID PART.
|
||||
//
|
||||
#define KEY_UP 30018
|
||||
#define KEY_DOWN 30023
|
||||
#define KEY_LEFT 30020
|
||||
|
@ -72,11 +79,17 @@
|
|||
#define KEY_8 0x38
|
||||
#define KEY_9 0x39
|
||||
|
||||
//TODO: move me into opcode.h
|
||||
#define ARGUMENTS_MAX 3
|
||||
//TODO: move me into opcode.h
|
||||
#define INSTRUCTION_SIZE 2
|
||||
|
||||
|
||||
// Define some buffer size.
|
||||
#define SESSIONS_SLOT 6
|
||||
#define CMD_LENGHT_MAX 15
|
||||
|
||||
// Define session modes.
|
||||
enum session_mode_e
|
||||
{
|
||||
UNUSED,
|
||||
|
@ -84,6 +97,7 @@ enum session_mode_e
|
|||
NORMAL,
|
||||
};
|
||||
|
||||
// session_s - session data part.
|
||||
struct session_s
|
||||
{
|
||||
enum session_mode_e mode;
|
||||
|
@ -91,6 +105,7 @@ struct session_s
|
|||
int cursor;
|
||||
};
|
||||
|
||||
// Define insert modes.
|
||||
enum insert_mode
|
||||
{
|
||||
LETTER,
|
||||
|
@ -99,7 +114,7 @@ enum insert_mode
|
|||
SHIFT
|
||||
};
|
||||
|
||||
|
||||
// vhex_s - vhex data part.
|
||||
struct vhex_s
|
||||
{
|
||||
int current_session;
|
||||
|
@ -113,11 +128,13 @@ struct vhex_s
|
|||
struct history_s history;
|
||||
};
|
||||
|
||||
// screen part.
|
||||
void dclear(void);
|
||||
void dupdate(void);
|
||||
|
||||
/* display instructions() - display binary instructions. */
|
||||
void display_instructions(const struct session_s *session);
|
||||
|
||||
/* display_metainfos() - display status bar. */
|
||||
void display_metainfos(const struct vhex_s *vhex, const struct session_s *session);
|
||||
|
||||
/* key_handling() - GetKey abstraction. */
|
||||
void key_handling(struct vhex_s *vhex, struct session_s *session, unsigned int key);
|
||||
|
||||
#endif /*__UTILS_H__*/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <stddef.h>
|
||||
extern int main(void);
|
||||
|
||||
//define by bootstrap.ld
|
||||
//defined by bootstrap.ld
|
||||
extern uint32_t bbss;
|
||||
extern uint32_t sbss;
|
||||
extern uint32_t bdata_rom;
|
||||
|
|
|
@ -5,6 +5,16 @@
|
|||
extern uint32_t bcmd_cache;
|
||||
extern uint32_t ecmd_cache;
|
||||
|
||||
//
|
||||
// cmd_cache_find()
|
||||
// Try to find the command into the command cache.
|
||||
//
|
||||
// NOTE:
|
||||
// The cache is generated during the compilation; all command
|
||||
// blocks is stored in the ".cmd.cache" section.
|
||||
// We use the section symbols to know where the cache end.
|
||||
// (see bootstrap.ld).
|
||||
//
|
||||
const struct cmd_info *cmd_cache_find(char const *name)
|
||||
{
|
||||
const struct cmd_info *cache;
|
||||
|
|
|
@ -2,29 +2,10 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
//---
|
||||
// Define all "command block". One block is composed by:
|
||||
// * id: used uniquely for the "command_find()" internal cache.
|
||||
// * name: string which contains the user's command.
|
||||
// * anchor: used if the constructor are not set, it is the new "location" of the anchor.
|
||||
// * constructor: the command constructor (and the new anchor location will be ignored).
|
||||
//---
|
||||
//TODO: generate automatically anonymous name, and remove "command_find()" cache.
|
||||
/*CMDBLOCK(rom, "rom", 0x00300200, NULL);
|
||||
CMDBLOCK(systab, "systab", 0x80010070, NULL);
|
||||
CMDBLOCK(ram, "ram", NULL, &ram_jump);
|
||||
CMDBLOCK(vbrjmp, "vbrjmp", NULL, &vbr_jump);
|
||||
CMDBLOCK(addr_jump, "jmp", NULL, &address_jump);
|
||||
CMDBLOCK(sysc_jump, "syscall", NULL, &syscall_jump);
|
||||
|
||||
CMDBLOCK(exit, "quit", NULL, &quit_command);
|
||||
CMDBLOCK(locate, "where", NULL, &where_command);
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// command_find
|
||||
// Try to find the user command in the internal cache and execute constructor.
|
||||
// Try to find the user command in the internal cache and execute
|
||||
// the command's function.
|
||||
//
|
||||
static int command_find(int argc, char **argv, struct session_s *session,
|
||||
struct vhex_s *vhex)
|
||||
|
@ -36,7 +17,7 @@ struct vhex_s *vhex)
|
|||
if (command == NULL)
|
||||
return (EINVAL);
|
||||
if (command->constructor == NULL){
|
||||
strcpy(vhex->info, "constructor error");
|
||||
strcpy(vhex->info, "function error");
|
||||
return (ENOSYS);
|
||||
}
|
||||
tmp = session->anchor;
|
||||
|
@ -51,7 +32,7 @@ struct vhex_s *vhex)
|
|||
|
||||
//
|
||||
// command_entry()
|
||||
// The goal of this part is to parse and execute user's command.
|
||||
// The goal of this part is to parse and execute the user's command.
|
||||
//
|
||||
void command_entry(struct session_s *session, struct vhex_s *vhex)
|
||||
{
|
||||
|
|
|
@ -3,13 +3,11 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* FIXME: write doc !! */
|
||||
|
||||
// Internal prototype.
|
||||
static void help_command(int argc, char **argv, struct session_s *session, char *info);
|
||||
static void help(int argc, char **argv, struct session_s *session, char *info);
|
||||
|
||||
// Define help command into the cache section.
|
||||
CMDBLOCK("help", &help_command,
|
||||
CMDBLOCK("help", &help,
|
||||
"Help for Vhex version 1.0\n"
|
||||
"This chapter introduces\noperations available with vhex.\n"
|
||||
"\n"
|
||||
|
@ -95,6 +93,7 @@ CMDBLOCK("help", &help_command,
|
|||
"work for any purpose and\nwithout any legal restrictions, "
|
||||
"except those required by law.\n");
|
||||
|
||||
/* get_nb_line() - Return the number of lines contain in the command's manual. */
|
||||
static int get_nb_line(char const *str)
|
||||
{
|
||||
int nb_line;
|
||||
|
@ -114,6 +113,7 @@ static int get_nb_line(char const *str)
|
|||
return (nb_line + 1);
|
||||
}
|
||||
|
||||
/* get_line() - Return the address of a target line */
|
||||
static const char *get_line(char const *str, int line)
|
||||
{
|
||||
int cursor;
|
||||
|
@ -133,6 +133,14 @@ static const char *get_line(char const *str, int line)
|
|||
return (str);
|
||||
}
|
||||
|
||||
//
|
||||
// display_text() - Display only lines which should be visible.
|
||||
//
|
||||
// NOTE:
|
||||
// Due to the Casio's GetKey function, the font used is a little bit weird,
|
||||
// some characters have not the same size, so we can't calculate easily
|
||||
// the line size. (TODO: fix that).
|
||||
//
|
||||
static void display_text(char *buf, char const *str, int current_line)
|
||||
{
|
||||
char const *text;
|
||||
|
@ -161,6 +169,7 @@ static void display_text(char *buf, char const *str, int current_line)
|
|||
print(0, nb_line * FONT_HEIGHT, buf);
|
||||
}
|
||||
|
||||
/* help_engine() - Display help information and handle keyboard. */
|
||||
static void help_engine(char const *text, int nb_line)
|
||||
{
|
||||
char buf[COLUMN_OFFSET + 1];
|
||||
|
@ -182,6 +191,8 @@ static void help_engine(char const *text, int nb_line)
|
|||
sprintf(buf, "%d/%d", cursor + 1, nb_line + 1);
|
||||
print(SCREEN_WIDTH - (strlen(buf) * FONT_WIDTH) - 1, SCREEN_HEIGHT - FONT_HEIGHT, buf);
|
||||
getkey(&key);
|
||||
|
||||
// Keys hanlding.
|
||||
if (key == KEY_UP && cursor > 0)
|
||||
cursor -= 1;
|
||||
if (key == KEY_DOWN && cursor < nb_line)
|
||||
|
@ -191,7 +202,8 @@ static void help_engine(char const *text, int nb_line)
|
|||
}
|
||||
}
|
||||
|
||||
static void help_command(int argc, char **argv, struct session_s *session, char *info)
|
||||
/* help() - display command manual pages. */
|
||||
static void help(int argc, char **argv, struct session_s *session, char *info)
|
||||
{
|
||||
const struct cmd_info *command;
|
||||
int nb_line;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Internal prototype.
|
||||
static void address_jump(int argc, char **argv, struct session_s *session, char *info);
|
||||
|
||||
// Define the command block into the cache
|
||||
// Define the command block into the cache.
|
||||
CMDBLOCK("jmp", &address_jump,
|
||||
"JMP command help\n"
|
||||
"This command takes one\nparameter: the address (hexa)\n"
|
||||
|
|
|
@ -24,7 +24,7 @@ CMDBLOCK("rom", &rom_jump,
|
|||
"MMU is disable and the area\nis not cached.\n"
|
||||
);
|
||||
|
||||
/* rom_jump() - jump into the start of the ROM */
|
||||
/* rom_jump() - jump into the ROM mapped in different parts of the Virtual Memory. */
|
||||
static void rom_jump(int argc, char **argv, struct session_s *session, char *info)
|
||||
{
|
||||
if (argc != 2){
|
||||
|
|
|
@ -101,8 +101,8 @@ static INLINE int check_address(char *str)
|
|||
//
|
||||
// syscall_jump()
|
||||
// Casio doesn't use the TRAPA instruction (software interruption), for switch from
|
||||
// user mode to privileged mode. They just jump to a content area (always at 0x80010070)
|
||||
// and use the table of syscall addresses to redirect the jump. (and the table is always
|
||||
// user mode to privileged mode. They just jump always at 0x80010070 and use the
|
||||
// table of syscall addresses to redirect the jump. (and the table address is always
|
||||
// stored at 0x8001007c).
|
||||
//
|
||||
static void syscall_jump(int argc, char **argv, struct session_s *session, char *info)
|
||||
|
|
|
@ -22,7 +22,7 @@ CMDBLOCK("vbrjmp", &vbrjmp,
|
|||
);
|
||||
|
||||
//
|
||||
// vbr_jump() - jump to the exception, tlb or interrupt Casio handler.
|
||||
// vbr_jump() - jump to the exception, tlb or interrupt, Casio handler.
|
||||
// Due to the SH3 / SH4 VBR system, there are 3 vectors offset called
|
||||
// by the processor:
|
||||
// * vbr + 0x100 -> general exeptions.
|
||||
|
|
|
@ -7,7 +7,7 @@ static void where(int argc, char **argv, struct session_s *session, char *info);
|
|||
// Define the command into the cache.
|
||||
CMDBLOCK("where", &where, NULL);
|
||||
|
||||
/* where() - display the user postision in the Virtual Memory. */
|
||||
/* where() - display the user positision in the Virtual Memory. */
|
||||
static void where(int argc, char **argv, struct session_s *session, char *info)
|
||||
{
|
||||
(void)argc;
|
||||
|
|
|
@ -27,7 +27,8 @@ static int check_session(unsigned int key, struct vhex_s *vhex)
|
|||
//
|
||||
// check_special()
|
||||
// As explained below, the Casio getkey function has an internal status.
|
||||
// Here we check if a "special" keys are pressed and update internal Vhex key's status.
|
||||
// Here we check if a "special" keys are pressed and update internal Vhex
|
||||
// "keyboard's status".
|
||||
//
|
||||
static int check_special(unsigned int key, struct vhex_s *vhex, struct session_s *session)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue