mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
gdb, video, r61524: gdb visual feedback + start video intf on CG
- Define a draft of the video interface - Implement that dragt for CG for a single mode * Includes stub of brightness setting from disassembling 3.60 - Use the video interface to show visual feedback on GDB on CG Using the video interface avoids directly linking into a driver, which will serve modularity in gint 3.
This commit is contained in:
parent
b4c0fc7cea
commit
0afd05848a
10 changed files with 328 additions and 93 deletions
|
@ -243,10 +243,12 @@ set(SOURCES
|
|||
src/usb/string.c
|
||||
src/usb/usb.c
|
||||
src/usb/write4.S
|
||||
# Video driver interface
|
||||
src/video/video.c
|
||||
)
|
||||
|
||||
set(ASSETS_FX src/font5x7.png)
|
||||
set(ASSETS_CG src/font8x9.png)
|
||||
set(ASSETS_FX src/font5x7.png src/gdb/icons-i1msb.png)
|
||||
set(ASSETS_CG src/font8x9.png src/gdb/icons-rgb565.png)
|
||||
fxconv_declare_assets(${ASSETS_FX} ${ASSETS_CG})
|
||||
|
||||
include_directories(
|
||||
|
|
11
TODO
11
TODO
|
@ -53,3 +53,14 @@ R61524:
|
|||
mode 1 : i3??? 396x224 @? Hz
|
||||
mode 2 : i1msb 128x64 @? Hz # <- for g1a emulation :)
|
||||
mode 3 : 2i1msb 128x64 @? Hz # <- for g1a emulation :)
|
||||
|
||||
enum {
|
||||
/* Indexed 1-bit, 0 is white, 1 is black. Row-major, left-to-right, each
|
||||
row a set of 4-byte values with leftmost pixel on the MSB. */
|
||||
IMAGE_FORMAT_I1MSB,
|
||||
/* Indexed 2-bit: white, light gray, dark gray, black. Represented as a
|
||||
pair of I1MSB buffers, the first being bit #0, the second bit #1. */
|
||||
IMAGE_FORMAT_2I1MSB,
|
||||
/* 16-bit RGB565. Row-major, left-to-right. */
|
||||
IMAGE_FORMAT_RGB565,
|
||||
};
|
||||
|
|
|
@ -35,8 +35,6 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include <gint/config.h>
|
||||
#if GINT_RENDER_RGB
|
||||
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <gint/defs/types.h>
|
||||
|
||||
|
@ -168,6 +166,8 @@ enum {
|
|||
// Image creation and destruction
|
||||
//---
|
||||
|
||||
#if GINT_RENDER_RGB
|
||||
|
||||
/* image_alloc(): Create a new (uninitialized) image
|
||||
|
||||
This function allocates a new image of the specified dimensions and format.
|
||||
|
|
91
include/gint/video.h
Normal file
91
include/gint/video.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
//---
|
||||
// gint:video - Generic video interface
|
||||
//
|
||||
// This header defines the interface for video (display) drivers. It allows
|
||||
// high-level code to manipulate the display independently of the underlying
|
||||
// hardware.
|
||||
//---
|
||||
|
||||
#ifndef GINT_VIDEO
|
||||
#define GINT_VIDEO
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <gint/defs/types.h>
|
||||
#include <gint/drivers.h>
|
||||
#include <gint/image.h>
|
||||
|
||||
/* Video mode offered by a driver for rendering. */
|
||||
typedef struct {
|
||||
/* Mode size */
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
/* Pixel format */
|
||||
int16_t format;
|
||||
/* Refresh frequency, -1 if unknown */
|
||||
int16_t freq;
|
||||
} video_mode_t;
|
||||
|
||||
/* Flags for the update function of the interface. */
|
||||
#define VIDEO_UPDATE_ENABLE_DMA 0x01
|
||||
#define VIDEO_UPDATE_ATOMIC 0x02
|
||||
|
||||
/* Video driver interface. */
|
||||
typedef struct {
|
||||
/* Associated driver (NULL if there's none). */
|
||||
gint_driver_t const *driver;
|
||||
|
||||
/* List of modes (terminated by an all-0 element). The first mode is the
|
||||
default mode and it should always be available. */
|
||||
video_mode_t const *modes;
|
||||
/* Get current video mode. */
|
||||
uint (*mode_get)(void);
|
||||
/* Set a video mode. */
|
||||
bool (*mode_set)(uint id);
|
||||
|
||||
/* Minimum and maximum brightness settings. */
|
||||
int brightness_min;
|
||||
int brightness_max;
|
||||
/* Set a brightness setting. */
|
||||
bool (*brightness_set)(int setting);
|
||||
|
||||
/* Implements video_update(); bounds are checked befoer calling. */
|
||||
bool (*update)(int x, int y, image_t const *framebuffer, int flags);
|
||||
|
||||
} video_interface_t;
|
||||
|
||||
/* Get the video interface currently in use. This can be NULL if the program is
|
||||
being linked without a display driver. */
|
||||
video_interface_t const *video_get_current_interface(void);
|
||||
|
||||
/* Get the index of the current video mode. This can be -1 if there is no
|
||||
interface; however, if there is an interface, this is always >= 0. */
|
||||
int video_get_current_mode_index(void);
|
||||
|
||||
/* Get the a pointer to the current video mode's definition. */
|
||||
video_mode_t const *video_get_current_mode(void);
|
||||
|
||||
/* Update the contents of the display from a framebuffer image. A combination
|
||||
of `VIDEO_UPDATE_*` flags can be specified to select the update method:
|
||||
- `ENABLE_DMA` allows the driver to copy using DMA, when applicable;
|
||||
- `ATOMIC` requires the driver to use an interrupt-less method.
|
||||
Returns true on success.
|
||||
|
||||
Update flags will be ignored if not applicable (e.g. `ENABLE_DMA` for a
|
||||
video interface that doesn't support DMA) but will result in an error if
|
||||
applicable and the specified method fails (e.g. DMA transfer error).
|
||||
|
||||
This function is usually called with (x,y) = (0,0) and a contiguous
|
||||
framebuffer whose size is the video mode size. Specifying images with other
|
||||
sizes, positions and strides is allowed only when they result in data
|
||||
transfers that are byte-aligned. DMA support is only guaranteed for
|
||||
contiguous input and output. The implied rectangle must be in-bounds. */
|
||||
bool video_update(int x, int y, image_t const *fb, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GINT_VIDEO */
|
9
src/gdb/fxconv-metadata.txt
Normal file
9
src/gdb/fxconv-metadata.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
icons-i1msb.png:
|
||||
type: bopti-image
|
||||
profile: mono
|
||||
name: gint_gdb_icons_i1msb
|
||||
|
||||
icons-rgb565.png:
|
||||
type: bopti-image
|
||||
profile: rgb565
|
||||
name: gint_gdb_icons_rgb565
|
|
@ -4,12 +4,40 @@
|
|||
#include <gint/ubc.h>
|
||||
#include <gint/usb-ff-bulk.h>
|
||||
#include <gint/usb.h>
|
||||
#include <gint/video.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define GDB_VISUAL_FEEDBACK 1
|
||||
|
||||
#if GDB_VISUAL_FEEDBACK
|
||||
|
||||
enum { ICON_WORKING, ICON_ERROR, ICON_COMM, ICON_IDLE };
|
||||
|
||||
static void gdb_show_stub_status(int icon)
|
||||
{
|
||||
video_mode_t const *M = video_get_current_mode();
|
||||
if(!M)
|
||||
return;
|
||||
|
||||
// extern image_t gint_gdb_icons_i1msb;
|
||||
extern image_t gint_gdb_icons_rgb565;
|
||||
|
||||
if(M->format == IMAGE_RGB565) {
|
||||
image_t sub;
|
||||
image_sub(&gint_gdb_icons_rgb565, 6*icon, 0, 7, 7, &sub);
|
||||
if(!video_update(M->width-7, 0, &sub, 0))
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
# define gdb_show_stub_status(...) ((void)0)
|
||||
#endif
|
||||
|
||||
static void gdb_hexlify(char* output_string, const uint8_t* input_buffer, size_t input_size)
|
||||
{
|
||||
const char* hex = "0123456789ABCDEF";
|
||||
|
@ -531,11 +559,11 @@ static void gdb_handle_single_step(uint32_t pc, ubc_break_mode_t break_mode)
|
|||
void gdb_main(gdb_cpu_state_t* cpu_state)
|
||||
{
|
||||
if (!gdb_started && gdb_start()) {
|
||||
// TODO: Visual signal "GDB stub error"
|
||||
gdb_show_stub_status(ICON_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Visual signal "GDB stub idle"
|
||||
gdb_show_stub_status(ICON_IDLE);
|
||||
|
||||
if (gdb_single_step_backup.single_stepped) {
|
||||
if (gdb_single_step_backup.channel0_used) {
|
||||
|
@ -557,7 +585,7 @@ void gdb_main(gdb_cpu_state_t* cpu_state)
|
|||
}
|
||||
|
||||
while (1) {
|
||||
// TODO: Visual signal "GDB stub communicating"
|
||||
gdb_show_stub_status(ICON_COMM);
|
||||
|
||||
char packet_buffer[256];
|
||||
ssize_t packet_size = gdb_recv_packet(packet_buffer, sizeof(packet_buffer));
|
||||
|
@ -566,7 +594,7 @@ void gdb_main(gdb_cpu_state_t* cpu_state)
|
|||
continue;
|
||||
}
|
||||
|
||||
// TODO: Visual signal "GDB stub working"
|
||||
gdb_show_stub_status(ICON_WORKING);
|
||||
|
||||
switch (packet_buffer[0]) {
|
||||
case '?': // Halt reason
|
||||
|
@ -620,7 +648,7 @@ void gdb_main(gdb_cpu_state_t* cpu_state)
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO: Visual signal "GDB stub idle"
|
||||
gdb_show_stub_status(ICON_IDLE);
|
||||
}
|
||||
|
||||
ret:
|
||||
|
|
BIN
src/gdb/icons-i1msb.png
Normal file
BIN
src/gdb/icons-i1msb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 626 B |
BIN
src/gdb/icons-rgb565.png
Normal file
BIN
src/gdb/icons-rgb565.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 614 B |
|
@ -9,126 +9,115 @@
|
|||
#include <gint/drivers/states.h>
|
||||
#include <gint/dma.h>
|
||||
#include <gint/drivers/r61524.h>
|
||||
#include <gint/video.h>
|
||||
#include <gint/image.h>
|
||||
#include <gint/config.h>
|
||||
|
||||
#if GINT_HW_CG
|
||||
|
||||
#define DMA SH7305_DMA
|
||||
#define POWER SH7305_POWER
|
||||
|
||||
//---
|
||||
// Device specification sheet
|
||||
//---
|
||||
|
||||
/* Registers and operations */
|
||||
enum {
|
||||
device_code_read = 0x000,
|
||||
driver_output_control = 0x001,
|
||||
entry_mode = 0x003,
|
||||
display_control_2 = 0x008,
|
||||
low_power_control = 0x00b,
|
||||
|
||||
ram_address_horizontal = 0x200,
|
||||
ram_address_vertical = 0x201,
|
||||
write_data = 0x202,
|
||||
|
||||
horizontal_ram_start = 0x210,
|
||||
horizontal_ram_end = 0x211,
|
||||
vertical_ram_start = 0x212,
|
||||
vertical_ram_end = 0x213,
|
||||
};
|
||||
|
||||
typedef word_union(entry_mode_t,
|
||||
uint TRI :1;
|
||||
uint DFM :1;
|
||||
uint :1;
|
||||
uint BGR :1;
|
||||
uint :2;
|
||||
uint HWM :1;
|
||||
uint :1;
|
||||
uint ORG :1;
|
||||
uint :1;
|
||||
uint ID :2;
|
||||
uint AM :1;
|
||||
uint :1;
|
||||
uint EPF :2;
|
||||
);
|
||||
|
||||
//---
|
||||
// Device communication primitives
|
||||
//---
|
||||
/* Registers */
|
||||
#define REG_DEVICE_CODE_READ 0x000
|
||||
#define REG_DRIVER_OUTPUT_CTL 0x001
|
||||
#define REG_ENTRY_MODE 0x003
|
||||
#define REG_DISPLAY_CTL2 0x008
|
||||
#define REG_LOW_POWER_CTL 0x00b
|
||||
#define REG_HADDR 0x200
|
||||
#define REG_VADDR 0x201
|
||||
#define REG_DATA 0x202
|
||||
#define REG_HSTART 0x210
|
||||
#define REG_HEND 0x211
|
||||
#define REG_VSTART 0x212
|
||||
#define REG_VEND 0x213
|
||||
|
||||
/* Interface with the controller */
|
||||
static volatile uint16_t *intf = (void *)0xb4000000;
|
||||
static volatile uint16_t *DISPLAY = (void *)0xb4000000;
|
||||
/* Bit 4 of Port R controls the RS bit of the display driver */
|
||||
static volatile uint8_t *PRDR = (void *)0xa405013c;
|
||||
|
||||
/* Select a register */
|
||||
GINLINE static void select(uint16_t reg)
|
||||
{
|
||||
/* Clear RS and write the register number */
|
||||
*PRDR &= ~0x10;
|
||||
synco();
|
||||
*intf = reg;
|
||||
*DISPLAY = reg;
|
||||
synco();
|
||||
|
||||
/* Set RS back. We don't do this in read()/write() because the display
|
||||
driver is optimized for consecutive GRAM access. LCD-transfers will
|
||||
be faster when executing select() followed by several calls to
|
||||
write(). (Although most applications should use the DMA instead.) */
|
||||
/* Set RS=1 to allow consecutive reads/writes after a select() */
|
||||
*PRDR |= 0x10;
|
||||
synco();
|
||||
}
|
||||
|
||||
GINLINE static uint16_t read(void)
|
||||
{
|
||||
return *intf;
|
||||
}
|
||||
|
||||
GINLINE static void write(uint16_t data)
|
||||
{
|
||||
*intf = data;
|
||||
*DISPLAY = data;
|
||||
}
|
||||
|
||||
uint16_t r61524_get(int ID)
|
||||
GINLINE uint16_t r61524_get(int ID)
|
||||
{
|
||||
select(ID);
|
||||
return read();
|
||||
return *DISPLAY;
|
||||
}
|
||||
|
||||
void r61524_set(int ID, uint16_t value)
|
||||
GINLINE void r61524_set(int ID, uint16_t value)
|
||||
{
|
||||
select(ID);
|
||||
write(value);
|
||||
*DISPLAY = value;
|
||||
}
|
||||
|
||||
//---
|
||||
// Window management
|
||||
// Window management
|
||||
//---
|
||||
|
||||
void r61524_win_get(uint16_t *HSA, uint16_t *HEA, uint16_t *VSA, uint16_t *VEA)
|
||||
{
|
||||
select(horizontal_ram_start);
|
||||
*HSA = read();
|
||||
select(horizontal_ram_end);
|
||||
*HEA = read();
|
||||
|
||||
select(vertical_ram_start);
|
||||
*VSA = read();
|
||||
select(vertical_ram_end);
|
||||
*VEA = read();
|
||||
*HSA = r61524_get(REG_HSTART);
|
||||
*HEA = r61524_get(REG_HEND);
|
||||
*VSA = r61524_get(REG_VSTART);
|
||||
*VEA = r61524_get(REG_VEND);
|
||||
}
|
||||
|
||||
void r61524_win_set(uint16_t HSA, uint16_t HEA, uint16_t VSA, uint16_t VEA)
|
||||
{
|
||||
select(horizontal_ram_start);
|
||||
write(HSA);
|
||||
select(horizontal_ram_end);
|
||||
write(HEA);
|
||||
r61524_set(REG_HSTART, HSA);
|
||||
r61524_set(REG_HEND, HEA);
|
||||
r61524_set(REG_VSTART, VSA);
|
||||
r61524_set(REG_VEND, VEA);
|
||||
}
|
||||
|
||||
select(vertical_ram_start);
|
||||
write(VSA);
|
||||
select(vertical_ram_end);
|
||||
write(VEA);
|
||||
//---
|
||||
// Backlight management
|
||||
//---
|
||||
|
||||
void r61525_brightness_set(int level)
|
||||
{
|
||||
bool GLOBAL_backlight_high_bit[7] = { /* at 0x80399530 */
|
||||
false, false, false, false,
|
||||
true, true, true,
|
||||
};
|
||||
uint8_t GLOBAL_backlight_table[7] = { /* at 0x80399537 */
|
||||
0x14, 0x4b, 0x78, 0xd2,
|
||||
0x6e, 0xa0, 0xc8,
|
||||
};
|
||||
uint8_t GLOBAL_0[10] = { /* at 0x8039953e */
|
||||
0x00, 0x01, 0x02, 0x03, 0x07,
|
||||
0x0f, 0x1f, 0x3f, 0x7f, 0xff,
|
||||
};
|
||||
|
||||
if(level < 1)
|
||||
level = 1;
|
||||
if(level > 5)
|
||||
level = 5;
|
||||
|
||||
int8_t volatile *PNDR = (void *)0xa4050138;
|
||||
if(GLOBAL_backlight_high_bit[level])
|
||||
*PNDR |= 0x10;
|
||||
else
|
||||
*PNDR &= 0xef;
|
||||
|
||||
synco();
|
||||
|
||||
r61524_set(0x5a2, GLOBAL_0[(level < 2) ? 9 : 5]);
|
||||
r61524_set(0x5a1, GLOBAL_backlight_table[level]);
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -141,13 +130,11 @@ void r61524_start_frame(int xmin, int xmax, int ymin, int ymax)
|
|||
{
|
||||
/* Move the window to the desired region, then select address 0 */
|
||||
r61524_win_set(395-xmax, 395-xmin, ymin, ymax);
|
||||
select(ram_address_horizontal);
|
||||
write(0);
|
||||
select(ram_address_vertical);
|
||||
write(0);
|
||||
r61524_set(REG_HADDR, 0);
|
||||
r61524_set(REG_VADDR, 0);
|
||||
|
||||
/* Bind address 0xb4000000 to the data write command */
|
||||
select(write_data);
|
||||
select(REG_DATA);
|
||||
}
|
||||
|
||||
void r61524_display(uint16_t *vram, int start, int height, int method)
|
||||
|
@ -281,6 +268,45 @@ void r61524_display_gray_128x64(uint32_t *light, uint32_t *dark)
|
|||
write(border);
|
||||
}
|
||||
|
||||
static bool r61524_update(int x, int y, image_t const *fb, int flags)
|
||||
{
|
||||
// TODO: r61524_update: Handle the mono cases
|
||||
if(fb->format != IMAGE_RGB565)
|
||||
return false;
|
||||
|
||||
uint w = fb->width;
|
||||
uint h = fb->height;
|
||||
|
||||
dma_transfer_wait(0);
|
||||
r61524_start_frame(x, x+w-1, y, y+h-1);
|
||||
|
||||
/* DMA if enabled */
|
||||
bool dma_possible = (!x && w == 396 && fb->stride == 396*2 && !(h%4));
|
||||
if((flags & VIDEO_UPDATE_ENABLE_DMA) && dma_possible) {
|
||||
void *src = fb->data;
|
||||
void *dst = (void *)DISPLAY;
|
||||
int blocks = 99 * (h / 4);
|
||||
|
||||
if(flags & VIDEO_UPDATE_ATOMIC)
|
||||
dma_transfer_atomic(0, DMA_32B, blocks, src, DMA_INC,
|
||||
dst, DMA_FIXED);
|
||||
else
|
||||
dma_transfer_async(0, DMA_32B, blocks, src, DMA_INC,
|
||||
dst, DMA_FIXED, GINT_CALL_NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t *pixels = fb->data;
|
||||
|
||||
for(int y = 0; y < fb->height; y++) {
|
||||
for(int x = 0; x < fb->width; x++)
|
||||
write(pixels[x]);
|
||||
pixels = (void *)pixels + fb->stride;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---
|
||||
// State and driver metadata
|
||||
//---
|
||||
|
@ -303,4 +329,33 @@ gint_driver_t drv_r61524 = {
|
|||
};
|
||||
GINT_DECLARE_DRIVER(26, drv_r61524);
|
||||
|
||||
//---
|
||||
// Video driver interface
|
||||
//---
|
||||
|
||||
static video_mode_t r61524_modes[] = {
|
||||
/* Standard full-screen full-color mode */
|
||||
{ 396, 224, IMAGE_RGB565, -1 },
|
||||
#if 0
|
||||
/* R61524 8-color mode with lower power consumption */
|
||||
{ 396, 224, IMAGE_P8_RGB565, -1 }, // TODO: actually P3, that's closest
|
||||
/* T6K11-emulation black-and-white mode */
|
||||
{ 128, 64, IMAGE_I1MSB, -1 },
|
||||
/* T6K11-emulation gray mode */
|
||||
{ 128, 64, IMAGE_2I1MSB, -1 },
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
video_interface_t r61524_video = {
|
||||
.driver = &drv_r61524,
|
||||
.modes = r61524_modes,
|
||||
.mode_get = NULL, // TODO
|
||||
.mode_set = NULL, // TODO
|
||||
.brightness_min = 0, // TODO
|
||||
.brightness_max = 0, // TODO
|
||||
.brightness_set = NULL,
|
||||
.update = r61524_update,
|
||||
};
|
||||
|
||||
#endif /* GINT_HW_CG */
|
||||
|
|
39
src/video/video.c
Normal file
39
src/video/video.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <gint/video.h>
|
||||
#include <gint/config.h>
|
||||
|
||||
// TODO: video: Have interface set by gint pre-main call instead
|
||||
extern video_interface_t t6k11_video, r61524_video;
|
||||
static video_interface_t const *current_intf =
|
||||
GINT_HW_SWITCH(NULL, &r61524_video);
|
||||
static int current_mode_index = GINT_HW_SWITCH(-1, 0);
|
||||
|
||||
video_interface_t const *video_get_current_interface(void)
|
||||
{
|
||||
return current_intf;
|
||||
}
|
||||
|
||||
int video_get_current_mode_index(void)
|
||||
{
|
||||
return current_mode_index;
|
||||
}
|
||||
|
||||
video_mode_t const *video_get_current_mode(void)
|
||||
{
|
||||
return (current_intf && current_mode_index >= 0)
|
||||
? ¤t_intf->modes[current_mode_index]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
bool video_update(int x, int y, image_t const *fb, int flags)
|
||||
{
|
||||
video_mode_t const *M = video_get_current_mode();
|
||||
|
||||
if(!M || !current_intf->update || fb->format != M->format)
|
||||
return false;
|
||||
if(x < 0 || y < 0)
|
||||
return false;
|
||||
if(x + fb->width > M->width || y + fb->height > M->height)
|
||||
return false;
|
||||
|
||||
return current_intf->update(x, y, fb, flags);
|
||||
}
|
Loading…
Reference in a new issue