ports/sh: first functional version, can compute in REPL
This commit is contained in:
parent
68f166dae9
commit
e33d85b1de
|
@ -0,0 +1,2 @@
|
|||
/icon.xcf
|
||||
/PythonExtra.g3a
|
|
@ -0,0 +1,44 @@
|
|||
include ../../py/mkenv.mk
|
||||
|
||||
# Use the sh-elf toolchain
|
||||
CROSS_COMPILE := sh-elf-
|
||||
|
||||
include $(TOP)/py/py.mk
|
||||
include $(TOP)/extmod/extmod.mk
|
||||
|
||||
CFLAGS += -m4-nofpu -mb -fstrict-volatile-bitfields -I. -I$(BUILD) -I$(TOP) -DFXCG50 -O2 -Wall -Wextra -Wno-unused-parameter
|
||||
LIBS += -nostdlib -Wl,--no-warn-rwx-segments -T fxcg50.ld -lm -lgint-cg -lc -lgint-cg -lgcc -Wl,-Map=build/map
|
||||
|
||||
# Source files
|
||||
SRC_C = \
|
||||
main.c \
|
||||
console.c \
|
||||
keymap.c \
|
||||
mphalport.c \
|
||||
shared/readline/readline.c \
|
||||
shared/runtime/gchelper_generic.c \
|
||||
shared/runtime/pyexec.c \
|
||||
shared/runtime/stdout_helpers.c \
|
||||
|
||||
SRC_QSTR += \
|
||||
shared/readline/readline.c \
|
||||
|
||||
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
|
||||
all: $(BUILD)/firmware.elf PythonExtra.g3a
|
||||
|
||||
PythonExtra.g3a: $(BUILD)/firmware.bin icon-uns.png icon-sel.png
|
||||
fxgxa --g3a -n PythonExtra --icon-uns=icon-uns.png --icon-sel=icon-sel.png $< -o $@
|
||||
|
||||
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
|
||||
$(Q)$(CC:gcc=objcopy) -O binary -R .bss -R .gint_bss $< $@
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
send: all
|
||||
fxlink -sw PythonExtra.g3a
|
||||
|
||||
include $(TOP)/py/mkrules.mk
|
|
@ -0,0 +1,110 @@
|
|||
#include <gint/keyboard.h>
|
||||
#include <gint/display.h>
|
||||
#include <gint/defs/util.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "console.h"
|
||||
|
||||
console_t *console_create(int max_lines)
|
||||
{
|
||||
console_t *cons = malloc(sizeof *cons);
|
||||
cons->max_lines = max_lines;
|
||||
cons->lines = calloc(max_lines, sizeof *cons->lines);
|
||||
for(int i = 0; i < max_lines; i++)
|
||||
cons->lines[i] = NULL;
|
||||
console_new_line(cons);
|
||||
return cons;
|
||||
}
|
||||
|
||||
void console_new_line(console_t *cons)
|
||||
{
|
||||
int n = cons->max_lines;
|
||||
free(cons->lines[0]);
|
||||
|
||||
for(int i = 0; i < n - 1; i++)
|
||||
cons->lines[i] = cons->lines[i+1];
|
||||
|
||||
cons->lines[n - 1] = strdup("");
|
||||
}
|
||||
|
||||
static void console_append_to_last_line(console_t *cons, void const *buf,
|
||||
int size)
|
||||
{
|
||||
int n = cons->max_lines;
|
||||
char *l = cons->lines[n - 1];
|
||||
int prev_size = l ? strlen(l) : 0;
|
||||
int new_size = prev_size + size + 1;
|
||||
|
||||
l = realloc(l, new_size);
|
||||
if(!l)
|
||||
return;
|
||||
|
||||
memcpy(l + prev_size, buf, size);
|
||||
l[new_size - 1] = 0;
|
||||
cons->lines[n - 1] = l;
|
||||
}
|
||||
|
||||
void console_append_str(console_t *cons, char const *str)
|
||||
{
|
||||
console_append_buf(cons, str, strlen(str));
|
||||
}
|
||||
|
||||
void console_append_buf(console_t *cons, void const *buf, size_t size_)
|
||||
{
|
||||
int offset = 0, size = size_;
|
||||
|
||||
while(offset < size) {
|
||||
/* Find the first '\n' (or end of buffer) in the segment */
|
||||
void const *endline = memchr(buf + offset, '\n', size - offset);
|
||||
if(endline == NULL)
|
||||
endline = buf + size;
|
||||
|
||||
int line_size = endline - (buf + offset);
|
||||
console_append_to_last_line(cons, buf + offset, line_size);
|
||||
|
||||
offset += line_size;
|
||||
|
||||
/* Found a '\n' */
|
||||
if(offset < size) {
|
||||
console_new_line(cons);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void console_render(int x, int y, console_t *cons, int w, int h)
|
||||
{
|
||||
int dy = 13;
|
||||
|
||||
for(int i = 0; i < cons->max_lines; i++) {
|
||||
/* Skip initial unallocated lines */
|
||||
if(cons->lines[i] == NULL)
|
||||
continue;
|
||||
|
||||
char const *p = cons->lines[i];
|
||||
char const *endline = p + strlen(p);
|
||||
|
||||
while(p < endline) {
|
||||
if(p[0] == '\n') {
|
||||
y += dy;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
char const *endscreen = drsize(p, NULL, w, NULL);
|
||||
char const *endline = strchrnul(p, '\n');
|
||||
int len = min(endscreen - p, endline - p);
|
||||
|
||||
dtext_opt(x, y, C_BLACK, C_NONE, DTEXT_LEFT, DTEXT_TOP, p, len);
|
||||
y += dy;
|
||||
p += len + (p[len] == '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void console_destroy(console_t *cons)
|
||||
{
|
||||
for(int i = 0; i < cons->max_lines; i++)
|
||||
free(cons->lines[i]);
|
||||
free(cons);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __PYTHONEXTRA_CONSOLE_H
|
||||
#define __PYTHONEXTRA_CONSOLE_H
|
||||
|
||||
//=== Console data storage ===//
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* An array lines[] of size [max_lines], filled from the end (always has a
|
||||
list of NULL followed by line pointers. */
|
||||
int max_lines;
|
||||
char **lines;
|
||||
|
||||
} console_t;
|
||||
|
||||
console_t *console_create(int max_lines);
|
||||
|
||||
void console_new_line(console_t *cons);
|
||||
|
||||
void console_append_str(console_t *cons, char const *str);
|
||||
|
||||
void console_append_buf(console_t *cons, void const *buf, size_t size);
|
||||
|
||||
/* TODO: Expand this function */
|
||||
void console_render(int x, int y, console_t *cons, int w, int h);
|
||||
|
||||
void console_destroy(console_t *cons);
|
||||
|
||||
#endif /* __PYTHONEXTRA_CONSOLE_H */
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
|
@ -0,0 +1,57 @@
|
|||
#include "keymap.h"
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
static int key_id(int keycode)
|
||||
{
|
||||
uint col = (keycode & 0x0f) - 1;
|
||||
uint row = 9 - ((keycode & 0xf0) >> 4);
|
||||
|
||||
if(col > 5 || row > 8) return -1;
|
||||
return 6 * row + col;
|
||||
}
|
||||
|
||||
static uint8_t map_flat[30] = {
|
||||
0, 0, '(', ')', ',', '=',
|
||||
'7', '8', '9', 0, 0, 0,
|
||||
'4', '5', '6', '*', '/', 0,
|
||||
'1', '2', '3', '+', '-', 0,
|
||||
'0', '.', 'e', '-', 0, 0,
|
||||
};
|
||||
static uint8_t map_alpha[36] = {
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l',
|
||||
'm', 'n', 'o', 0, 0, 0,
|
||||
'p', 'q', 'r', 's', 't', 0,
|
||||
'u', 'v', 'w', 'x', 'y', 0,
|
||||
'z', ' ', '"', 0, 0, 0,
|
||||
};
|
||||
|
||||
uint32_t keymap_translate(int key, bool shift, bool alpha)
|
||||
{
|
||||
int id = key_id(key);
|
||||
if(id < 0) return 0;
|
||||
|
||||
if(!shift && !alpha) {
|
||||
/* The first 4 rows have no useful characters */
|
||||
return (id < 24) ? 0 : map_flat[id - 24];
|
||||
}
|
||||
if(shift && !alpha) {
|
||||
if(key == KEY_MUL) return '{';
|
||||
if(key == KEY_DIV) return '}';
|
||||
if(key == KEY_ADD) return '[';
|
||||
if(key == KEY_SUB) return ']';
|
||||
if(key == KEY_DOT) return '=';
|
||||
if(key == KEY_0) return ':';
|
||||
if(key == KEY_EXP) return 0x3c0; // 'π'
|
||||
}
|
||||
if(!shift && alpha) {
|
||||
/* The first 3 rows have no useful characters */
|
||||
return (id < 18) ? 0 : map_alpha[id - 18];
|
||||
}
|
||||
if(shift && alpha) {
|
||||
int c = keymap_translate(key, false, true);
|
||||
return (c >= 'a' && c <= 'z') ? (c & ~0x20) : c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __PYTHONEXTRA_KEYMAP_H
|
||||
#define __PYTHONEXTRA_KEYMAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
uint32_t keymap_translate(int key, bool shift, bool alpha);
|
||||
|
||||
#endif /* __PYTHONEXTRA_KEYMAP_H */
|
|
@ -0,0 +1,116 @@
|
|||
#include "py/compile.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "py/builtin.h"
|
||||
#include "shared/runtime/gchelper.h"
|
||||
#include "shared/runtime/pyexec.h"
|
||||
|
||||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/fs.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "console.h"
|
||||
|
||||
// Allocate memory for the MicroPython GC heap.
|
||||
static char heap[32768];
|
||||
|
||||
int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, mp_uint_t exec_flags);
|
||||
|
||||
//=== Console-based standard streams ===//
|
||||
|
||||
ssize_t stdouterr_write(void *data, void const *buf, size_t size)
|
||||
{
|
||||
console_t *cons = data;
|
||||
console_append_buf(cons, buf, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
fs_descriptor_type_t stdouterr_type = {
|
||||
.read = NULL,
|
||||
.write = stdouterr_write,
|
||||
.lseek = NULL,
|
||||
.close = NULL,
|
||||
};
|
||||
|
||||
//=== Main function ===//
|
||||
|
||||
static console_t *cons = NULL;
|
||||
|
||||
void pe_draw(void)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
dtext(1, 1, C_BLACK, "PythonExtra, very much WIP :)");
|
||||
dline(1, 16, DWIDTH-1, 16, C_BLACK);
|
||||
console_render(1, 18, cons, DWIDTH-2, -1);
|
||||
dupdate();
|
||||
}
|
||||
|
||||
void pe_exithandler(void)
|
||||
{
|
||||
pe_draw();
|
||||
drect(DWIDTH-8, 0, DWIDTH-1, 7, C_RED);
|
||||
dupdate();
|
||||
getkey();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Set up standard streams */
|
||||
cons = console_create(10);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
open_generic(&stdouterr_type, cons, STDOUT_FILENO);
|
||||
open_generic(&stdouterr_type, cons, STDERR_FILENO);
|
||||
|
||||
atexit(pe_exithandler);
|
||||
|
||||
/* Initialize MicroPython */
|
||||
mp_stack_ctrl_init();
|
||||
gc_init(heap, heap + sizeof(heap));
|
||||
mp_init();
|
||||
|
||||
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
|
||||
pyexec_friendly_repl();
|
||||
|
||||
console_destroy(cons);
|
||||
|
||||
// Deinitialise the runtime.
|
||||
gc_sweep_all();
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle uncaught exceptions (should never be reached in a correct C implementation).
|
||||
void nlr_jump_fail(void *val) {
|
||||
dclear(C_BLACK);
|
||||
dtext(2, 2, C_WHITE, "nlr_jump_fail!");
|
||||
dprint(2, 2, C_WHITE, "val = %p", val);
|
||||
dupdate();
|
||||
while(1)
|
||||
getkey();
|
||||
}
|
||||
|
||||
// Do a garbage collection cycle.
|
||||
void gc_collect(void) {
|
||||
gc_collect_start();
|
||||
gc_helper_collect_regs_and_stack();
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
// There is no filesystem so stat'ing returns nothing.
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
// There is no filesystem so opening a file raises an exception.
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
|
||||
// Other options: BASIC_FEATURES, EXTRA_FEATURES, FULL_FEATURES, EVERYTHING
|
||||
|
||||
#define MICROPY_ENABLE_COMPILER (1)
|
||||
#define MP_ENDIANNESS_BIG (1)
|
||||
|
||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
||||
// #define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
|
||||
#define MICROPY_ALLOC_PATH_MAX (256)
|
||||
#define MICROPY_ALLOC_PARSE_CHUNK_INIT (16)
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
#define MICROPY_EMIT_THUMB (0)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (0)
|
||||
#define MICROPY_COMP_MODULE_CONST (0)
|
||||
#define MICROPY_COMP_CONST (0)
|
||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
|
||||
#define MICROPY_MEM_STATS (0)
|
||||
#define MICROPY_DEBUG_PRINTERS (0)
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_GC_ALLOC_THRESHOLD (0)
|
||||
#define MICROPY_REPL_EVENT_DRIVEN (0)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED)
|
||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (1)
|
||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
|
||||
#define MICROPY_PY_BUILTINS_ENUMERATE (1)
|
||||
#define MICROPY_PY_BUILTINS_FILTER (1)
|
||||
// #define MICROPY_PY_BUILTINS_FROZENSET (1)
|
||||
#define MICROPY_PY_BUILTINS_REVERSED (1)
|
||||
#define MICROPY_PY_BUILTINS_SET (1)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (1)
|
||||
#define MICROPY_PY_BUILTINS_PROPERTY (1)
|
||||
#define MICROPY_PY_BUILTINS_MIN_MAX (1)
|
||||
#define MICROPY_PY___FILE__ (0)
|
||||
#define MICROPY_PY_GC (1)
|
||||
#define MICROPY_PY_ARRAY (1)
|
||||
#define MICROPY_PY_ATTRTUPLE (1)
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MICROPY_PY_CMATH (1)
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_STRUCT (1)
|
||||
#define MICROPY_PY_SYS (1)
|
||||
// #define MICROPY_MODULE_FROZEN_MPY (1)
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE)
|
||||
// #define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
|
||||
#define MP_NEED_LOG2 (1)
|
||||
|
||||
/* #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
|
||||
|
||||
#define MICROPY_MIN_USE_STDOUT (1) */
|
||||
|
||||
// Type definitions for the specific machine.
|
||||
|
||||
typedef intptr_t mp_int_t; // must be pointer size
|
||||
typedef uintptr_t mp_uint_t; // must be pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// We need to provide a declaration/definition of alloca().
|
||||
#include <alloca.h>
|
||||
|
||||
// Define the port's name and hardware.
|
||||
#define MICROPY_HW_BOARD_NAME "sh7305"
|
||||
#define MICROPY_HW_MCU_NAME "sh-4a"
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
|
@ -0,0 +1,36 @@
|
|||
#include <unistd.h>
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mphal.h"
|
||||
#include "../../shared/readline/readline.h"
|
||||
|
||||
#include "keymap.h"
|
||||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
// Receive single character, blocking until one is available.
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
while(1) {
|
||||
key_event_t ev = getkey();
|
||||
int key = ev.key;
|
||||
|
||||
if(key == KEY_ACON)
|
||||
return CHAR_CTRL_C;
|
||||
if(key == KEY_EXE)
|
||||
return '\r';
|
||||
if(key == KEY_EXIT)
|
||||
return CHAR_CTRL_D;
|
||||
|
||||
uint32_t code_point = keymap_translate(key, ev.shift, ev.alpha);
|
||||
if(code_point != 0)
|
||||
return code_point;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the string of given length.
|
||||
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||
int r = write(STDOUT_FILENO, str, len);
|
||||
(void)r;
|
||||
|
||||
extern void pe_draw(void);
|
||||
pe_draw();
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
static inline void mp_hal_set_interrupt_char(char c) {}
|
|
@ -41,6 +41,8 @@ typedef uintptr_t gc_helper_regs_t[4];
|
|||
typedef uintptr_t gc_helper_regs_t[10];
|
||||
#elif defined(__aarch64__)
|
||||
typedef uintptr_t gc_helper_regs_t[11]; // x19-x29
|
||||
#elif defined(__sh3__)
|
||||
typedef uintptr_t gc_helper_regs_t[8];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -150,6 +150,27 @@ STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
|
|||
arr[10] = x29;
|
||||
}
|
||||
|
||||
#elif defined(__sh3__)
|
||||
|
||||
STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
|
||||
register const long r8 asm ("r8");
|
||||
register const long r9 asm ("r9");
|
||||
register const long r10 asm ("r10");
|
||||
register const long r11 asm ("r11");
|
||||
register const long r12 asm ("r12");
|
||||
register const long r13 asm ("r13");
|
||||
register const long r14 asm ("r14");
|
||||
register const long r15 asm ("r15");
|
||||
arr[0] = r8;
|
||||
arr[1] = r9;
|
||||
arr[2] = r10;
|
||||
arr[3] = r11;
|
||||
arr[4] = r12;
|
||||
arr[5] = r13;
|
||||
arr[6] = r14;
|
||||
arr[7] = r15;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation."
|
||||
|
|
Loading…
Reference in New Issue