Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cd6e044
Collision borders now true to hardware
nanochess Jul 27, 2021
d4c67db
Corrected file permissions (new machine)
nanochess Jul 27, 2021
69e0eeb
Further permissions corrected
nanochess Jul 27, 2021
036806d
Merge pull request #61 from nanochess/master
inactive123 Jul 30, 2021
d74a75d
add retrofw target
Jul 30, 2021
1c08578
Merge pull request #63 from Poligraf/retrofw
inactive123 Jul 30, 2021
1e90784
Update .gitlab-ci.yml
inactive123 Jul 30, 2021
0794f15
Added save states via retro_serialize()
nanochess Aug 10, 2021
02b166e
Forgot to add comment in README
nanochess Aug 10, 2021
3801fc4
Merge pull request #64 from nanochess/master
inactive123 Aug 11, 2021
6412f72
Corrected small bug in unserialize (detected by Jamiras)
nanochess Aug 14, 2021
796e7a6
Merge pull request #65 from nanochess/master
inactive123 Aug 16, 2021
0053374
Serialization now can work anytime. Rewind working. PSG now compatibl…
nanochess Aug 18, 2021
0058a09
Merge pull request #66 from nanochess/master
inactive123 Aug 19, 2021
e900ed4
Writes to GRAM and'ed to 8-bit (solves Tower of Doom bug)
nanochess Dec 10, 2021
1ccfe21
Solved display bug with D1K and D2K. Better counting time for instruc…
nanochess Dec 11, 2021
f0f4866
Added support for Intellivoice
nanochess Dec 14, 2021
c304570
Merge pull request #67 from nanochess/master
inactive123 Dec 14, 2021
995e9bf
Solved bug in border collision when enabling border mask (fixes #68 I…
nanochess Dec 17, 2021
910b25c
Added audio interpolator (solves chirps on Lock&Chase)
nanochess Jan 5, 2022
7b77234
Merge pull request #69 from nanochess/master
inactive123 Jan 6, 2022
063903a
Fix spacing to use tab spaces to match the rest of the file.
msheehan79 Jan 7, 2022
3996fb1
Add Input Descriptors for the controls. Map Keypad 5 to the Right thu…
msheehan79 Jan 7, 2022
0ab0a7c
Merge pull request #70 from msheehan79/master
inactive123 Jan 7, 2022
19286dd
Attempt to fix MSVC build errors
msheehan79 Jan 7, 2022
1dd07ba
Merge branch 'libretro:master' into master
msheehan79 Jan 7, 2022
2c65695
Merge pull request #71 from msheehan79/master
inactive123 Jan 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
10 changes: 10 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ include:
# PlayStation2
- project: 'libretro-infrastructure/ci-templates'
file: '/ps2-static.yml'

# OpenDingux
- project: 'libretro-infrastructure/ci-templates'
file: '/dingux-mips32.yml'

# tvOS (AppleTV)
- project: 'libretro-infrastructure/ci-templates'
Expand Down Expand Up @@ -256,3 +260,9 @@ libretro-build-libnx-aarch64:
extends:
- .libretro-libnx-static-retroarch-master
- .core-defs

# RetroFW
libretro-build-retrofw-mips32:
extends:
- .libretro-retrofw-mips32-make-default
- .core-defs
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,22 @@ else ifeq ($(platform), gcw0)

DISABLE_ERROR_LOGGING := 1
CFLAGS += -march=mips32 -mtune=mips32r2 -mhard-float

# RETROFW
else ifeq ($(platform), retrofw)
TARGET := $(TARGET_NAME)_libretro.so
CC = /opt/retrofw-toolchain/usr/bin/mipsel-linux-gcc
AR = /opt/retrofw-toolchain/usr/bin/mipsel-linux-ar
fpic := -fPIC
SHARED := -shared -Wl,--version-script=link.T -Wl,-no-undefined

DISABLE_ERROR_LOGGING := 1
CFLAGS += -Ofast
CFLAGS += -march=mips32 -mtune=mips32 -mhard-float
CFLAGS += -falign-functions=1 -falign-jumps=1 -falign-loops=1
CFLAGS += -fomit-frame-pointer -ffast-math
CFLAGS += -funsafe-math-optimizations -fsingle-precision-constant -fexpensive-optimizations
CFLAGS += -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops

# Windows MSVC 2010 x64
else ifeq ($(platform), windows_msvc2010_x64)
Expand Down
3 changes: 2 additions & 1 deletion Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ SOURCES_C := \
$(SOURCE_DIR)/cp1610.c \
$(SOURCE_DIR)/cart.c \
$(SOURCE_DIR)/controller.c \
$(SOURCE_DIR)/osd.c \
$(SOURCE_DIR)/osd.c \
$(SOURCE_DIR)/ivoice.c \
$(SOURCE_DIR)/psg.c \
$(SOURCE_DIR)/stic.c

Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ FreeIntv is a libretro emulation core for the Mattel Intellivision designed to b
## Authors

FreeIntv was created by David Richardson.
The PSG and STIC emulation was made closer to hardware and optimized by Oscar Toledo G. (nanochess)
The PSG and STIC emulation was made closer to hardware and optimized by Oscar Toledo G. (nanochess), who also added save states.

The Intellivoice code has been contributed by Joe Zbiciak (author of jzintv), and adapted by Oscar Toledo G. (nanochess)

## License
The FreeIntv core is licensed under GPLv3. More information at https://github.com/markwkidd/FreeIntv/blob/master/LICENSE.
Expand All @@ -19,8 +21,8 @@ FreeIntv requires two Intellivision BIOS files to be placed in the libretro 'sys

* BIOS filenames are case-sensitive

## Entertainment Computer System and Intellivoice
FreeIntv does not currently support Entertainment Computer System (ECS) and Intellivoice functionality. Contributions to the code are welcome!
## Entertainment Computer System
FreeIntv does not currently support Entertainment Computer System (ECS) functionality. Contributions to the code are welcome!

## Controller overlays
Mattel Intellivision games were often meant to be played with game-specific cards overlaid on the numeric keypad. These overlays convey information which can be very useful in gameplay. Images of a limited selection of Intellivision titles are available at: http://www.intellivisionlives.com/bluesky/games/instructions.shtml
Expand Down
Binary file added src/.DS_Store
Binary file not shown.
8 changes: 8 additions & 0 deletions src/controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ int getControllerState(int joypad[], int player)
state |= keypadDirections[norm & 0x07];
}

// Thumbsticks for Keypad 0/5
if(joypad[18]!=0) { state |= K_0; } // 0x48 - Keypad 0
if(joypad[19]!=0) { state |= K_5; } // 0x42 - Keypad 5

// L/R triggers for Keypad Enter/Clear
if(joypad[12]!=0) { state |= K_C; } // 0x88 - Keypad Clear
if(joypad[13]!=0) { state |= K_E; } // 0x28 - Keypad Enter

return state;
}

Expand Down
69 changes: 57 additions & 12 deletions src/cp1610.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,28 @@ int Flag_Sign = 0;
int Flag_Zero = 0;
int Flag_Overflow = 0;

void CP1610Serialize(struct CP1610serialized *all)
{
all->Flag_DoubleByteData = Flag_DoubleByteData;
all->Flag_InteruptEnable = Flag_InteruptEnable;
all->Flag_Carry = Flag_Carry;
all->Flag_Sign = Flag_Sign;
all->Flag_Zero = Flag_Zero;
all->Flag_Overflow = Flag_Overflow;
memcpy(&all->R[0], &R[0], sizeof(R));
}

void CP1610Unserialize(const struct CP1610serialized *all)
{
Flag_DoubleByteData = all->Flag_DoubleByteData;
Flag_InteruptEnable = all->Flag_InteruptEnable;
Flag_Carry = all->Flag_Carry;
Flag_Sign = all->Flag_Sign;
Flag_Zero = all->Flag_Zero;
Flag_Overflow = all->Flag_Overflow;
memcpy(&R[0], &all->R[0], sizeof(R));
}

void CP1610Reset()
{
Flag_DoubleByteData = 0;
Expand Down Expand Up @@ -148,6 +170,9 @@ int CP1610Tick(int debug)
unsigned int instruction = readMem(R[PC]);

int ticks = 0;
#if 0
static int global_ticks = 0;
#endif

// DEBUG
#if 0
Expand All @@ -157,6 +182,21 @@ int CP1610Tick(int debug)
fprintf(stdout, "%04x:[%03x%c %04x %04x %04x %04x %04x %04x %04x %s %c%c%c%c%c%c\n", R[7], instruction, instruction > 0x03ff ? 'X' : ']', R[0], R[1], R[2], R[3], R[4], R[5], R[6], Nmemonic[instruction], Flag_Sign ? 'S' : '-', Flag_Carry ? 'C' : '-', Flag_Overflow ? 'O' : '-', Flag_Zero ? 'Z' : '-', Flag_InteruptEnable ? 'I' : '-', Flag_DoubleByteData ? 'D' : '-');
}
#endif
#if 0 // Debug output compatible with JZINTV for comparison purposes
{
FILE *debug_file;

fprintf(debug_file, " %04X %04X %04X %04X %04X %04X %04X %04X %c%c%c%c%c%c%c%c %20s %d\n", R[0], R[1], R[2], R[3], R[4], R[5], R[6], R[7],
Flag_Sign ? 'S' : '-',
Flag_Zero ? 'Z' : '-',
Flag_Overflow ? 'O' : '-',
Flag_Carry ? 'C' : '-',
Flag_InteruptEnable ? 'I' : '-',
Flag_DoubleByteData ? 'D' : '-',
Interuptable[instruction] ? 'i' : '-',
SR1 > 0 ? 'q' : '-' , Nmemonic[instruction], global_ticks);
}
#endif

if(instruction > 0x03FF)
{
Expand Down Expand Up @@ -184,6 +224,9 @@ int CP1610Tick(int debug)
}
}

#if 0
global_ticks += ticks;
#endif
return ticks;
}

Expand Down Expand Up @@ -222,6 +265,7 @@ int TCI(int v) { return 4; } // Terminate Current Interrupt (not used)
int CLRC(int v) { Flag_Carry = 0; return 4; } // Clear Carry
int SETC(int v) { Flag_Carry = 1; return 4; } // Set Carry

#define EXTRA_IF_R6(reg) (reg == 6 ? 3 : 0)
#define EXTRA_IF_R6R7(reg) (reg >= 6 ? 1 : 0)

int INCR(int v) // Increment Register
Expand Down Expand Up @@ -494,6 +538,7 @@ int Branch(int v) // Branch - B, BC, BOV, BPL, BEQ, BLT, BLE, BUSC, NOPP, BNC, B
{
if(direction==0) { R[PC] = R[PC]+offset; }
if(direction==1) { R[PC] = R[PC]-offset-1; }
return 9;
}
return 7;
}
Expand Down Expand Up @@ -540,14 +585,14 @@ int MVI(int v) // Move In 0000:0010:1000:0rrr aaaa:aaaa:aaaa:aaaa
{
int reg = v & 0x07;
R[reg] = readOperandIndirect();
return 10;
return 10 + EXTRA_IF_R6R7(reg);
}
int MVIa(int v) // Move In Indirect 0000:0010:10aa:addd
{
int areg = (v >> 3) & 0x7;
int dreg = v & 0x7;
R[dreg] = readIndirect(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(dreg) + EXTRA_IF_R6(areg);
}
int MVII(int v) // Move In Immediate (copies operand to register)
{
Expand All @@ -563,15 +608,15 @@ int ADD(int v) // Add
int reg = v & 0x07;
int val = readOperandIndirect();
R[reg] = AddSetSZOC(R[reg], val);
return 10;
return 10 + EXTRA_IF_R6R7(reg);;
}
int ADDa(int v) // Add Indirect
{
int areg = (v >> 3) & 0x07;
int dreg = v & 0x07;
int val = readIndirect(areg);
R[dreg] = AddSetSZOC(R[dreg], val);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg) + EXTRA_IF_R6(areg);
}
int ADDI(int v) // Add Immediate
{
Expand All @@ -584,7 +629,7 @@ int SUB(int v) // Subtract
int val = readOperandIndirect();
R[reg] = SubSetOC(R[reg], val);
SetFlagsSZ(reg);
return 10;
return 10 + EXTRA_IF_R6R7(reg);
}
int SUBa(int v) // Subtract Indirect
{
Expand All @@ -593,7 +638,7 @@ int SUBa(int v) // Subtract Indirect
int val = readIndirect(areg);
R[dreg] = SubSetOC(R[dreg], val);
SetFlagsSZ(dreg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg) + EXTRA_IF_R6(areg);
}
int SUBI(int v) // Subtract Immediate
{
Expand All @@ -607,7 +652,7 @@ int CMP(int v)
int res = SubSetOC(R[reg], val);
Flag_Sign = (res & 0x8000)!=0;
Flag_Zero = res==0;
return 10;
return 10 + EXTRA_IF_R6R7(reg);
}
int CMPa(int v)
{
Expand All @@ -617,7 +662,7 @@ int CMPa(int v)
int res = SubSetOC(R[dreg], val);
Flag_Sign = (res & 0x8000)!=0;
Flag_Zero = res==0;
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg) + EXTRA_IF_R6(areg);
}
int CMPI(int v) // CMP Immediate
{
Expand All @@ -630,7 +675,7 @@ int AND(int v) // And
int val = readOperandIndirect();
R[reg] = R[reg] & val;
SetFlagsSZ(reg);
return 10;
return 10 + EXTRA_IF_R6R7(reg);
}
int ANDa(int v) // And Indirect
{
Expand All @@ -639,7 +684,7 @@ int ANDa(int v) // And Indirect
int val = readIndirect(areg);
R[dreg] = R[dreg] & val;
SetFlagsSZ(dreg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg) + EXTRA_IF_R6(areg);
}
int ANDI(int v) // And Immediate
{
Expand All @@ -652,7 +697,7 @@ int XOR(int v) // Xor
int val = readOperandIndirect();
R[reg] = R[reg] ^ val;
SetFlagsSZ(reg);
return 10;
return 10 + EXTRA_IF_R6R7(reg);
}
int XORa(int v) // Xor Indirect
{
Expand All @@ -661,7 +706,7 @@ int XORa(int v) // Xor Indirect
int val = readIndirect(areg);
R[dreg] = R[dreg] ^ val;
SetFlagsSZ(dreg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg);
return (Flag_DoubleByteData == 1 ? 10 : 8) + EXTRA_IF_R6R7(areg) + EXTRA_IF_R6(areg);
}
int XORI(int v) // Xor Immediate
{
Expand Down
15 changes: 14 additions & 1 deletion src/cp1610.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,23 @@
along with FreeIntv. If not, see http://www.gnu.org/licenses/
*/

struct CP1610serialized {
int Flag_DoubleByteData;
int Flag_InteruptEnable;
int Flag_Carry;
int Flag_Sign;
int Flag_Zero;
int Flag_Overflow;
unsigned int R[8];
};

void CP1610Serialize(struct CP1610serialized *);
void CP1610Unserialize(const struct CP1610serialized *);

void CP1610Init(void); // Adds opcodes to lookup tables

void CP1610Reset(void); // reset cpu

int CP1610Tick(int debug); // execute a single instruction, return cycles used

#endif
#endif
21 changes: 18 additions & 3 deletions src/intv.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "controller.h"
#include "cart.h"
#include "osd.h"
#include "ivoice.h"

int SR1;
int intv_halt;
Expand Down Expand Up @@ -100,15 +101,16 @@ void Reset()
SR1 = 0;
intv_halt = 0;
CP1610Reset();
MemoryInit();
STICReset();
PSGInit();
ivoice_reset();
}

void Init()
{
CP1610Init();
MemoryInit();
PSGInit();
ivoice_init(0, 1.0);
}

void Run()
Expand Down Expand Up @@ -142,6 +144,9 @@ int exec(void) // Run one instruction

// Tick PSG
PSGTick(ticks);

// Tick Intellivoice
ivoice_tk(ticks);

if(SR1>0)
{
Expand All @@ -160,11 +165,17 @@ int exec(void) // Run one instruction
SR1 = phase_len;
// Render Frame //
STICDrawFrame(stic_vid_enable);
// The following line was below just after
// "stic_vid_enable = DisplayEnabled;"
// It caused D1K Homebrew to fail:
// o D1K misses a video interrupt.
// o However it updates DisplayEnabled in time (writing to 0x20)
// o So the DisplayEnabled variable should be reset here.
DisplayEnabled = 0;
return 0;
case 1:
phase_len += 3796 - 2900;
stic_vid_enable = DisplayEnabled;
DisplayEnabled = 0;
if (stic_vid_enable)
stic_reg = 0; // STIC registers now inaccessible
stic_gram = 1; // GRAM accessible
Expand All @@ -177,13 +188,15 @@ int exec(void) // Run one instruction
stic_gram = 0; // GRAM now inaccessible
phase_len -= 68; // BUSRQ period (STIC reads RAM)
PSGTick(68);
ivoice_tk(68);
}
break;
default:
phase_len += 912;
if (stic_vid_enable) {
phase_len -= 108; // BUSRQ period (STIC reads RAM)
PSGTick(108);
ivoice_tk(108);
}
break;
case 14:
Expand All @@ -193,6 +206,7 @@ int exec(void) // Run one instruction
if (stic_vid_enable) {
phase_len -= 108; // BUSRQ period (STIC reads RAM)
PSGTick(108);
ivoice_tk(108);
}
break;
case 15:
Expand All @@ -201,6 +215,7 @@ int exec(void) // Run one instruction
if (stic_vid_enable && delayV == 0) {
phase_len -= 38; // BUSRQ period (STIC reads RAM)
PSGTick(38);
ivoice_tk(38);
}
break;

Expand Down
Loading