PCE: pce_joypad_read() only returning low nibble?
bcampbell opened this issue · comments
I wrote a little PCE program to display the joypad value, and only the lower bits seem to work. Start, Select and the two fire buttons seem fine, but I get no directions.
It could be my emulator config... but when I run a game rom with the same commandline options the joypad seems to work fine.
Of course, github doesn't let me attach a C file... so here's my test program inlined!
// Show joypad input as hex in top left of screen (and a timer in the top right).
//
// compile:
// $ mos-pce-clang -o demo demo.c
//
// run:
// $ retroarch --verbose --libretro /usr/lib/x86_64-linux-gnu/libretro/mednafen_pce_fast_libretro.so demo
#define PCE_CONFIG_IMPLEMENTATION
#include <pce.h>
// Aiming for largest possible contiguous ROM without any bankswitching.
PCE_ROM_FIXED_BANK_SIZE(6);
// our vram memory map
#define VRAM_BAT 0x0000 // Background Attribute Table (tilemap)
#define VRAM_CG 0x8000 // Character Generator (tile definitions)
// index of first tile
#define BASECHAR (VRAM_CG/32)
// size of map, in tile coords
#define CW 32
#define CH 32
void loadtiles();
void clr(uint8_t c);
void plonkchr(uint8_t cx, uint8_t cy, uint8_t chr);
void plonkhex(uint8_t cx, uint8_t cy, uint8_t v);
void showpad();
volatile uint8_t tick = 0;
__attribute__((interrupt)) void irq_vdc(void) {
uint8_t status = *IO_VDC_STATUS;
if (status & VDC_FLAG_VBLANK) {
++tick;
}
}
void waitvbl()
{
uint8_t tmp = tick;
while (tmp == tick) {}
}
int main(void) {
// Set up vblank interrupt
pce_vdc_irq_vblank_enable();
pce_irq_enable(IRQ_VDC);
pce_cpu_irq_enable();
// set up screen and bg
pce_vdc_set_resolution(256,240, 0);
pce_vdc_bg_set_size(VDC_BG_SIZE_32_32);
pce_vdc_bg_enable();
loadtiles();
// set up first bg palette.
*IO_VCE_COLOR_INDEX = 0x000;
*IO_VCE_COLOR_DATA = 0x0000;
for( uint16_t i=1; i<16; ++i) {
*IO_VCE_COLOR_INDEX = 0x0 + i;
*IO_VCE_COLOR_DATA = 0xffff;
}
clr(0);
while (1) {
// print joypad at top left
uint8_t j = pce_joypad_read();
plonkhex(0, 0, j);
// print ticks at top right, just so we can see something happening.
plonkhex(CW-2, 0, tick);
waitvbl();
}
}
// print v as a hex value, at tilemap position cx,cy.
void plonkhex(uint8_t cx, uint8_t cy, uint8_t v)
{
char buf[2];
buf[0] = (v >> 4)+1;
buf[1] = (v & 0x0f)+1;
plonkchr(cx,cy,buf[0]);
plonkchr(cx+1,cy,buf[1]);
}
// Some tiledata for showing hex numbers.
// (Just a single bitplane - loadtiles() will duplicate them)
const uint8_t tiles[17*8] = {
// space
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
// 0
0b01111100,
0b11000110,
0b11000110,
0b11000110,
0b11000110,
0b11000110,
0b01111100,
0b00000000,
// 1
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00000000,
// 2
0b01111100,
0b11000110,
0b00000110,
0b00011100,
0b00110000,
0b01100000,
0b11111110,
0b00000000,
// 3
0b01111100,
0b11000110,
0b00000110,
0b00111100,
0b00000110,
0b11000110,
0b01111100,
0b00000000,
// 4
0b11000000,
0b11000000,
0b11000000,
0b11011000,
0b11011000,
0b11111110,
0b00011000,
0b00000000,
// 5
0b11111110,
0b11000000,
0b11000000,
0b11111100,
0b00000110,
0b11000110,
0b01111100,
0b00000000,
// 6
0b11000000,
0b11000000,
0b11000000,
0b11111100,
0b11000110,
0b11000110,
0b01111100,
0b00000000,
// 7
0b11111110,
0b00000110,
0b00000110,
0b00000110,
0b00000110,
0b00000110,
0b00000110,
0b00000000,
// 8
0b01111100,
0b11000110,
0b11000110,
0b01111100,
0b11000110,
0b11000110,
0b01111100,
0b00000000,
// 9
0b01111100,
0b11000110,
0b11000110,
0b01111110,
0b00000110,
0b00000110,
0b00000110,
0b00000000,
// A
0b01111100,
0b11000110,
0b11000110,
0b11111110,
0b11000110,
0b11000110,
0b11000110,
0b00000000,
// B
0b11111100,
0b11000110,
0b11000110,
0b11111100,
0b11000110,
0b11000110,
0b11111100,
0b00000000,
// C
0b01111100,
0b11000110,
0b11000000,
0b11000000,
0b11000000,
0b11000110,
0b01111100,
0b00000000,
// D
0b11111100,
0b11000110,
0b11000110,
0b11000110,
0b11000110,
0b11000110,
0b11111100,
0b00000000,
// E
0b11111110,
0b11000000,
0b11000000,
0b11111110,
0b11000000,
0b11000000,
0b11111110,
0b00000000,
// F
0b11111110,
0b11000000,
0b11000000,
0b11111000,
0b11000000,
0b11000000,
0b11000000,
0b00000000,
};
// load our tiles into VRAM (starting at VRAM_CG)
void loadtiles()
{
const uint8_t *src = tiles;
pce_vdc_set_copy_word();
for (uint8_t t=0; t<17; ++t) {
uint8_t buf[4*8];
for (uint8_t y=0; y<8; ++y) {
uint8_t b = *src++;
// use the src data for all 4 bitplanes
buf[y*2 + 0] = b;
buf[y*2 + 1] = b;
buf[16 + y*2 + 0] = b;
buf[16 + y*2 + 1] = b;
}
pce_vdc_copy_to_vram((VRAM_CG+(t*32))/2, (const void *)buf, sizeof(buf));
}
}
// set a single tile at cx,cy
void plonkchr(uint8_t cx, uint8_t cy, uint8_t chr)
{
uint16_t dest = VRAM_BAT + ((cy*CW + cx)*2);
uint16_t tmp = BASECHAR + chr;
pce_vdc_copy_to_vram(dest/2, &tmp, 2);
}
// clear the screen using given tile
void clr(uint8_t chr)
{
uint16_t dest = VRAM_BAT;
for (uint8_t cy = 0; cy < CH; ++cy)
{
uint16_t linebuf[CW];
for (uint8_t cx = 0; cx < CW; ++cx)
{
linebuf[cx] = BASECHAR + chr;
}
pce_vdc_copy_to_vram(dest/2, linebuf, sizeof(linebuf));
dest += (CW*2);
}
}
Did you find the implementation of pce_joypad_read()?
llvm-mos-sdk/mos-platform/pce-common/libpce/src/joypad.c
Lines 12 to 29 in a6e5206
JOYPAD_SEL
is
and IO_JOYPAD
I am not familiar with PC Engine to be intimate with that code, though briefly correlating against example code at https://www.chibiakumas.com/6502/platform2.php#LessonP14 , everything does check out. You could try copy-pasting the implementation of those functions to your own code and playing around with the constructs to see if you can find an issue.
The only thing that I find different is that the above code sleep 4x SXY instructions for 4x3 = 12 clock cycles, whereas the code I found on the above web page waits for a PHA+PLA+NOP+NOP = 3+4+2+2 = 11 clock cycles. Hrm, so that wouldn't explain a problem either.
There is a mention however
Before we can start reading, we need to initialize the 'Multitap' (the hardware that toggles the joypads)...
to do this we just write a #1 then #3 to port $1000... we need a short delay after each write....
Maybe that is what might be missing?
The multitap handling is broken in some manner (and 6-button gamepad handling is not implemented at all).
You can easily verify this in Mednafen by setting pce.input.multitap
to 0, or in Ares by using the GUI.