mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
rearrange globals
scripted find/replace gives slightly better code on ARM, less unnecessary asm, ~400 bytes saved
This commit is contained in:
parent
759c9d3846
commit
93f9619ed8
47 changed files with 532 additions and 573 deletions
|
@ -309,7 +309,7 @@ static void blitscreen_clut(void)
|
|||
blit_16bit_mode = 0;
|
||||
}
|
||||
|
||||
if ((PicoOpt&0x10) && Pico.m.dirtyPal)
|
||||
if ((PicoIn.opt&0x10) && Pico.m.dirtyPal)
|
||||
do_pal_update(0, 0);
|
||||
|
||||
sceKernelDcacheWritebackAll();
|
||||
|
@ -395,7 +395,7 @@ static void dbg_text(void)
|
|||
/* called after rendering is done, but frame emulation is not finished */
|
||||
void blit1(void)
|
||||
{
|
||||
if (PicoOpt&0x10)
|
||||
if (PicoIn.opt&0x10)
|
||||
{
|
||||
int i;
|
||||
unsigned char *pd;
|
||||
|
@ -406,7 +406,7 @@ void blit1(void)
|
|||
memset32((int *)pd, 0xe0e0e0e0, 320/4);
|
||||
}
|
||||
|
||||
if (PicoAHW & PAHW_PICO)
|
||||
if (PicoIn.AHW & PAHW_PICO)
|
||||
draw_pico_ptr();
|
||||
|
||||
blitscreen_clut();
|
||||
|
@ -424,7 +424,7 @@ static void blit2(const char *fps, const char *notice, int lagging_behind)
|
|||
|
||||
//dbg_text();
|
||||
|
||||
if ((emu_opt & 0x400) && (PicoAHW & PAHW_MCD))
|
||||
if ((emu_opt & 0x400) && (PicoIn.AHW & PAHW_MCD))
|
||||
cd_leds();
|
||||
|
||||
if (currentConfig.EmuOpt & 0x2000) { // want vsync
|
||||
|
@ -571,10 +571,10 @@ void pemu_sound_start(void)
|
|||
|
||||
samples_made = samples_done = 0;
|
||||
|
||||
if (PsndRate != PsndRate_old || (PicoOpt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
|
||||
if (PsndRate != PsndRate_old || (PicoIn.opt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
|
||||
PsndRerate(Pico.m.frame_count ? 1 : 0);
|
||||
}
|
||||
stereo=(PicoOpt&8)>>3;
|
||||
stereo=(PicoIn.opt&8)>>3;
|
||||
|
||||
samples_block = Pico.m.pal ? SOUND_BLOCK_SIZE_PAL : SOUND_BLOCK_SIZE_NTSC;
|
||||
if (PsndRate <= 22050) samples_block /= 2;
|
||||
|
@ -597,7 +597,7 @@ void pemu_sound_start(void)
|
|||
samples_made = samples_block; // send 1 empty block first..
|
||||
PsndOut = sndBuffer;
|
||||
PsndRate_old = PsndRate;
|
||||
PicoOpt_old = PicoOpt;
|
||||
PicoOpt_old = PicoIn.opt;
|
||||
pal_old = Pico.m.pal;
|
||||
}
|
||||
}
|
||||
|
@ -664,20 +664,20 @@ static void writeSound(int len)
|
|||
|
||||
static void SkipFrame(void)
|
||||
{
|
||||
PicoSkipFrame=1;
|
||||
PicoIn.skipFrame=1;
|
||||
PicoFrame();
|
||||
PicoSkipFrame=0;
|
||||
PicoIn.skipFrame=0;
|
||||
}
|
||||
|
||||
void pemu_forced_frame(int no_scale, int do_emu)
|
||||
{
|
||||
int po_old = PicoOpt;
|
||||
int po_old = PicoIn.opt;
|
||||
int eo_old = currentConfig.EmuOpt;
|
||||
|
||||
PicoOpt &= ~POPT_ALT_RENDERER;
|
||||
PicoOpt |= POPT_ACC_SPRITES;
|
||||
PicoIn.opt &= ~POPT_ALT_RENDERER;
|
||||
PicoIn.opt |= POPT_ACC_SPRITES;
|
||||
if (!no_scale)
|
||||
PicoOpt |= POPT_EN_SOFTSCALE;
|
||||
PicoIn.opt |= POPT_EN_SOFTSCALE;
|
||||
currentConfig.EmuOpt |= 0x80;
|
||||
|
||||
vidResetMode();
|
||||
|
@ -692,7 +692,7 @@ void pemu_forced_frame(int no_scale, int do_emu)
|
|||
blit1();
|
||||
sceGuSync(0,0);
|
||||
|
||||
PicoOpt = po_old;
|
||||
PicoIn.opt = po_old;
|
||||
currentConfig.EmuOpt = eo_old;
|
||||
}
|
||||
|
||||
|
@ -703,7 +703,7 @@ static void RunEventsPico(unsigned int events, unsigned int keys)
|
|||
|
||||
if (pico_inp_mode != 0)
|
||||
{
|
||||
PicoPad[0] &= ~0x0f; // release UDLR
|
||||
PicoIn.pad[0] &= ~0x0f; // release UDLR
|
||||
if (keys & PBTN_UP) { pico_pen_y--; if (pico_pen_y < 8) pico_pen_y = 8; }
|
||||
if (keys & PBTN_DOWN) { pico_pen_y++; if (pico_pen_y > 224-PICO_PEN_ADJUST_Y) pico_pen_y = 224-PICO_PEN_ADJUST_Y; }
|
||||
if (keys & PBTN_LEFT) { pico_pen_x--; if (pico_pen_x < 0) pico_pen_x = 0; }
|
||||
|
@ -754,12 +754,12 @@ static void RunEvents(unsigned int which)
|
|||
}
|
||||
if (which & 0x0400) // switch renderer
|
||||
{
|
||||
if (PicoOpt&0x10) { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; }
|
||||
else { PicoOpt|= 0x10; currentConfig.EmuOpt &= ~0x80; }
|
||||
if (PicoIn.opt&0x10) { PicoIn.opt&=~0x10; currentConfig.EmuOpt |= 0x80; }
|
||||
else { PicoIn.opt|= 0x10; currentConfig.EmuOpt &= ~0x80; }
|
||||
|
||||
vidResetMode();
|
||||
|
||||
if (PicoOpt & POPT_ALT_RENDERER)
|
||||
if (PicoIn.opt & POPT_ALT_RENDERER)
|
||||
emu_status_msg("fast renderer");
|
||||
else if (currentConfig.EmuOpt&0x80)
|
||||
emu_status_msg("accurate renderer");
|
||||
|
@ -794,11 +794,11 @@ static void updateKeys(void)
|
|||
|
||||
keys &= CONFIGURABLE_KEYS;
|
||||
|
||||
PicoPad[0] = allActions[0] & 0xfff;
|
||||
PicoPad[1] = allActions[1] & 0xfff;
|
||||
PicoIn.pad[0] = allActions[0] & 0xfff;
|
||||
PicoIn.pad[1] = allActions[1] & 0xfff;
|
||||
|
||||
if (allActions[0] & 0x7000) emu_DoTurbo(&PicoPad[0], allActions[0]);
|
||||
if (allActions[1] & 0x7000) emu_DoTurbo(&PicoPad[1], allActions[1]);
|
||||
if (allActions[0] & 0x7000) emu_DoTurbo(&PicoIn.pad[0], allActions[0]);
|
||||
if (allActions[1] & 0x7000) emu_DoTurbo(&PicoIn.pad[1], allActions[1]);
|
||||
|
||||
events = (allActions[0] | allActions[1]) >> 16;
|
||||
|
||||
|
@ -809,7 +809,7 @@ static void updateKeys(void)
|
|||
|
||||
events &= ~prevEvents;
|
||||
|
||||
if (PicoAHW == PAHW_PICO)
|
||||
if (PicoIn.AHW == PAHW_PICO)
|
||||
RunEventsPico(events, keys);
|
||||
if (events) RunEvents(events);
|
||||
if (movie_data) emu_updateMovie();
|
||||
|
@ -861,7 +861,7 @@ void pemu_loop(void)
|
|||
target_frametime = Pico.m.pal ? (1000000<<8)/50 : (1000000<<8)/60+1;
|
||||
reset_timing = 1;
|
||||
|
||||
if (PicoAHW & PAHW_MCD) {
|
||||
if (PicoIn.AHW & PAHW_MCD) {
|
||||
// prepare CD buffer
|
||||
PicoCDBufferInit();
|
||||
// mp3...
|
||||
|
@ -986,7 +986,7 @@ void pemu_loop(void)
|
|||
|
||||
updateKeys();
|
||||
|
||||
if (!(PicoOpt&0x10))
|
||||
if (!(PicoIn.opt&0x10))
|
||||
EmuScanPrepare();
|
||||
|
||||
PicoFrame();
|
||||
|
@ -1019,7 +1019,7 @@ void pemu_loop(void)
|
|||
|
||||
emu_set_fastforward(0);
|
||||
|
||||
if (PicoAHW & PAHW_MCD) PicoCDBufferFree();
|
||||
if (PicoIn.AHW & PAHW_MCD) PicoCDBufferFree();
|
||||
|
||||
if (PsndOut != NULL) {
|
||||
pemu_sound_stop();
|
||||
|
@ -1039,7 +1039,7 @@ void pemu_loop(void)
|
|||
|
||||
void emu_HandleResume(void)
|
||||
{
|
||||
if (!(PicoAHW & PAHW_MCD)) return;
|
||||
if (!(PicoIn.AHW & PAHW_MCD)) return;
|
||||
|
||||
// reopen first CD track
|
||||
if (Pico_mcd->TOC.Tracks[0].F != NULL)
|
||||
|
|
|
@ -506,7 +506,7 @@ static void draw_savestate_bg(int slot)
|
|||
}
|
||||
|
||||
if (file) {
|
||||
if (PicoAHW & PAHW_MCD) {
|
||||
if (PicoIn.AHW & PAHW_MCD) {
|
||||
PicoCdLoadStateGfx(file);
|
||||
} else {
|
||||
areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file
|
||||
|
@ -708,7 +708,7 @@ menu_entry ctrlopt_entries[] =
|
|||
{ "Player 1", MB_NONE, MA_CTRL_PLAYER1, NULL, 0, 0, 0, 1, 0 },
|
||||
{ "Player 2", MB_NONE, MA_CTRL_PLAYER2, NULL, 0, 0, 0, 1, 0 },
|
||||
{ "Emulator controls", MB_NONE, MA_CTRL_EMU, NULL, 0, 0, 0, 1, 0 },
|
||||
{ "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoOpt, 0x020, 0, 0, 1, 1 },
|
||||
{ "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoIn.opt, 0x020, 0, 0, 1, 1 },
|
||||
{ "Turbo rate", MB_RANGE, MA_CTRL_TURBO_RATE, ¤tConfig.turbo_rate, 0, 1, 30, 1, 1 },
|
||||
{ "Done", MB_NONE, MA_CTRL_DONE, NULL, 0, 0, 0, 1, 0 },
|
||||
};
|
||||
|
@ -763,7 +763,7 @@ static void kc_sel_loop(void)
|
|||
if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }
|
||||
if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }
|
||||
if (inp & PBTN_CIRCLE) {
|
||||
int is_6button = PicoOpt & POPT_6BTN_PAD;
|
||||
int is_6button = PicoIn.opt & POPT_6BTN_PAD;
|
||||
switch (selected_id) {
|
||||
case MA_CTRL_PLAYER1: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 0); return;
|
||||
case MA_CTRL_PLAYER2: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 1); return;
|
||||
|
@ -786,12 +786,12 @@ menu_entry cdopt_entries[] =
|
|||
{ NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 },
|
||||
{ NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 },
|
||||
{ "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, ¤tConfig.EmuOpt, 0x0400, 0, 0, 1, 1 },
|
||||
{ "CDDA audio", MB_ONOFF, MA_CDOPT_CDDA, &PicoOpt, 0x0800, 0, 0, 1, 1 },
|
||||
{ "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoOpt, 0x0400, 0, 0, 1, 1 },
|
||||
{ "CDDA audio", MB_ONOFF, MA_CDOPT_CDDA, &PicoIn.opt, 0x0800, 0, 0, 1, 1 },
|
||||
{ "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoIn.opt, 0x0400, 0, 0, 1, 1 },
|
||||
{ NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1, 1 },
|
||||
{ "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoOpt, 0x8000, 0, 0, 1, 1 },
|
||||
{ "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoOpt, 0x1000, 0, 0, 1, 1 },
|
||||
{ "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoOpt, 0x2000, 0, 0, 1, 1 },
|
||||
{ "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoIn.opt, 0x8000, 0, 0, 1, 1 },
|
||||
{ "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoIn.opt, 0x1000, 0, 0, 1, 1 },
|
||||
{ "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoIn.opt, 0x2000, 0, 0, 1, 1 },
|
||||
{ "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1, 0 },
|
||||
};
|
||||
|
||||
|
@ -1115,14 +1115,14 @@ static void dispmenu_loop_options(void)
|
|||
|
||||
menu_entry opt2_entries[] =
|
||||
{
|
||||
{ "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoOpt, 0x40000, 0, 0, 1, 1 },
|
||||
{ "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoOpt, 0x00004, 0, 0, 1, 1 },
|
||||
{ "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoOpt, 0x00001, 0, 0, 1, 1 },
|
||||
{ "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496, &PicoOpt, 0x00002, 0, 0, 1, 1 },
|
||||
{ "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoIn.opt, 0x40000, 0, 0, 1, 1 },
|
||||
{ "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoIn.opt, 0x00004, 0, 0, 1, 1 },
|
||||
{ "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoIn.opt, 0x00001, 0, 0, 1, 1 },
|
||||
{ "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496, &PicoIn.opt, 0x00002, 0, 0, 1, 1 },
|
||||
{ "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, ¤tConfig.EmuOpt, 0x00008, 0, 0, 1, 1 },
|
||||
{ "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, ¤tConfig.EmuOpt, 0x00020, 0, 0, 1, 1 },
|
||||
{ "Status line in main menu", MB_ONOFF, MA_OPT2_STATUS_LINE, ¤tConfig.EmuOpt, 0x20000, 0, 0, 1, 1 },
|
||||
{ "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoOpt, 0x80000, 0, 0, 1, 1 },
|
||||
{ "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoIn.opt, 0x80000, 0, 0, 1, 1 },
|
||||
{ "Disable frame limiter", MB_ONOFF, MA_OPT2_NO_FRAME_LIMIT, ¤tConfig.EmuOpt, 0x40000, 0, 0, 1, 1 },
|
||||
{ "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 },
|
||||
};
|
||||
|
@ -1182,7 +1182,7 @@ static void amenu_loop_options(void)
|
|||
menu_entry opt_entries[] =
|
||||
{
|
||||
{ NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1, 1 },
|
||||
{ "Accurate sprites", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoOpt, 0x080, 0, 0, 0, 1 },
|
||||
{ "Accurate sprites", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoIn.opt, 0x080, 0, 0, 0, 1 },
|
||||
{ "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, ¤tConfig.EmuOpt, 0x0002, 0, 0, 1, 1 },
|
||||
{ NULL, MB_RANGE, MA_OPT_FRAMESKIP, ¤tConfig.Frameskip, 0, -1, 16, 1, 1 },
|
||||
{ "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, ¤tConfig.EmuOpt, 0x0004, 0, 0, 1, 1 },
|
||||
|
@ -1211,7 +1211,7 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
|
|||
switch (entry->id)
|
||||
{
|
||||
case MA_OPT_RENDERER:
|
||||
if (PicoOpt & 0x10)
|
||||
if (PicoIn.opt & 0x10)
|
||||
str = "fast";
|
||||
else if (currentConfig.EmuOpt & 0x80)
|
||||
str = "accurate";
|
||||
|
@ -1226,11 +1226,11 @@ static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *para
|
|||
text_out16(x, y, "Frameskip %s", str24);
|
||||
break;
|
||||
case MA_OPT_SOUND_QUALITY:
|
||||
str = (PicoOpt&0x08)?"stereo":"mono";
|
||||
str = (PicoIn.opt&0x08)?"stereo":"mono";
|
||||
text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);
|
||||
break;
|
||||
case MA_OPT_REGION:
|
||||
text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));
|
||||
text_out16(x, y, "Region: %s", me_region_name(PicoIn.regionOverride, PicoIn.autoRgnOrder));
|
||||
break;
|
||||
case MA_OPT_CONFIRM_STATES:
|
||||
switch ((currentConfig.EmuOpt >> 9) & 5) {
|
||||
|
@ -1291,31 +1291,31 @@ static void region_prevnext(int right)
|
|||
static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };
|
||||
int i;
|
||||
if (right) {
|
||||
if (!PicoRegionOverride) {
|
||||
if (!PicoIn.regionOverride) {
|
||||
for (i = 0; i < 6; i++)
|
||||
if (rgn_orders[i] == PicoAutoRgnOrder) break;
|
||||
if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];
|
||||
else PicoRegionOverride=1;
|
||||
if (rgn_orders[i] == PicoIn.autoRgnOrder) break;
|
||||
if (i < 5) PicoIn.autoRgnOrder = rgn_orders[i+1];
|
||||
else PicoIn.regionOverride=1;
|
||||
}
|
||||
else PicoRegionOverride<<=1;
|
||||
if (PicoRegionOverride > 8) PicoRegionOverride = 8;
|
||||
else PicoIn.regionOverride<<=1;
|
||||
if (PicoIn.regionOverride > 8) PicoIn.regionOverride = 8;
|
||||
} else {
|
||||
if (!PicoRegionOverride) {
|
||||
if (!PicoIn.regionOverride) {
|
||||
for (i = 0; i < 6; i++)
|
||||
if (rgn_orders[i] == PicoAutoRgnOrder) break;
|
||||
if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];
|
||||
if (rgn_orders[i] == PicoIn.autoRgnOrder) break;
|
||||
if (i > 0) PicoIn.autoRgnOrder = rgn_orders[i-1];
|
||||
}
|
||||
else PicoRegionOverride>>=1;
|
||||
else PicoIn.regionOverride>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
static void menu_options_save(void)
|
||||
{
|
||||
if (PicoRegionOverride) {
|
||||
if (PicoIn.regionOverride) {
|
||||
// force setting possibly changed..
|
||||
Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;
|
||||
Pico.m.pal = (PicoIn.regionOverride == 2 || PicoIn.regionOverride == 8) ? 1 : 0;
|
||||
}
|
||||
if (!(PicoOpt & POPT_6BTN_PAD)) {
|
||||
if (!(PicoIn.opt & POPT_6BTN_PAD)) {
|
||||
// unbind XYZ MODE, just in case
|
||||
unbind_action(0xf00);
|
||||
}
|
||||
|
@ -1344,11 +1344,11 @@ static int menu_loop_options(void)
|
|||
if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&PBTN_RIGHT) ? 1 : 0)) {
|
||||
switch (selected_id) {
|
||||
case MA_OPT_RENDERER:
|
||||
if ((PicoOpt & 0x10) || !(currentConfig.EmuOpt & 0x80)) {
|
||||
PicoOpt &= ~0x10;
|
||||
if ((PicoIn.opt & 0x10) || !(currentConfig.EmuOpt & 0x80)) {
|
||||
PicoIn.opt &= ~0x10;
|
||||
currentConfig.EmuOpt |= 0x80;
|
||||
} else {
|
||||
PicoOpt |= 0x10;
|
||||
PicoIn.opt |= 0x10;
|
||||
currentConfig.EmuOpt &= ~0x80;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -466,7 +466,7 @@ int mp3_get_offset(void) // 0-1023
|
|||
unsigned int offs1024 = 0;
|
||||
int cdda_on;
|
||||
|
||||
cdda_on = (PicoAHW & PAHW_MCD) && (PicoOpt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&
|
||||
cdda_on = (PicoIn.AHW & PAHW_MCD) && (PicoIn.opt&0x800) && !(Pico_mcd->s68k_regs[0x36] & 1) &&
|
||||
(Pico_mcd->scd.Status_CDC & 1) && mp3_handle >= 0;
|
||||
|
||||
if (cdda_on) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue