diff --git a/hash/vboy.xml b/hash/vboy.xml
index 279d5b72cd1..0b4f88aa23d 100644
--- a/hash/vboy.xml
+++ b/hash/vboy.xml
@@ -83,7 +83,8 @@ Ball goes out of bounds sometimes on gameplay (verify)
1995
Nintendo
@@ -100,7 +101,9 @@ Missing intro and gameplay graphics, uses [VIP] framebuffer
2013?
<unknown>
@@ -181,7 +184,9 @@ Glitchy [VIP] backgrounds during gameplay
1995
Nintendo
@@ -194,13 +199,12 @@ Title screen logo is misplaced if intro isn't skipped
-
+
Nester's Funky Bowling (USA)
1996
Nintendo
@@ -251,8 +255,6 @@ Gameplay [VIP] flickers too much, framebuffer?
Nintendo
@@ -270,8 +272,6 @@ Triggers [V810] TRAP opcode on gameplay (related to above?)
T&E Soft
@@ -308,8 +308,8 @@ Overdriven [sound] samples when moving outside the allocated space
1995
Taito
@@ -357,7 +357,7 @@ I/O access (regression)
1995
Nintendo
@@ -406,7 +406,7 @@ Verify player KO graphics
1995
Pack-In-Video
@@ -459,7 +459,8 @@ Missing GFXs for gender select in name entry
1995
T&E Soft
@@ -525,7 +526,7 @@ Unresponsive [pad] inputs on gameplay
-
+
V-Tetris (Japan)
1995
Bullet-Proof Software
@@ -550,6 +551,7 @@ Slightly overdriven [sound] samples during gameplay
diff --git a/src/devices/cpu/v810/v810.cpp b/src/devices/cpu/v810/v810.cpp
index 79b5b83ea68..3c20810e0a4 100644
--- a/src/devices/cpu/v810/v810.cpp
+++ b/src/devices/cpu/v810/v810.cpp
@@ -1,7 +1,7 @@
// license:BSD-3-Clause
// copyright-holders: Tomasz Slanina, Angelo Salese
/******************************************************************
- NEC V810 (upd70732) core
+ NEC V810 (μpd70732) core
Tomasz Slanina
Angelo Salese
@@ -20,12 +20,13 @@
TODO:
- Verify floating point opcodes (single precision IEEE-754 standard)
- - CY flag in few floating point opcodes;
- - split maskable interrupt lines into separate entities;
+ - CY flag in floating point opcodes that supports them;
+ - Subclass NVC (vboy CPU), few extra opcodes plus onchip peripherals ($0200'0000 area);
- implement trap opcode;
- implement halt opcode;
- implement double exception behaviour;
- implement NP fatal exception;
+ - implement NMI;
- implement floating point exceptions;
- verify and improve bitstring opcodes;
- cache handling;
@@ -189,6 +190,7 @@ std::unique_ptr v810_device::create_disassembler()
+// r0 is literally a "register zero", reading returns 0, writing is ignored.
void v810_device::SETREG(uint32_t reg,uint32_t val)
{
if(reg)
@@ -630,13 +632,14 @@ uint32_t v810_device::opJAL(uint32_t op)
return 3;
}
-
+// TODO: specific to NVC
uint32_t v810_device::opEI(uint32_t op)
{
SET_ID(0);
return 1;
}
+// TODO: specific to NVC
uint32_t v810_device::opDI(uint32_t op)
{
SET_ID(1);
@@ -1057,50 +1060,53 @@ uint32_t v810_device::opCVTW(uint32_t op)
return 18;
}
-uint32_t v810_device::opMPYHW(uint32_t op)
-{
- int val1=(GETREG(GET1) & 0xffff);
- int val2=(GETREG(GET2) & 0xffff);
- SET_OV(0);
- val2*=val1;
- SET_Z((val2==0.0f)?1:0);
- SET_S((val2<0.0f)?1:0);
- SETREG(GET2,val2);
- // TODO: unknown
- return 18;
-}
-
uint32_t v810_device::opXB(uint32_t op)
{
int val=GETREG(GET2);
- SET_OV(0);
val = (val & 0xffff0000) | swapendian_int16(val & 0xffff);
- SET_Z((val==0.0f)?1:0);
- SET_S((val<0.0f)?1:0);
+ // TODO: verify flags really being unaffected
+ //SET_OV(0);
+ //SET_Z((val==0.0f)?1:0);
+ //SET_S((val<0.0f)?1:0);
SETREG(GET2,val);
// TODO: unknown
- return 18;
+ return 1;
}
uint32_t v810_device::opXH(uint32_t op)
{
int val=GETREG(GET2);
- SET_OV(0);
val = ((val & 0xffff0000)>>16) | ((val & 0xffff)<<16);
- SET_Z((val==0.0f)?1:0);
- SET_S((val<0.0f)?1:0);
+ // TODO: verify flags really being unaffected
+ //SET_OV(0);
+ //SET_Z((val==0.0f)?1:0);
+ //SET_S((val<0.0f)?1:0);
SETREG(GET2,val);
// TODO: unknown
- return 18;
+ return 1;
+}
+
+uint32_t v810_device::opMPYHW(uint32_t op)
+{
+ s16 val1 = (s16)GETREG(GET1);
+ s16 val2 = (s16)GETREG(GET2);
+ s32 result = (s32)(val1 * val2);
+ // TODO: verify flags really being unaffected
+ //SET_OV(0);
+ //SET_Z((result == 0) ? 1 : 0);
+ //SET_S((result < 0) ? 1 : 0);
+ SETREG(GET2,result);
+ return 9;
}
uint32_t v810_device::opFpoint(uint32_t op)
{
uint32_t tmp=R_OP(PC);
uint32_t op_cycles = 0;
- PC+=2;
- switch((tmp&0xfc00)>>10)
+ const u8 op_type = (tmp&0xfc00)>>10;
+ PC += 2;
+ switch(op_type)
{
// TODO: (*) denotes Virtual Boy specific opcodes
// likely needs co-processor override
@@ -1113,10 +1119,11 @@ uint32_t v810_device::opFpoint(uint32_t op)
case 0x7: op_cycles = opDIVF(op);break;
case 0x8: op_cycles = opXB(op); break; // (*)
case 0x9: op_cycles = opXH(op); break; // (*)
+ //case 0xa: REV (*)
case 0xb: op_cycles = opTRNC(op);break;
case 0xc: op_cycles = opMPYHW(op); break; // (*)
default:
- throw emu_fatalerror("Floating point unknown type %02x\n",(tmp&0xfc00) >> 10);
+ throw emu_fatalerror("Floating point unknown type %02x\n", op_type);
break;
}
return op_cycles;
@@ -1315,13 +1322,11 @@ void v810_device::device_start()
space(AS_PROGRAM).specific(m_program);
space(has_space(AS_IO) ? AS_IO : AS_PROGRAM).specific(m_io);
- m_irq_line = 0;
- m_irq_state = CLEAR_LINE;
+ m_irq_state = 0;
m_nmi_line = CLEAR_LINE;
memset(m_reg, 0x00, sizeof(m_reg));
save_item(NAME(m_reg));
- save_item(NAME(m_irq_line));
save_item(NAME(m_irq_state));
save_item(NAME(m_nmi_line));
save_item(NAME(m_PPC));
@@ -1398,60 +1403,82 @@ void v810_device::state_string_export(const device_state_entry &entry, std::stri
void v810_device::device_reset()
{
- int i;
- for(i=0;i<64;i++) m_reg[i]=0;
+ // everything else is "Undefind" (sic)
+ m_reg[0] = 0;
PC = 0xfffffff0;
- PSW = 0x1000;
- ECR = 0x0000fff0;
+ PSW = 0x00008000;
+ ECR = 0x0000fff0;
}
-// TODO: unsafe on different irq levels asserted at same time
-// TODO: sketchy, lacks fatal & double exceptions
-void v810_device::take_interrupt()
+// TODO: remaining exception types
+void v810_device::check_interrupts()
{
- EIPC = PC;
- EIPSW = PSW;
+ if (m_irq_state == 0)
+ return;
- PC = 0xfffffe00 | (m_irq_line << 4);
- ECR = 0xfe00 | (m_irq_line << 4);
+ if (GET_NP || GET_EP || GET_ID)
+ return;
- uint8_t num = m_irq_line + 1;
- if (num==0x10) num=0x0f;
+ for (u16 irq_line = 15; irq_line >= (PSW & 0xF0000) >> 16; irq_line --)
+ {
+ if (!((1 << irq_line) & m_irq_state))
+ continue;
- PSW &= 0xfff0ffff; // clear interrupt level
- SET_EP(1);
- SET_ID(1);
- PSW |= num << 16;
+ standard_irq_callback(irq_line, PC);
- m_icount -= clkIRQ;
+ EIPC = PC;
+ EIPSW = PSW;
+
+ PC = 0xfffffe00 | (irq_line << 4);
+ ECR = 0xfe00 | (irq_line << 4);
+
+ uint8_t num = irq_line + 1;
+ if (num == 0x10) num = 0x0f;
+
+ // clear interrupt level
+ PSW &= 0xfff0ffff;
+ SET_EP(1);
+ SET_ID(1);
+ SET_AE(0);
+ PSW |= num << 16;
+
+ m_icount -= clkIRQ;
+ return;
+ }
}
void v810_device::execute_run()
{
- if (m_irq_state != CLEAR_LINE) {
- if (!(GET_NP | GET_EP | GET_ID)) {
- if (m_irq_line >=((PSW & 0xF0000) >> 16)) {
- take_interrupt();
- }
- }
- }
- while(m_icount>0)
+ // TODO: move in execution body
+ // (breaks pcfx boot)
+ check_interrupts();
+
+ do
{
- uint32_t op;
-
- m_PPC=PC;
+ m_PPC = PC;
debugger_instruction_hook(PC);
- op=R_OP(PC);
- PC+=2;
- int cnt;
- cnt = (this->*s_OpCodeTable[op>>10])(op);
- m_icount-= cnt;
- }
+ uint32_t op = R_OP(PC);
+ PC += 2;
+
+ int cnt = (this->*s_OpCodeTable[op>>10])(op);
+ m_icount -= cnt;
+
+ } while(m_icount > 0);
}
-void v810_device::execute_set_input( int irqline, int state)
+// TODO: logically connects to /INTV0-/INTV3 pins
+// v810 just exposes an INT and 4 V(ector?) lines.
+// - on pcfx there's an unknown chip irq priority/mask dispatcher;
+// - on vboy it's implied in the NVC specs with a laconic "Interrupt Encoder".
+// It's also 5 possible lines, which wouldn't work bitwise;
+void v810_device::execute_set_input( int irqline, int state )
{
- m_irq_state = state;
- m_irq_line = irqline;
+ if (state == HOLD_LINE)
+ throw emu_fatalerror("V810: using HOLD_LINE is unsupported by the core");
+ u16 mask = 1 << irqline;
+ if (state == ASSERT_LINE)
+ m_irq_state |= mask;
+ else
+ m_irq_state &= ~mask;
}
diff --git a/src/devices/cpu/v810/v810.h b/src/devices/cpu/v810/v810.h
index 9a392595eeb..4a56ecf9fb1 100644
--- a/src/devices/cpu/v810/v810.h
+++ b/src/devices/cpu/v810/v810.h
@@ -113,9 +113,8 @@ private:
address_space_config m_program_config;
address_space_config m_io_config;
- uint32_t m_reg[65];
- uint8_t m_irq_line;
- uint8_t m_irq_state;
+ uint32_t m_reg[65]{};
+ uint16_t m_irq_state;
uint8_t m_nmi_line;
memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache m_cache;
memory_access<32, 2, 0, ENDIANNESS_LITTLE>::specific m_program;
@@ -191,7 +190,7 @@ private:
uint32_t opXH(uint32_t op);
uint32_t opFpoint(uint32_t op);
uint32_t opBSU(uint32_t op);
- void take_interrupt();
+ void check_interrupts();
};
diff --git a/src/devices/video/huc6261.cpp b/src/devices/video/huc6261.cpp
index 4a117b73d08..13658b9a9cc 100644
--- a/src/devices/video/huc6261.cpp
+++ b/src/devices/video/huc6261.cpp
@@ -293,14 +293,14 @@ void huc6261_device::write(offs_t offset, uint16_t data)
break;
case 0x01:
- logerror("huc6261: writing 0x%04x to register 0x%02x\n", data, m_register );
+ //logerror("huc6261: writing 0x%04x to register 0x%02x\n", data, m_register );
switch( m_register )
{
/* Control register */
// -x-- ---- ---- ---- Enable HuC6271: 0 - disabled, 1 - enabled
// --x- ---- ---- ---- Enable HuC6272 BG3: 0 - disabled, 1 - enabled
// ---x ---- ---- ---- Enable HuC6272 BG2: 0 - disabled, 1 - enabled
- // ---- x--- ---- ---- Enable Huc6272 BG1: 0 - disabled, 1 - enabled
+ // ---- x--- ---- ---- Enable HuC6272 BG1: 0 - disabled, 1 - enabled
// ---- -x-- ---- ---- Enable HuC6272 BG0: 0 - disabled, 1 - enabled
// ---- --x- ---- ---- Enable HuC6270 SPR: 0 - disabled, 1 - enabled
// ---- ---x ---- ---- Enable HuC6270 BG: 0 - disabled, 1 - enabled
diff --git a/src/devices/video/huc6272.cpp b/src/devices/video/huc6272.cpp
index 781bf0a2c91..bd046584f42 100644
--- a/src/devices/video/huc6272.cpp
+++ b/src/devices/video/huc6272.cpp
@@ -6,12 +6,12 @@
TODO:
- Use NSCSI instead of legacy one;
+ \- SEL acknowledges with 0x84, bit 7 controller type is unknown at this time
+ (bit 2 should select the CD drive);
- Convert base mapping to address_map;
- Convert I/O to space address, and make it honor mem_mask;
- subclass "SCSICD" into SCSI-2 "CD-ROM DRIVE:FX"
- \- Crashes if CD-ROM is in, on unhandled command 0x28 "Read(10)".
- Tries to LBA with 0xffff'ff7a and 0 after failing a custom mode sense,
- prior TOC tests makes even less sense, CPU core bug?
+ \- Fails detection of PC-FX discs, detects as normal audio CDs;
\- During POST it tries an unhandled 0x44 "Read Header";
\- Derivative design of PCE drive, which in turn is a derivative of PC-8801-30 (cd drive)
and PC-8801-31 (interface);
@@ -70,7 +70,7 @@ void huc6272_device::amap(address_map &map)
void huc6272_device::io_map(address_map &map)
{
map(0x00, 0x00).rw(FUNC(huc6272_device::scsi_data_r), FUNC(huc6272_device::scsi_data_w));
- map(0x01, 0x01).w(FUNC(huc6272_device::scsi_initiate_cmd_w));
+ map(0x01, 0x01).rw(FUNC(huc6272_device::scsi_cmd_status_r), FUNC(huc6272_device::scsi_initiate_cmd_w));
// map(0x02, 0x02) SCSI DMA mode
map(0x03, 0x03).w(FUNC(huc6272_device::scsi_target_cmd_w));
map(0x05, 0x05).rw(FUNC(huc6272_device::scsi_bus_r), FUNC(huc6272_device::scsi_bus_w));
@@ -135,22 +135,23 @@ void huc6272_device::io_map(address_map &map)
//-------------------------------------------------
huc6272_device::huc6272_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, HUC6272, tag, owner, clock),
- device_memory_interface(mconfig, *this),
- m_huc6271(*this, finder_base::DUMMY_TAG),
- m_cdda_l(*this, "cdda_l"),
- m_cdda_r(*this, "cdda_r"),
- m_program_space_config("microprg", ENDIANNESS_LITTLE, 16, 4, 0, address_map_constructor(FUNC(huc6272_device::microprg_map), this)),
- m_data_space_config("kram", ENDIANNESS_LITTLE, 32, 21, 0, address_map_constructor(FUNC(huc6272_device::kram_map), this)),
- m_io_space_config("io", ENDIANNESS_LITTLE, 32, 7, -2, address_map_constructor(FUNC(huc6272_device::io_map), this)),
- m_microprg_ram(*this, "microprg_ram"),
- m_kram_page0(*this, "kram_page0"),
- m_kram_page1(*this, "kram_page1"),
- m_scsibus(*this, "scsi"),
- m_scsi_data_in(*this, "scsi_data_in"),
- m_scsi_data_out(*this, "scsi_data_out"),
- m_scsi_ctrl_in(*this, "scsi_ctrl_in"),
- m_irq_changed_cb(*this)
+ : device_t(mconfig, HUC6272, tag, owner, clock)
+ , device_memory_interface(mconfig, *this)
+ , m_huc6271(*this, finder_base::DUMMY_TAG)
+ , m_cdda_l(*this, "cdda_l")
+ , m_cdda_r(*this, "cdda_r")
+ , m_program_space_config("microprg", ENDIANNESS_LITTLE, 16, 4, 0, address_map_constructor(FUNC(huc6272_device::microprg_map), this))
+ , m_data_space_config("kram", ENDIANNESS_LITTLE, 32, 21, 0, address_map_constructor(FUNC(huc6272_device::kram_map), this))
+ , m_io_space_config("io", ENDIANNESS_LITTLE, 32, 7, -2, address_map_constructor(FUNC(huc6272_device::io_map), this))
+ , m_microprg_ram(*this, "microprg_ram")
+ , m_kram_page0(*this, "kram_page0")
+ , m_kram_page1(*this, "kram_page1")
+ , m_scsibus(*this, "scsi")
+ , m_scsi_data_in(*this, "scsi_data_in")
+ , m_scsi_data_out(*this, "scsi_data_out")
+ , m_scsi_ctrl_in(*this, "scsi_ctrl_in")
+ , m_scsi_cmd_in(*this, "scsi_cmd_in")
+ , m_irq_changed_cb(*this)
{
}
@@ -334,6 +335,11 @@ void huc6272_device::scsi_data_w(offs_t offset, u32 data, u32 mem_mask)
m_scsi_data_out->write(data & 0xff);
}
+u32 huc6272_device::scsi_cmd_status_r(offs_t offset)
+{
+ return m_scsi_cmd_in->read() & 0xff;
+}
+
void huc6272_device::scsi_initiate_cmd_w(offs_t offset, u32 data, u32 mem_mask)
{
//m_scsibus->write_bsy(BIT(data, 0)); // bus?
@@ -731,9 +737,16 @@ void huc6272_device::device_add_mconfig(machine_config &config)
scsibus.io_handler().set("scsi_ctrl_in", FUNC(input_buffer_device::write_bit2));
scsibus.sel_handler().set("scsi_ctrl_in", FUNC(input_buffer_device::write_bit1));
+ scsibus.rst_handler().append("scsi_cmd_in", FUNC(input_buffer_device::write_bit7));
+ scsibus.ack_handler().set("scsi_cmd_in", FUNC(input_buffer_device::write_bit4));
+ scsibus.sel_handler().append("scsi_cmd_in", FUNC(input_buffer_device::write_bit2));
+ scsibus.atn_handler().set("scsi_cmd_in", FUNC(input_buffer_device::write_bit1));
+ scsibus.bsy_handler().append("scsi_cmd_in", FUNC(input_buffer_device::write_bit0));
+
output_latch_device &scsiout(OUTPUT_LATCH(config, "scsi_data_out"));
scsibus.set_output_latch(scsiout);
+ INPUT_BUFFER(config, "scsi_cmd_in");
INPUT_BUFFER(config, "scsi_ctrl_in");
INPUT_BUFFER(config, "scsi_data_in");
diff --git a/src/devices/video/huc6272.h b/src/devices/video/huc6272.h
index 67a629c1299..169eda8cee9 100644
--- a/src/devices/video/huc6272.h
+++ b/src/devices/video/huc6272.h
@@ -114,6 +114,7 @@ private:
required_device m_scsi_data_in;
required_device m_scsi_data_out;
required_device m_scsi_ctrl_in;
+ required_device m_scsi_cmd_in;
/* Callback for when the irq line may have changed (mandatory) */
devcb_write_line m_irq_changed_cb;
@@ -142,6 +143,7 @@ private:
u32 scsi_data_r(offs_t offset);
void scsi_data_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+ u32 scsi_cmd_status_r(offs_t offset);
void scsi_initiate_cmd_w(offs_t offset, u32 data, u32 mem_mask = ~0);
void scsi_target_cmd_w(offs_t offset, u32 data, u32 mem_mask = ~0);
diff --git a/src/mame/nintendo/vboy.cpp b/src/mame/nintendo/vboy.cpp
index 93ef7f56474..7a2f00b329d 100644
--- a/src/mame/nintendo/vboy.cpp
+++ b/src/mame/nintendo/vboy.cpp
@@ -172,11 +172,11 @@ private:
void put_obj(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, uint16_t code, uint8_t pal);
void fill_ovr_char(uint16_t code, uint8_t pal);
- int8_t get_bg_map_pixel(int num, int xpos, int ypos);
+ int8_t get_bg_map_pixel(int num, int xpos, int ypos, u8 scx);
void draw_bg_map(bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t param_base, int mode, int gx, int gp, int gy, int mx, int mp, int my,int h, int w,
- uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num);
+ uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num, u8 scx);
void draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t param_base, int gx, int gp, int gy, int h, int w,
- uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num);
+ uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num, u8 scx);
uint8_t display_world(int num, bitmap_ind16 &bitmap, const rectangle &cliprect, bool right, int &cur_spt);
void set_brightness();
void vboy_palette(palette_device &palette) const;
@@ -187,7 +187,6 @@ private:
TIMER_DEVICE_CALLBACK_MEMBER(vboy_scanlineL);
void vboy_map(address_map &map);
- void vboy_io(address_map &map);
};
@@ -206,33 +205,6 @@ void vboy_state::video_start()
m_bgmap = make_unique_clear(0x20000 >> 1);
}
-void vboy_state::put_obj(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, uint16_t code, uint8_t pal)
-{
- for (uint8_t yi = 0; yi < 8; yi++)
- {
- uint16_t const data = READ_FONT(code * 8 + yi);
-
- for (uint8_t xi = 0; xi < 8; xi++)
- {
- uint8_t const dat = ((data >> (xi << 1)) & 0x03);
-
- if (dat)
- {
- uint16_t const res_x = x + xi;
- uint16_t const res_y = y + yi;
-
- if (cliprect.contains(res_x, res_y))
- {
- uint8_t const col = (pal >> (dat * 2)) & 3;
-
- bitmap.pix((res_y), (res_x)) = m_palette->pen(col);
- }
- }
- }
- }
-}
-
-
void vboy_state::fill_ovr_char(uint16_t code, uint8_t pal)
{
@@ -250,15 +222,19 @@ void vboy_state::fill_ovr_char(uint16_t code, uint8_t pal)
}
}
-inline int8_t vboy_state::get_bg_map_pixel(int num, int xpos, int ypos)
+inline int8_t vboy_state::get_bg_map_pixel(int num, int xpos, int ypos, u8 scx)
{
// auto profile1 = g_profiler.start(PROFILER_USER1);
- int const y = ypos >>3;
- int const x = xpos >>3;
+ int const y = ypos >> 3;
+ int const x = xpos >> 3;
+ // an individual tilemap is 64x64, the upper X/Y bits selects pages in 4096 units and joins with the global BGMAP_BASE.
+ // hyperfgt backgrounds in particular wants to multiply Y page by SCX factor,
+ // - it's 1 for E.Honda stage (the two 512x1024 tilemaps composing the hot bath)
+ // - and 2 elsewhere (1024x1024).
uint8_t const stepx = (x & 0x1c0) >> 6;
- uint8_t const stepy = ((y & 0x1c0) >> 6) * (stepx+1);
+ uint8_t const stepy = ((y & 0x1c0) >> 6) * (scx + 1);
uint16_t const val = READ_BGMAP((x & 0x3f) + (64 * (y & 0x3f)) + ((num + stepx + stepy) * 0x1000));
int const pal = m_vip_io.GPLT[(val >> 14) & 3];
int const code = val & 0x3fff;
@@ -271,11 +247,11 @@ inline int8_t vboy_state::get_bg_map_pixel(int num, int xpos, int ypos)
if(dat == 0)
return -1;
else
- return (pal >> (dat*2)) & 3;
+ return (pal >> (dat * 2)) & 3;
}
void vboy_state::draw_bg_map(bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t param_base, int mode, int gx, int gp, int gy, int mx, int mp, int my, int h, int w,
- uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num)
+ uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num, u8 scx)
{
// auto profile2 = g_profiler.start(PROFILER_USER2);
@@ -315,12 +291,12 @@ void vboy_state::draw_bg_map(bitmap_ind16 &bitmap, const rectangle &cliprect, ui
}
else
{
- pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask);
+ pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask, scx);
}
}
else
{
- pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask);
+ pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask, scx);
}
if(pix != -1)
@@ -330,17 +306,17 @@ void vboy_state::draw_bg_map(bitmap_ind16 &bitmap, const rectangle &cliprect, ui
}
void vboy_state::draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t param_base, int gx, int gp, int gy, int h, int w,
- uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num)
+ uint16_t x_mask, uint16_t y_mask, uint8_t ovr, bool right, int bg_map_num, u8 scx)
{
// auto profile3 = g_profiler.start(PROFILER_USER3);
- for(int y=0;y<=h;y++)
+ for(int y = 0; y <= h; y++)
{
- float h_skw = (int16_t)READ_BGMAP(param_base + (y*8+0)) / 8.0;
- float prlx = (int16_t)READ_BGMAP(param_base + (y*8+1)) / 8.0;
- float v_skw = (int16_t)READ_BGMAP(param_base + (y*8+2)) / 8.0;
- float h_scl = (int16_t)READ_BGMAP(param_base + (y*8+3)) / 512.0;
- float v_scl = (int16_t)READ_BGMAP(param_base + (y*8+4)) / 512.0;
+ float h_skw = (int16_t)READ_BGMAP(param_base + (y * 8 + 0)) / 8.0;
+ float prlx = (int16_t)READ_BGMAP(param_base + (y * 8 + 1)) / 8.0;
+ float v_skw = (int16_t)READ_BGMAP(param_base + (y * 8 + 2)) / 8.0;
+ float h_scl = (int16_t)READ_BGMAP(param_base + (y * 8 + 3)) / 512.0;
+ float v_scl = (int16_t)READ_BGMAP(param_base + (y * 8 + 4)) / 512.0;
h_skw += right ? -prlx : prlx;
@@ -351,7 +327,10 @@ void vboy_state::draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect
int16_t x1 = (x+gx);
int pix = 0;
- x1 += right ? -gp : gp;
+ x1 += (right ? -gp : gp);
+ // clamp for spaceinv gameplay shots
+ // (sets GPs with out of bounds GP values, cfr. $3da40/$3daa0 0xc*** world entries)
+ x1 &= 0x1fff;
src_x = (int32_t)((h_skw) + (h_scl * x));
src_y = (int32_t)((v_skw) + (v_scl * x));
@@ -362,7 +341,7 @@ void vboy_state::draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect
}
else
{
- pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask);
+ pix = get_bg_map_pixel(bg_map_num, src_x & x_mask, src_y & y_mask, scx);
}
if(pix != -1)
@@ -372,40 +351,76 @@ void vboy_state::draw_affine_map(bitmap_ind16 &bitmap, const rectangle &cliprect
}
}
+void vboy_state::put_obj(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y, uint16_t code, uint8_t pal)
+{
+ for (uint8_t yi = 0; yi < 8; yi++)
+ {
+ uint16_t const data = READ_FONT(code * 8 + yi);
+
+ for (uint8_t xi = 0; xi < 8; xi++)
+ {
+ uint8_t const dat = ((data >> (xi << 1)) & 0x03);
+
+ if (dat)
+ {
+ uint16_t const res_x = x + xi;
+ uint16_t const res_y = y + yi;
+
+ if (cliprect.contains(res_x, res_y))
+ {
+ uint8_t const col = (pal >> (dat * 2)) & 3;
+
+ bitmap.pix((res_y), (res_x)) = m_palette->pen(col);
+ }
+ }
+ }
+ }
+}
+
/*
-x--- ---- ---- ---- [0] LON
--x-- ---- ---- ---- RON
---xx ---- ---- ---- BGM type
----- xx-- ---- ---- SCX
----- --xx ---- ---- SCY
----- ---- x--- ---- OVR
----- ---- -x-- ---- END
----- ---- --00 ----
----- ---- ---- xxxx BGMAP_BASE
+ * $3d800 World list
+ *
+ * x--- ---- ---- ---- [0] LON enabled for left screen
+ * -x-- ---- ---- ---- RON enabled for right screen
+ * --xx ---- ---- ---- BGM type
+ * --00 ---- ---- ---- Normal
+ * --01 ---- ---- ---- Hi-Bias
+ * --10 ---- ---- ---- Affine
+ * --11 ---- ---- ---- OAM
+ * ---- xx-- ---- ---- SCX number of pages in the X axis
+ * ---- --xx ---- ---- SCY number of pages in the Y axis
+ * ---- ---- x--- ---- OVR enable overdraw char
+ * ---- ---- -x-- ---- END marker for end of list processing
+ * ---- ---- --00 ----
+ * ---- ---- ---- xxxx BGMAP_BASE
*/
uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle &cliprect, bool right, int &cur_spt)
{
num <<= 4;
- uint16_t def = READ_WORLD(num);
- uint8_t lon = (def >> 15) & 1;
- uint8_t ron = (def >> 14) & 1;
- uint8_t mode = (def >> 12) & 3;
- uint16_t scx = 64 << ((def >> 10) & 3);
- uint16_t scy = 64 << ((def >> 8) & 3);
- uint8_t ovr = (def >> 7) & 1;
- uint8_t end = (def >> 6) & 1;
- int16_t gx = READ_WORLD(num+1);
- int16_t gp = READ_WORLD(num+2);
- int16_t gy = READ_WORLD(num+3);
- int16_t mx = READ_WORLD(num+4);
- int16_t mp = READ_WORLD(num+5);
- int16_t my = READ_WORLD(num+6);
- uint16_t w = READ_WORLD(num+7);
- uint16_t h = READ_WORLD(num+8);
- uint16_t param_base = READ_WORLD(num+9) & 0xfff0;
- uint16_t ovr_char = READ_BGMAP(READ_WORLD(num+10));
- uint8_t bg_map_num = def & 0x0f;
+ const uint16_t def = READ_WORLD(num);
+ const uint8_t lon = (def >> 15) & 1;
+ const uint8_t ron = (def >> 14) & 1;
+ const uint8_t mode = (def >> 12) & 3;
+ const u8 raw_scx = ((def >> 10) & 3);
+ const u8 raw_scy = ((def >> 8) & 3);
+ const uint16_t scx = 64 << raw_scx;
+ const uint16_t scy = 64 << raw_scy;
+ const uint16_t scx_mask = scx * 8 - 1;
+ const uint16_t scy_mask = scy * 8 - 1;
+ const uint8_t ovr = (def >> 7) & 1;
+ const uint8_t end = (def >> 6) & 1;
+ const int16_t gx = READ_WORLD(num+1);
+ const int16_t gp = READ_WORLD(num+2);
+ const int16_t gy = READ_WORLD(num+3);
+ const int16_t mx = READ_WORLD(num+4);
+ const int16_t mp = READ_WORLD(num+5);
+ const int16_t my = READ_WORLD(num+6);
+ const uint16_t w = READ_WORLD(num+7);
+ const uint16_t h = READ_WORLD(num+8);
+ const uint16_t param_base = READ_WORLD(num+9) & 0xfff0;
+ const uint16_t ovr_char = READ_BGMAP(READ_WORLD(num+10));
+ const uint8_t bg_map_num = def & 0x0f;
if(end)
return 1;
@@ -417,12 +432,12 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
if (lon && (!right))
{
- draw_bg_map(bitmap, cliprect, param_base, mode, gx, gp, gy, mx, mp, my, h,w, scx*8-1, scy*8-1, ovr, right, bg_map_num);
+ draw_bg_map(bitmap, cliprect, param_base, mode, gx, gp, gy, mx, mp, my, h,w, scx_mask, scy_mask, ovr, right, bg_map_num, raw_scx);
}
if (ron && (right))
{
- draw_bg_map(bitmap, cliprect, param_base, mode, gx, gp, gy, mx, mp, my, h,w, scx*8-1, scy*8-1, ovr, right, bg_map_num);
+ draw_bg_map(bitmap, cliprect, param_base, mode, gx, gp, gy, mx, mp, my, h,w, scx_mask, scy_mask, ovr, right, bg_map_num, raw_scx);
}
}
else if (mode==2) // Affine Mode
@@ -432,12 +447,12 @@ uint8_t vboy_state::display_world(int num, bitmap_ind16 &bitmap, const rectangle
if (lon && (!right))
{
- draw_affine_map(bitmap, cliprect, param_base, gx, gp, gy, h,w, scx*8-1, scy*8-1, ovr, right, bg_map_num);
+ draw_affine_map(bitmap, cliprect, param_base, gx, gp, gy, h,w, scx_mask, scy_mask, ovr, right, bg_map_num, raw_scx);
}
if (ron && (right))
{
- draw_affine_map(bitmap, cliprect, param_base, gx, gp, gy, h,w, scx*8-1, scy*8-1, ovr, right, bg_map_num);
+ draw_affine_map(bitmap, cliprect, param_base, gx, gp, gy, h,w, scx_mask, scy_mask, ovr, right, bg_map_num, raw_scx);
}
}
else if (mode==3) // OBJ Mode
@@ -611,11 +626,18 @@ void vboy_state::timer_control_w(offs_t offset, u8 data)
{
m_maintimer->adjust(attotime::from_hz(10000));
}
-
}
}
+ else
+ {
+ m_maintimer->adjust(attotime::never);
+ // hyperfgt writes 0x18 -> 0x1c -> 0x19 in irq service,
+ // implying that a 1 -> 0 transition will ack as well
+ m_maincpu->set_input_line(1, CLEAR_LINE);
+ }
- m_regs.tcr = (data & 0xfd) | (0xe4) | (m_regs.tcr & 2); // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only.
+ // according to docs: bits 5, 6 & 7 are unused and set to 1, bit 1 is read only.
+ m_regs.tcr = (data & 0xfd) | (0xe4) | (m_regs.tcr & 2);
if(data & 4)
m_regs.tcr &= 0xfd;
}
@@ -675,8 +697,10 @@ void vboy_state::vip_map(address_map &map)
}
// TODO: verify against real HW
-// - brightness presumably isn't a linear algorithm
-// - REST needs to be taken into account (needs a working example)
+// - LED brightness doesn't scale well with regular raster pen color.
+// These BRTx values are the "time" where the LED stays on.
+// - REST needs to be taken into account (nothing sets it up so far)
+// - vfishing draws selection accents in main menu with BRTA signal (currently almost invisible);
void vboy_state::set_brightness()
{
int a,b,c;
@@ -773,13 +797,13 @@ uint16_t vboy_state::vip_io_r(offs_t offset)
//printf("%d\n",row_num);
- res = m_vip_io.XPSTTS & 0x00f3; // empty ^^'
+ res = m_vip_io.XPSTTS & 0x00f3;
res |= m_drawfb << 2;
if(m_row_num < 224/8)
{
res |= 0x8000;
- res |= m_row_num<<8;
+ res |= m_row_num << 8;
}
return res;
@@ -824,8 +848,9 @@ uint16_t vboy_state::vip_io_r(offs_t offset)
void vboy_state::vip_io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
+ // wariolnd end boss has these writes
if(mem_mask != 0xffff)
- printf("%04x %02x\n",mem_mask,offset*2);
+ logerror("Warning: register %04x write with non-word access %02x & %04x\n",offset*2, data, mem_mask);
switch(offset << 1) {
/*
@@ -1038,15 +1063,6 @@ void vboy_state::vboy_map(address_map &map)
//map(0x07000000, 0x07ffffff) cartslot ROM
}
-void vboy_state::vboy_io(address_map &map)
-{
- map.global_mask(0x07ffffff);
- map(0x00000000, 0x0007ffff).m(FUNC(vboy_state::vip_map));
- map(0x01000000, 0x010005ff).rw("vbsnd", FUNC(vboysnd_device::read), FUNC(vboysnd_device::write));
- map(0x02000000, 0x020000ff).mirror(0x0ffff00).m(FUNC(vboy_state::io_map)).umask32(0x000000ff);
- // TODO: verify if ROM/RAM mirrors on I/O space (nesterfb)
-}
-
/* Input ports */
static INPUT_PORTS_START( vboy )
PORT_START("INPUT")
@@ -1218,7 +1234,8 @@ void vboy_state::vboy(machine_config &config)
/* basic machine hardware */
V810(config, m_maincpu, XTAL(20'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &vboy_state::vboy_map);
- m_maincpu->set_addrmap(AS_IO, &vboy_state::vboy_io);
+ // no AS_IO, and some games relies on r/w the program map with INH/OUTH
+ // cfr. vforce, nesterfb, panicbom (sound)
TIMER(config, "scantimer_l").configure_scanline(FUNC(vboy_state::vboy_scanlineL), "3dleft", 0, 1);
//TIMER(config, "scantimer_r").configure_scanline(FUNC(vboy_state::vboy_scanlineR), "3dright", 0, 1);
@@ -1234,13 +1251,13 @@ void vboy_state::vboy(machine_config &config)
PALETTE(config, m_palette, FUNC(vboy_state::vboy_palette), 4);
/* Left screen */
- screen_device &lscreen(SCREEN(config, "3dleft", SCREEN_TYPE_RASTER));
+ screen_device &lscreen(SCREEN(config, "3dleft", SCREEN_TYPE_LCD));
lscreen.set_raw(XTAL(20'000'000)/2,757,0,384,264,0,224);
lscreen.set_screen_update(FUNC(vboy_state::screen_update_left));
lscreen.set_palette(m_palette);
/* Right screen */
- screen_device &rscreen(SCREEN(config, "3dright", SCREEN_TYPE_RASTER));
+ screen_device &rscreen(SCREEN(config, "3dright", SCREEN_TYPE_LCD));
rscreen.set_raw(XTAL(20'000'000)/2,757,0,384,264,0,224);
rscreen.set_screen_update(FUNC(vboy_state::screen_update_right));
rscreen.set_palette(m_palette);