New! With more games than the 32X! And better sounding ones too!

This commit is contained in:
nattthebear 2017-07-03 21:29:34 -04:00
parent 41fdb3a140
commit bd57871171
18 changed files with 4654 additions and 224 deletions

View File

@ -1,226 +1,227 @@
using System;
using System.Globalization;
namespace BizHawk.Client.ApiHawk
{
/// <summary>
/// This class holds a converter for BizHawk SystemId (which is a simple <see cref="string"/>
/// It allows you to convert it to a <see cref="CoreSystem"/> value and vice versa
/// </summary>
/// <remarks>I made it this way just in case one day we need it for WPF (DependencyProperty binding). Just uncomment :IValueConverter implementation
/// I didn't implemented it because of mono compatibility
/// </remarks>
public sealed class BizHawkSystemIdToEnumConverter //:IValueConverter
{
/// <summary>
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
/// </summary>
/// <param name="value"><see cref="string"/> you want to convert</param>
/// <param name="targetType">The type of the binding target property</param>
/// <param name="parameter">The converter parameter to use; null in our case</param>
/// <param name="cultureInfo">The culture to use in the converter</param>
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
switch ((string)value)
{
case "AppleII":
return CoreSystem.AppleII;
case "A26":
return CoreSystem.Atari2600;
case "A78":
return CoreSystem.Atari2600;
case "A7800":
return CoreSystem.Atari7800;
case "Coleco":
return CoreSystem.ColecoVision;
case "C64":
return CoreSystem.Commodore64;
case "DGB":
return CoreSystem.DualGameBoy;
case "GB":
return CoreSystem.GameBoy;
case "GBA":
return CoreSystem.GameBoyAdvance;
case "GEN":
return CoreSystem.Genesis;
case "INTV":
return CoreSystem.Intellivision;
case "Libretro":
return CoreSystem.Libretro;
case "Lynx":
return CoreSystem.Lynx;
case "SMS":
return CoreSystem.MasterSystem;
case "NES":
return CoreSystem.NES;
case "N64":
return CoreSystem.Nintendo64;
case "NULL":
return CoreSystem.Null;
case "PCE":
case "PCECD":
case "SGX":
return CoreSystem.PCEngine;
case "PSX":
return CoreSystem.Playstation;
case "PSP":
return CoreSystem.PSP;
case "SAT":
return CoreSystem.Saturn;
case "SNES":
return CoreSystem.SNES;
case "TI83":
return CoreSystem.TI83;
case "WSWAN":
return CoreSystem.WonderSwan;
case "VB":
case "NGP":
using System;
using System.Globalization;
namespace BizHawk.Client.ApiHawk
{
/// <summary>
/// This class holds a converter for BizHawk SystemId (which is a simple <see cref="string"/>
/// It allows you to convert it to a <see cref="CoreSystem"/> value and vice versa
/// </summary>
/// <remarks>I made it this way just in case one day we need it for WPF (DependencyProperty binding). Just uncomment :IValueConverter implementation
/// I didn't implemented it because of mono compatibility
/// </remarks>
public sealed class BizHawkSystemIdToEnumConverter //:IValueConverter
{
/// <summary>
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
/// </summary>
/// <param name="value"><see cref="string"/> you want to convert</param>
/// <param name="targetType">The type of the binding target property</param>
/// <param name="parameter">The converter parameter to use; null in our case</param>
/// <param name="cultureInfo">The culture to use in the converter</param>
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
switch ((string)value)
{
case "AppleII":
return CoreSystem.AppleII;
case "A26":
return CoreSystem.Atari2600;
case "A78":
return CoreSystem.Atari2600;
case "A7800":
return CoreSystem.Atari7800;
case "Coleco":
return CoreSystem.ColecoVision;
case "C64":
return CoreSystem.Commodore64;
case "DGB":
return CoreSystem.DualGameBoy;
case "GB":
return CoreSystem.GameBoy;
case "GBA":
return CoreSystem.GameBoyAdvance;
case "GEN":
return CoreSystem.Genesis;
case "INTV":
return CoreSystem.Intellivision;
case "Libretro":
return CoreSystem.Libretro;
case "Lynx":
return CoreSystem.Lynx;
case "SMS":
return CoreSystem.MasterSystem;
case "NES":
return CoreSystem.NES;
case "N64":
return CoreSystem.Nintendo64;
case "NULL":
return CoreSystem.Null;
case "PCE":
case "PCECD":
case "SGX":
return CoreSystem.PCEngine;
case "PSX":
return CoreSystem.Playstation;
case "PSP":
return CoreSystem.PSP;
case "SAT":
return CoreSystem.Saturn;
case "SNES":
return CoreSystem.SNES;
case "TI83":
return CoreSystem.TI83;
case "WSWAN":
return CoreSystem.WonderSwan;
case "VB":
case "NGP":
case "DNGP":
case "O2":
case "SGB":
return 0; // like I give a shit
default:
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
}
}
/// <summary>
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
/// </summary>
/// <param name="value"><see cref="string"/> you want to convert</param>
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
public CoreSystem Convert(string value)
{
return (CoreSystem)Convert(value, null, null, CultureInfo.CurrentCulture);
}
/// <summary>
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
/// </summary>
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
/// <param name="targetType">The type of the binding target property</param>
/// <param name="parameter">The converter parameter to use; null in our case</param>
/// <param name="cultureInfo">The culture to use in the converter</param>
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
switch ((CoreSystem)value)
{
case CoreSystem.AppleII:
return "AppleII";
case CoreSystem.Atari2600:
return "A26";
case CoreSystem.Atari7800:
return "A78";
case CoreSystem.ColecoVision:
return "Coleco";
case CoreSystem.Commodore64:
return "C64";
case CoreSystem.DualGameBoy:
return "DGB";
case CoreSystem.GameBoy:
return "GB";
case CoreSystem.GameBoyAdvance:
return "GBA";
case CoreSystem.Genesis:
return "GEN";
case CoreSystem.Intellivision:
return "INTV";
case CoreSystem.Libretro:
return "Libretro";
case CoreSystem.Lynx:
return "Lynx";
case CoreSystem.MasterSystem:
return "SMS";
case CoreSystem.NES:
return "NES";
case CoreSystem.Nintendo64:
return "N64";
case CoreSystem.Null:
return "NULL";
case CoreSystem.PCEngine:
return "PCE";
case CoreSystem.Playstation:
return "PSX";
case CoreSystem.PSP:
return "PSP";
case CoreSystem.Saturn:
return "SAT";
case CoreSystem.SNES:
return "SNES";
case CoreSystem.TI83:
return "TI83";
case CoreSystem.WonderSwan:
return "WSWAN";
default:
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
}
}
/// <summary>
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
/// </summary>
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
public string ConvertBack(CoreSystem value)
{
return (string)ConvertBack(value, null, null, CultureInfo.CurrentCulture);
}
}
}
case "SGB":
case "UZE":
return 0; // like I give a shit
default:
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
}
}
/// <summary>
/// Convert BizHawk SystemId <see cref="string"/> to <see cref="CoreSystem"/> value
/// </summary>
/// <param name="value"><see cref="string"/> you want to convert</param>
/// <returns>A <see cref="CoreSystem"/> that is equivalent to BizHawk SystemId <see cref="string"/></returns>
/// <exception cref="IndexOutOfRangeException">Thrown when SystemId hasn't been found</exception>
public CoreSystem Convert(string value)
{
return (CoreSystem)Convert(value, null, null, CultureInfo.CurrentCulture);
}
/// <summary>
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
/// </summary>
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
/// <param name="targetType">The type of the binding target property</param>
/// <param name="parameter">The converter parameter to use; null in our case</param>
/// <param name="cultureInfo">The culture to use in the converter</param>
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
{
switch ((CoreSystem)value)
{
case CoreSystem.AppleII:
return "AppleII";
case CoreSystem.Atari2600:
return "A26";
case CoreSystem.Atari7800:
return "A78";
case CoreSystem.ColecoVision:
return "Coleco";
case CoreSystem.Commodore64:
return "C64";
case CoreSystem.DualGameBoy:
return "DGB";
case CoreSystem.GameBoy:
return "GB";
case CoreSystem.GameBoyAdvance:
return "GBA";
case CoreSystem.Genesis:
return "GEN";
case CoreSystem.Intellivision:
return "INTV";
case CoreSystem.Libretro:
return "Libretro";
case CoreSystem.Lynx:
return "Lynx";
case CoreSystem.MasterSystem:
return "SMS";
case CoreSystem.NES:
return "NES";
case CoreSystem.Nintendo64:
return "N64";
case CoreSystem.Null:
return "NULL";
case CoreSystem.PCEngine:
return "PCE";
case CoreSystem.Playstation:
return "PSX";
case CoreSystem.PSP:
return "PSP";
case CoreSystem.Saturn:
return "SAT";
case CoreSystem.SNES:
return "SNES";
case CoreSystem.TI83:
return "TI83";
case CoreSystem.WonderSwan:
return "WSWAN";
default:
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
}
}
/// <summary>
/// Convert a <see cref="CoreSystem"/> value to BizHawk SystemId <see cref="string"/>
/// </summary>
/// <param name="value"><see cref="CoreSystem"/> you want to convert</param>
/// <returns>A <see cref="string"/> that is used by BizHawk SystemId</returns>
/// <exception cref="IndexOutOfRangeException">Thrown when <see cref="CoreSystem"/> hasn't been found</exception>
public string ConvertBack(CoreSystem value)
{
return (string)ConvertBack(value, null, null, CultureInfo.CurrentCulture);
}
}
}

View File

@ -344,6 +344,10 @@ namespace BizHawk.Emulation.Common
case ".O2":
game.System = "O2";
break;
case ".UZE":
game.System = "UZE";
break;
}
game.Name = Path.GetFileNameWithoutExtension(fileName)?.Replace('_', ' ');

View File

@ -407,6 +407,8 @@
<Compile Include="Consoles\Atari\lynx\Lynx.IVideoProvider.cs">
<DependentUpon>Lynx.cs</DependentUpon>
</Compile>
<Compile Include="Consoles\Belogic\LibUzem.cs" />
<Compile Include="Consoles\Belogic\Uzem.cs" />
<Compile Include="Consoles\Coleco\ColecoVision.cs" />
<Compile Include="Consoles\Coleco\ColecoVision.IDebuggable.cs">
<DependentUpon>ColecoVision.cs</DependentUpon>

View File

@ -0,0 +1,28 @@
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Belogic
{
public abstract class LibUzem : LibWaterboxCore
{
[StructLayout(LayoutKind.Sequential)]
public new class FrameInfo : LibWaterboxCore.FrameInfo
{
public int ButtonsP1;
public int ButtonsP2;
public int ButtonsConsole;
}
[BizImport(CC)]
public abstract bool Init();
[BizImport(CC)]
public abstract bool MouseEnabled();
}
}

View File

@ -0,0 +1,153 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Belogic
{
[CoreAttributes("uzem", "David Etherton", true, false, "", "", false)]
public class Uzem : WaterboxCore
{
private LibUzem _uze;
private bool _mouseEnabled;
[CoreConstructor("UZE")]
public Uzem(CoreComm comm, byte[] rom)
:base(comm, new Configuration
{
DefaultWidth = 720,
DefaultHeight = 224,
MaxWidth = 720,
MaxHeight = 224,
MaxSamples = 4096,
SystemId = "UZE",
DefaultFpsNumerator = 28618182,
DefaultFpsDenominator = 476840
})
{
_uze = PreInit<LibUzem>(new PeRunnerOptions
{
Filename = "uzem.wbx",
SbrkHeapSizeKB = 4,
SealedHeapSizeKB = 4,
InvisibleHeapSizeKB = 4,
MmapHeapSizeKB = 4,
PlainHeapSizeKB = 4,
});
_exe.AddReadonlyFile(rom, "romfile");
if (!_uze.Init())
throw new InvalidOperationException("Core rejected the rom!");
_mouseEnabled = _uze.MouseEnabled();
_exe.RemoveReadonlyFile("romfile");
PostInit();
}
private static readonly ControllerDefinition TwoPads = new ControllerDefinition
{
Name = "SNES Controller",
BoolButtons =
{
"P1 Up", "P1 Left", "P1 Right", "P1 Down", "P1 Select", "P1 Start", "P1 X", "P1 A", "P1 B", "P1 Y", "P1 R", "P1 L",
"P2 Up", "P2 Left", "P2 Right", "P2 Down", "P2 Select", "P2 Start", "P2 X", "P2 A", "P2 B", "P2 Y", "P2 R", "P2 L",
"Power"
}
};
private static readonly ControllerDefinition Mouse = new ControllerDefinition
{
Name = "SNES Controller",
BoolButtons =
{
"P1 Mouse Left", "P1 Mouse Right", "Power"
},
FloatControls =
{
"P1 Mouse X", "P1 Mouse Y"
},
FloatRanges =
{
new[] { -127f, 0f, 127f },
new[] { -127f, 0f, 127f }
}
};
private static readonly string[] PadBits =
{
"B", "Y", "Select", "Start", "Up", "Down", "Left", "Right", "A", "X", "L", "R"
};
private static int EncodePad(IController c, int p)
{
int ret = 0;
int val = 1;
int idx = 0;
foreach (var s in PadBits)
{
if (c.IsPressed("P" + p + " " + PadBits[idx++]))
ret |= val;
val <<= 1;
}
return ret;
}
private static int EncodeDelta(float value)
{
int v = (int)value;
if (v > 127)
v = 127;
if (v < -127)
v = -127;
int ret = 0;
if (v < 0)
{
ret |= 1;
v = -v;
}
int mask = 64;
int bit = 2;
while (mask != 0)
{
if ((v & mask) != 0)
ret |= bit;
mask >>= 1;
bit <<= 1;
}
return ret;
}
public override ControllerDefinition ControllerDefinition => _mouseEnabled ? Mouse : TwoPads;
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
var ret = new LibUzem.FrameInfo();
if (_mouseEnabled)
{
ret.ButtonsP1 = EncodeDelta(controller.GetFloat("P1 X"))
| EncodeDelta(controller.GetFloat("P1 Y"))
| 0x8000;
if (controller.IsPressed("P1 Mouse Left"))
ret.ButtonsP1 |= 0x200;
if (controller.IsPressed("P1 Mouse Right"))
ret.ButtonsP1 |= 0x100;
}
else
{
ret.ButtonsP1 = EncodePad(controller, 1);
ret.ButtonsP2 = EncodePad(controller, 2);
}
if (controller.IsPressed("Power"))
ret.ButtonsConsole = 1;
return ret;
}
public override int VirtualHeight => 448; // TODO: It's not quite this, NTSC and such
}
}

BIN
output/dll/uzem.wbx.gz Normal file

Binary file not shown.

10
waterbox/uzem/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
"files.associations": {
"ios": "cpp",
"xiosbase": "cpp",
"queue": "cpp"
},
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false
}

45
waterbox/uzem/Makefile Normal file
View File

@ -0,0 +1,45 @@
CC = x86_64-nt64-midipix-g++
CCFLAGS:= -I. -I../emulibc \
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
-Wno-reorder \
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
-DNOGDB \
-O3 -flto
TARGET = uzem.wbx
LDFLAGS = -Wl,--dynamicbase,--export-all-symbols
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRCS:=$(shell find $(ROOT_DIR) -type f -name '*.cpp')
OBJ_DIR:=$(ROOT_DIR)/obj
_OBJS:=$(SRCS:.cpp=.o)
OBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.o: %.cpp
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS)
all: $(TARGET)
.PHONY: clean all
$(TARGET).in: $(OBJS)
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
$(TARGET): $(TARGET).in
strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
# cp $< $@
clean:
rm -rf $(OBJ_DIR)
rm -f $(TARGET).in
rm -f $(TARGET)
print-%:
@echo $* = $($*)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

2328
waterbox/uzem/avr8.cpp Normal file

File diff suppressed because it is too large Load Diff

697
waterbox/uzem/avr8.h Normal file
View File

@ -0,0 +1,697 @@
/*
(The MIT License)
Copyright (c) 2008-2016 by
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <vector>
#include <stdint.h>
#include <queue>
#include <cstring>
// Video: Offset of display on the emulator's surface
// Syncronized with the kernel, this value now results in the image
// being perfectly centered in both the emulator and a real TV
#define VIDEO_LEFT_EDGE 168U
// Video: Display width; the width of the emulator's output (before any
// scaling applied) and video capturing
#define VIDEO_DISP_WIDTH 720U
//Uzebox keyboard defines
#define KB_STOP 0
#define KB_TX_START 1
#define KB_TX_READY 2
#define KB_SEND_KEY 0x00
#define KB_SEND_END 0x01
#define KB_SEND_DEVICE_ID 0x02
#define KB_SEND_FIRMWARE_REV 0x03
#define KB_RESET 0x7f
// Joysticks
#define MAX_JOYSTICKS 2
#define NUM_JOYSTICK_BUTTONS 8
#define MAX_JOYSTICK_AXES 8
#define MAX_JOYSTICK_HATS 8
#define JOY_SNES_X 0
#define JOY_SNES_A 1
#define JOY_SNES_B 2
#define JOY_SNES_Y 3
#define JOY_SNES_LSH 6
#define JOY_SNES_RSH 7
#define JOY_SNES_SELECT 8
#define JOY_SNES_START 9
#define JOY_DIR_UP 1
#define JOY_DIR_RIGHT 2
#define JOY_DIR_DOWN 4
#define JOY_DIR_LEFT 8
#define JOY_DIR_COUNT 4
#define JOY_AXIS_UNUSED -1
#define JOY_MASK_UP 0x11111111
#define JOY_MASK_RIGHT 0x22222222
#define JOY_MASK_DOWN 0x44444444
#define JOY_MASK_LEFT 0x88888888
#ifndef JOY_ANALOG_DEADZONE
#define JOY_ANALOG_DEADZONE 4096
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400
// don't whine about sprintf and fopen.
// could switch to sprintf_s but that's not standard.
#pragma warning(disable : 4996)
#endif
// 644 Overview: http://www.atmel.com/dyn/resources/prod_documents/doc2593.pdf
// AVR8 insn set: http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf
enum
{
NES_A,
NES_B,
PAD_SELECT,
PAD_START,
PAD_UP,
PAD_DOWN,
PAD_LEFT,
PAD_RIGHT
};
enum
{
SNES_B,
SNES_Y,
SNES_A = 8,
SNES_X,
SNES_LSH,
SNES_RSH
};
#if 1 // 644P
const unsigned eepromSize = 2048;
const unsigned sramSize = 4096;
const unsigned progSize = 65536;
#else // 1284P
const unsigned eepromSize = 4096;
const unsigned sramSize = 16384;
const unsigned progSize = 131072;
#endif
#define IOBASE 32
#define SRAMBASE 256
namespace ports
{
enum
{
PINA,
DDRA,
PORTA,
PINB,
DDRB,
PORTB,
PINC,
DDRC,
PORTC,
PIND,
DDRD,
PORTD,
res2C,
res2D,
res2E,
res2F,
res30,
res31,
res32,
res33,
res34,
TIFR0,
TIFR1,
TIFR2,
res38,
res39,
res3A,
PCIFR,
EIFR,
EIMSK,
GPIOR0,
EECR,
EEDR,
EEARL,
EEARH,
GTCCR,
TCCR0A,
TCCR0B,
TCNT0,
OCR0A,
OCR0B,
res49,
GPIOR1,
GPIOR2,
SPCR,
SPSR,
SPDR,
res4f,
ACSR,
OCDR,
res52,
SMCR,
MCUSR,
MCUCR,
res56,
SPMCSR,
res58,
res59,
res5A,
res5B,
res5C,
SPL,
SPH,
SREG,
WDTCSR,
CLKPR,
res62,
res63,
PRR,
res65,
OSCCAL,
res67,
PCICR,
EICRA,
res6a,
PCMSK0,
PCMSK1,
PCMSK2,
TIMSK0,
TIMSK1,
TIMSK2,
res71,
res72,
PCMSK3,
res74,
res75,
res76,
res77,
ADCL,
ADCH,
ADCSRA,
ADCSRB,
ADMUX,
res7d,
DIDR0,
DIDR1,
TCCR1A,
TCCR1B,
TCCR1C,
res83,
TCNT1L,
TCNT1H,
ICR1L,
ICR1H,
OCR1AL,
OCR1AH,
OCR1BL,
OCR1BH,
res8c,
res8d,
res8e,
res8f,
res90,
res91,
res92,
res93,
res94,
res95,
res96,
res97,
res98,
res99,
res9a,
res9b,
res9c,
res9d,
res9e,
res9f,
resa0,
resa1,
resa2,
resa3,
resa4,
resa5,
resa6,
resa7,
resa8,
resa9,
resaa,
resab,
resac,
resad,
resae,
resaf,
TCCR2A,
TCCR2B,
TCNT2,
OCR2A,
OCR2B,
resb5,
ASSR,
resb7,
TWBR,
TWSR,
TWAR,
TWDR,
TWCR,
TWAMR,
resbe,
resbf,
UCSR0A,
UCSR0B,
UCSR0C,
resc3,
UBRR0L,
UBRR0H,
UDR0,
resc7,
resc8,
resc9,
resca,
rescb,
rescc,
rescd,
resce,
rescf,
resd0,
resd1,
resd2,
resd3,
resd4,
resd5,
resd6,
resd7,
resd8,
resd9,
resda,
resdb,
resdc,
resdd,
resde,
resdf,
rese0,
rese1,
rese2,
rese3,
rese4,
rese5,
rese6,
rese7,
rese8,
rese9,
resea,
reseb,
resec,
resed,
resee,
resef,
resf0,
resf1,
resf2,
resf3,
resf4,
resf5,
resf6,
resf7,
resf8,
resf9,
resfa,
resfb,
resfc,
resfd,
resfe,
resff
};
}
typedef uint8_t u8;
typedef int8_t s8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef struct
{
s16 arg2;
u8 arg1;
u8 opNum;
} __attribute__((packed)) instructionDecode_t;
typedef struct
{
u8 opNum;
char opName[32];
u8 arg1Type;
u8 arg1Mul;
u8 arg1Offset;
u8 arg1Neg;
u8 arg2Type;
u8 arg2Mul;
u8 arg2Offset;
u8 arg2Neg;
u8 words;
u8 clocks;
u16 mask;
u16 arg1Mask;
u16 arg2Mask;
} instructionList_t;
using namespace std;
//SPI state machine states
enum
{
SPI_IDLE_STATE,
SPI_ARG_X_LO,
SPI_ARG_X_HI,
SPI_ARG_Y_LO,
SPI_ARG_Y_HI,
SPI_ARG_CRC,
SPI_RESPOND_SINGLE,
SPI_RESPOND_MULTI,
SPI_READ_SINGLE_BLOCK,
SPI_READ_MULTIPLE_BLOCK,
SPI_WRITE_SINGLE,
SPI_WRITE_SINGLE_BLOCK,
SPI_RESPOND_R1,
SPI_RESPOND_R1B,
SPI_RESPOND_R2,
SPI_RESPOND_R3,
SPI_RESPOND_R7,
};
struct SDPartitionEntry
{
u8 state;
u8 startHead;
u16 startCylinder;
u8 type;
u8 endHead;
u16 endCylinder;
u32 sectorOffset;
u32 sectorCount;
};
struct avr8
{
avr8() : /*Core*/
pc(0),
watchdogTimer(0), prevPortB(0), prevWDR(0),
dly_out(0), itd_TIFR1(0), elapsedCyclesSleep(0),
timer1_next(0), timer1_base(0), TCNT1(0),
//to align with AVR Simulator 2 since it has a bug that the first JMP
//at the reset vector takes only 2 cycles
cycleCounter(-1),
/*Video*/
video_buffer(nullptr),
/*Audio*/
enableSound(true),
/*Joystick*/
new_input_mode(false), lagged(false),
/*Uzekeyboard*/
uzeKbState(0), uzeKbEnabled(false),
/*SPI Emulation*/
spiByte(0), spiClock(0), spiTransfer(0), spiState(SPI_IDLE_STATE), spiResponsePtr(0), spiResponseEnd(0)
{
memset(r, 0, sizeof(r));
memset(io, 0, sizeof(io));
memset(sram, 0, sizeof(sram));
memset(eeprom, 0, sizeof(eeprom));
memset(progmem, 0, progSize / 2);
memset(progmemDecoded, 0, progSize / 2);
}
/*Core*/
u16 progmem[progSize / 2];
instructionDecode_t progmemDecoded[progSize / 2];
u16 pc, currentPc;
private:
unsigned int cycleCounter;
unsigned int elapsedCycles, prevCyclesCounter, elapsedCyclesSleep, lastCyclesSleep;
unsigned int prevPortB, prevWDR;
unsigned int watchdogTimer;
unsigned int cycle_ctr_ins; // Used in update_hardware_ins to track elapsed cycles between calls
// u8 eeClock; TODO: Only set at one location, never used. Maybe a never completed EEPROM timing code.
unsigned int T16_latch; // Latch for 16-bit timers (16 bits used)
unsigned int TCNT1; // Timer 1 counter (used instead of TCNT1H:TCNT1L)
unsigned int timer1_next; // Cycles remaining until next timer1 event
unsigned int timer1_base; // Where the between-events timer started (to reproduce TCNT1)
unsigned int itd_TIFR1; // Interrupt delaying for TIFR1 (8 bits used)
unsigned int dly_out; // Delayed output flags
unsigned int dly_TCCR1B; // Delayed Timer1 controls
unsigned int dly_TCNT1L; // Delayed Timer1 count (low)
unsigned int dly_TCNT1H; // Delayed Timer1 count (high)
public:
int randomSeed;
u16 decodeArg(u16 flash, u16 argMask, u8 argNeg);
void instructionDecode(u16 address);
void decodeFlash(void);
void decodeFlash(u16 address);
struct
{
union {
u8 r[32]; // Register file
struct
{
u8 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
u8 r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, XL, XH, YL, YH, ZL, ZH;
};
};
union {
u8 io[256]; // Direct-mapped I/O space
struct
{
u8 PINA, DDRA, PORTA, PINB, DDRB, PORTB, PINC, DDRC;
u8 PORTC, PIND, DDRD, PORTD, res2C, res2D, res2E, res2F;
u8 res30, res31, res32, res33, res34, TIFR0, TIFR1, TIFR2;
u8 res38, res39, res3A, PCIFR, EIFR, EIMSK, GPIOR0, EECR;
u8 EEDR, EEARL, EEARH, GTCCR, TCCR0A, TCCR0B, TCNT0, OCR0A;
u8 OCR0B, res49, GPIOR1, GPIOR2, SPCR, SPSR, SPDR, res4f;
u8 ACSR, OCDR, res52, SMCR, MCUSR, MCUCR, res56, SPMCSR;
u8 res58, res59, res5A, res5B, res5C, SPL, SPH, SREG;
u8 WDTCSR, CLKPR, res62, res63, PRR, res65, OSCCAL, res67;
u8 PCICR, EICRA, res6a, PCMSK0, PCMSK1, PCMSK2, TIMSK0, TIMSK1;
u8 TIMSK2, res71, res72, PCMSK3, res74, res75, res76, res77;
u8 ADCL, ADCH, ADCSRA, ADCSRB, ADMUX, res7d, DIDR0, DIDR1;
u8 TCCR1A, TCCR1B, TCCR1C, res83, TCNT1L, TCNT1H, ICR1L, ICR1H;
u8 OCR1AL, OCR1AH, OCR1BL, OCR1BH, res8c, res8d, res8e, res8f;
u8 res90, res91, res92, res93, res94, res95, res96, res97;
u8 res98, res99, res9a, res9b, res9c, res9d, res9e, res9f;
u8 resa0, resa1, resa2, resa3, resa4, resa5, resa6, resa7;
u8 resa8, resa9, resaa, resab, resac, resad, resae, resaf;
u8 TCCR2A, TCCR2B, TCNT2, OCR2A, OCR2B, resb5, ASSR, resb7;
u8 TWBR, TWSR, TWAR, TWDR, TWCR, TWAMR, resbe, resbf;
u8 UCSR0A, UCSR0B, UCSR0C, resc3, UBRR0L, UBRR0H, UDR0, resc7;
u8 resc8, resc9, resca, rescb, rescc, rescd, resce, rescf;
u8 resd0, resd1, resd2, resd3, resd4, resd5, resd6, resd7;
u8 resd8, resd9, resda, resdb, resdc, resdd, resde, resdf;
u8 rese0, rese1, rese2, rese3, rese4, rese5, rese6, rese7;
u8 rese8, rese9, resea, reseb, resec, resed, resee, resef;
u8 resf0, resf1, resf2, resf3, resf4, resf5, resf6, resf7;
u8 resf8, resf9, resfa, resfb, resfc, resfd, resfe, resff;
};
};
u8 sram[sramSize];
};
u8 eeprom[eepromSize];
int scanline_count;
unsigned int left_edge_cycle;
int scanline_top;
unsigned int left_edge;
u32 inset;
u32 palette[256];
u8 scanline_buf[2048]; // For collecting pixels from a single scanline
u8 pixel_raw; // Raw (8 bit) input pixel
u32 *video_buffer;
/*Audio*/
bool enableSound;
/*Joystick*/
// SNES bit order: 0 = B, Y, Select, Start, Up, Down, Left, Right, A, X, L, 11 = R
// NES bit order: 0 = A, B, Select, Start, Up, Down, Left, 7 = Right
u32 buttons[2], latched_buttons[2];
bool new_input_mode;
bool lagged;
/*Uzebox Keyboard*/
u8 uzeKbState;
u8 uzeKbDataOut;
bool uzeKbEnabled;
queue<u8> uzeKbScanCodeQueue;
u8 uzeKbDataIn;
u8 uzeKbClock;
/*SPI Emulation*/
u8 spiByte;
u8 spiTransfer;
u16 spiClock;
u16 spiCycleWait;
u8 spiState;
u8 spiCommand;
u8 spiCommandDelay;
union {
u32 spiArg;
union {
struct
{
u16 spiArgY;
u16 spiArgX;
};
struct
{
u8 spiArgYlo;
u8 spiArgYhi;
u8 spiArgXlo;
u8 spiArgXhi;
};
};
};
u32 spiByteCount;
u8 spiResponseBuffer[12];
u8 *spiResponsePtr;
u8 *spiResponseEnd;
private:
void write_io(u8 addr, u8 value);
u8 read_io(u8 addr);
// Should not be called directly (see write_io)
void write_io_x(u8 addr, u8 value);
inline u8 read_progmem(u16 addr)
{
u16 word = progmem[addr >> 1];
return (addr & 1) ? word >> 8 : word;
}
inline void write_sram(u16 addr, u8 value)
{
sram[(addr - SRAMBASE) & (sramSize - 1U)] = value;
}
void write_sram_io(u16 addr, u8 value)
{
if (addr >= SRAMBASE)
{
sram[(addr - SRAMBASE) & (sramSize - 1)] = value;
}
else if (addr >= IOBASE)
{
write_io(addr - IOBASE, value);
}
else
{
r[addr] = value; // Write a register
}
}
inline u8 read_sram(u16 addr)
{
return sram[(addr - SRAMBASE) & (sramSize - 1U)];
}
u8 read_sram_io(u16 addr)
{
if (addr >= SRAMBASE)
{
return sram[(addr - SRAMBASE) & (sramSize - 1)];
}
else if (addr >= IOBASE)
{
return read_io(addr - IOBASE);
}
else
{
return r[addr]; // Read a register
}
}
inline static unsigned int get_insn_size(unsigned int insn)
{
/* 41 LDS Rd,k (next word is rest of address)
82 STS k,Rr (next word is rest of address)
30 JMP k (next word is rest of address)
14 CALL k (next word is rest of address) */
// This code is simplified by assuming upper k bits are zero on 644
if (insn == 14 || insn == 30 || insn == 41 || insn == 82)
{
return 2U;
}
else
{
return 1U;
}
}
public:
bool init_gui();
void draw_memorymap();
void trigger_interrupt(unsigned int location);
unsigned int exec();
void spi_calculateClock();
void update_hardware();
void update_hardware_fast();
void update_hardware_ins();
void update_spi();
u8 SDReadByte();
void SDWriteByte(u8 value);
void SDCommit();
void LoadEEPROMFile(const char *filename);
void shutdown(int errcode);
void idle(void);
};
// undefine the following to disable SPI debug messages
#ifdef USE_SPI_DEBUG
#define SPI_DEBUG(...) printf(__VA_ARGS__)
#else
#define SPI_DEBUG(...)
#endif
#ifdef USE_EEPROM_DEBUG
#define EEPROM_DEBUG(...) printf(__VA_ARGS__)
#else
#define EEPROM_DEBUG(...)
#endif

View File

@ -0,0 +1,92 @@
0000 0000 0000 0000 NOP
0000 0001 dddd rrrr MOVW Rd+1:Rd,Rr+1:R
0000 0010 dddd rrrr MULS Rd,Rr
0000 0011 0ddd 0rrr MULSU Rd,Rr (registers are in 16-23 range)
0000 0011 0ddd 1rrr FMUL Rd,Rr (registers are in 16-23 range)
0000 0011 1ddd 0rrr FMULS Rd,Rr
0000 0011 1ddd 1rrr FMULSU Rd,Rr
0000 01rd dddd rrrr CPC Rd,Rr
0000 10rd dddd rrrr SBC Rd,Rr
0000 11rd dddd rrrr ADD Rd,Rr (LSL is ADD Rd,Rd)
0001 00rd dddd rrrr CPSE Rd,Rr
0001 01rd dddd rrrr CP Rd,Rr
0001 10rd dddd rrrr SUB Rd,Rr
0001 11rd dddd rrrr ADC Rd,Rr (ROL is ADC Rd,Rd)
0010 00rd dddd rrrr AND Rd,Rr (TST is AND Rd,Rd)
0010 01rd dddd rrrr EOR Rd,Rr (CLR is EOR Rd,Rd)
0010 10rd dddd rrrr OR Rd,Rr
0010 11rd dddd rrrr MOV Rd,Rr
0011 KKKK dddd KKKK CPI Rd,K
0100 KKKK dddd KKKK SBCI Rd,K
0101 KKKK dddd KKKK SUBI Rd,K
0110 KKKK dddd KKKK ORI Rd,K (same as SBR insn)
0111 KKKK dddd KKKK ANDI Rd,K (CBR is ANDI with K complemented)
10q0 qq0d dddd 0qqq LD Rd,Z+q
10q0 qq0d dddd 1qqq LD Rd,Y+q
10q0 qq1d dddd 0qqq ST Z+q,Rd
10q0 qq1d dddd 1qqq ST Y+q,Rd
1001 000d dddd 0000 LDS Rd,k (next word is rest of address)
1001 000d dddd 0001 LD Rd,Z+
1001 000d dddd 0010 LD Rd,-Z
1001 000d dddd 0100 LPM Rd,Z
1001 000d dddd 0101 LPM Rd,Z+
1001 000d dddd 0110 ELPM Rd,Z
1001 000d dddd 0111 ELPM Rd,Z+
1001 000d dddd 1001 LD Rd,Y+
1001 000d dddd 1010 LD Rd,-Y
1001 000d dddd 1100 LD rd,X
1001 000d dddd 1101 LD rd,X+
1001 000d dddd 1110 LD rd,-X
1001 000d dddd 1111 POP Rd
1001 001d dddd 0000 STS k,Rr (next word is rest of address)
1001 001r rrrr 0001 ST Z+,Rr
1001 001r rrrr 0010 ST -Z,Rr
1001 001r rrrr 1001 ST Y+,Rr
1001 001r rrrr 1010 ST -Y,Rr
1001 001r rrrr 1100 ST X,Rr
1001 001r rrrr 1101 ST X+,Rr
1001 001r rrrr 1110 ST -X,Rr
1001 001d dddd 1111 PUSH Rd
1001 010d dddd 0000 COM Rd
1001 010d dddd 0001 NEG Rd
1001 010d dddd 0010 SWAP Rd
1001 010d dddd 0011 INC Rd
1001 010d dddd 0101 ASR Rd
1001 010d dddd 0110 LSR Rd
1001 010d dddd 0111 ROR Rd
1001 010d dddd 1010 DEC Rd
1001 010k kkkk 110k JMP k (next word is rest of address)
1001 010k kkkk 111k CALL k (next word is rest of address)
1001 0100 0sss 1000 BSET s (SEC, etc are aliases with sss implicit)
1001 0100 1sss 1000 BCLR s (CLC, etc are aliases with sss implicit)
1001 0100 0000 1001 IJMP (jump thru Z register)
1001 0101 0000 1000 RET
1001 0101 0000 1001 ICALL (call thru Z register)
1001 0101 0001 1000 RETI
1001 0101 1000 1000 SLEEP
1001 0101 1001 1000 BREAK
1001 0101 1010 1000 WDR
1001 0101 1100 1000 LPM (r0 implied, why is this special?)
1001 0101 1110 1000 SPM Z (writes R1:R0)
1001 0110 KKdd KKKK ADIW Rd+1:Rd,K (16-bit add to upper four register pairs)
1001 0111 KKdd KKKK SBIW Rd+1:Rd,K
1001 1000 AAAA Abbb CBI A,b
1001 1001 AAAA Abbb SBIC A,b
1001 1010 AAAA Abbb SBI A,b
1001 1011 AAAA Abbb SBIS A,b
1001 11rd dddd rrrr MUL Rd,Rr
1011 0AAd dddd AAAA IN Rd,A
1011 1AAd dddd AAAA OUT A,Rd
1100 kkkk kkkk kkkk RJMP k
1101 kkkk kkkk kkkk RCALL k
1110 KKKK dddd KKKK LDI Rd,K (SER is just LDI Rd,255)
1111 00kk kkkk ksss BRBS s,k (same here)
1111 01kk kkkk ksss BRBC s,k (BRCC, etc are aliases for this with sss implicit)
1111 100d dddd 0bbb BLD Rd,b
1111 101d dddd 0bbb BST Rd,b
1111 110r rrrr 0bbb SBRC Rr,b
1111 111r rrrr 0bbb SBRS Rr,b

344
waterbox/uzem/blip_buf.cpp Normal file
View File

@ -0,0 +1,344 @@
/* blip_buf 1.1.0. http://www.slack.net/~ant/ */
#include "blip_buf.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
/* Library Copyright (C) 2003-2009 Shay Green. This library is free software;
you can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
library is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#if defined (BLARGG_TEST) && BLARGG_TEST
#include "blargg_test.h"
#endif
/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000.
Avoids constants that don't fit in 32 bits. */
#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF
typedef unsigned long fixed_t;
enum { pre_shift = 32 };
#elif defined(ULLONG_MAX)
typedef unsigned long long fixed_t;
enum { pre_shift = 32 };
#else
typedef unsigned fixed_t;
enum { pre_shift = 0 };
#endif
enum { time_bits = pre_shift + 20 };
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
enum { half_width = 8 };
enum { buf_extra = half_width*2 + end_frame_extra };
enum { phase_bits = 5 };
enum { phase_count = 1 << phase_bits };
enum { delta_bits = 15 };
enum { delta_unit = 1 << delta_bits };
enum { frac_bits = time_bits - pre_shift };
/* We could eliminate avail and encode whole samples in offset, but that would
limit the total buffered samples to blip_max_frame. That could only be
increased by decreasing time_bits, which would reduce resample ratio accuracy.
*/
/** Sample buffer that resamples to output rate and accumulates samples
until they're read out */
struct blip_t
{
fixed_t factor;
fixed_t offset;
int avail;
int size;
int integrator;
};
typedef int buf_t;
/* probably not totally portable */
#define SAMPLES( buf ) ((buf_t*) ((buf) + 1))
/* Arithmetic (sign-preserving) right shift */
#define ARITH_SHIFT( n, shift ) \
((n) >> (shift))
enum { max_sample = +32767 };
enum { min_sample = -32768 };
#define CLAMP( n ) \
{\
if ( (short) n != n )\
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
}
static void check_assumptions( void )
{
int n;
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
#error "int must be at least 32 bits"
#endif
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
n = max_sample * 2;
CLAMP( n );
assert( n == max_sample );
n = min_sample * 2;
CLAMP( n );
assert( n == min_sample );
assert( blip_max_ratio <= time_unit );
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
}
blip_t* blip_new( int size )
{
blip_t* m;
assert( size >= 0 );
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
if ( m )
{
m->factor = time_unit / blip_max_ratio;
m->size = size;
blip_clear( m );
check_assumptions();
}
return m;
}
void blip_delete( blip_t* m )
{
if ( m != NULL )
{
/* Clear fields in case user tries to use after freeing */
memset( m, 0, sizeof *m );
free( m );
}
}
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
{
double factor = time_unit * sample_rate / clock_rate;
m->factor = (fixed_t) factor;
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
/* Avoid requiring math.h. Equivalent to
m->factor = (int) ceil( factor ) */
if ( m->factor < factor )
m->factor++;
/* At this point, factor is most likely rounded up, but could still
have been rounded down in the floating-point calculation. */
}
void blip_clear( blip_t* m )
{
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
factor is rounded up. factor-1 is suitable if factor is rounded down.
Since we don't know rounding direction, factor/2 accommodates either,
with the slight loss of showing an error in half the time. Since for
a 64-bit factor this is years, the halving isn't a problem. */
m->offset = m->factor / 2;
m->avail = 0;
m->integrator = 0;
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
}
int blip_clocks_needed( const blip_t* m, int samples )
{
fixed_t needed;
/* Fails if buffer can't hold that many more samples */
assert( samples >= 0 && m->avail + samples <= m->size );
needed = (fixed_t) samples * time_unit;
if ( needed < m->offset )
return 0;
return (needed - m->offset + m->factor - 1) / m->factor;
}
void blip_end_frame( blip_t* m, unsigned t )
{
fixed_t off = t * m->factor + m->offset;
m->avail += off >> time_bits;
m->offset = off & (time_unit - 1);
/* Fails if buffer size was exceeded */
assert( m->avail <= m->size );
}
int blip_samples_avail( const blip_t* m )
{
return m->avail;
}
static void remove_samples( blip_t* m, int count )
{
buf_t* buf = SAMPLES( m );
int remain = m->avail + buf_extra - count;
m->avail -= count;
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
memset( &buf [remain], 0, count * sizeof buf [0] );
}
int blip_read_samples( blip_t* m, short out [], int count, int stereo )
{
assert( count >= 0 );
if ( count > m->avail )
count = m->avail;
if ( count )
{
int const step = stereo ? 2 : 1;
buf_t const* in = SAMPLES( m );
buf_t const* end = in + count;
int sum = m->integrator;
do
{
/* Eliminate fraction */
int s = ARITH_SHIFT( sum, delta_bits );
sum += *in++;
CLAMP( s );
*out = s;
out += step;
/* High-pass filter */
sum -= s << (delta_bits - bass_shift);
}
while ( in != end );
m->integrator = sum;
remove_samples( m, count );
}
return count;
}
/* Things that didn't help performance on x86:
__attribute__((aligned(128)))
#define short int
restrict
*/
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
static short const bl_step [phase_count + 1] [half_width] =
{
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
{ 46, -122, 336, -431, 942, -549, 4156,20829},
{ 47, -123, 327, -404, 868, -418, 3629,20679},
{ 47, -122, 316, -375, 792, -285, 3124,20488},
{ 47, -120, 303, -344, 714, -151, 2644,20256},
{ 46, -117, 289, -310, 634, -17, 2188,19985},
{ 46, -114, 273, -275, 553, 117, 1758,19675},
{ 44, -108, 255, -237, 471, 247, 1356,19327},
{ 43, -103, 237, -199, 390, 373, 981,18944},
{ 42, -98, 218, -160, 310, 495, 633,18527},
{ 40, -91, 198, -121, 231, 611, 314,18078},
{ 38, -84, 178, -81, 153, 722, 22,17599},
{ 36, -76, 157, -43, 80, 824, -241,17092},
{ 34, -68, 135, -3, 8, 919, -476,16558},
{ 32, -61, 115, 34, -60, 1006, -683,16001},
{ 29, -52, 94, 70, -123, 1083, -862,15422},
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
};
/* Shifting by pre_shift allows calculation using unsigned int rather than
possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
And by having pre_shift 32, a 32-bit platform can easily do the shift by
simply ignoring the low half. */
void blip_add_delta( blip_t* m, unsigned time, int delta )
{
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
int const phase_shift = frac_bits - phase_bits;
int phase = fixed >> phase_shift & (phase_count - 1);
short const* in = bl_step [phase];
short const* rev = bl_step [phase_count - phase];
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
int delta2 = (delta * interp) >> delta_bits;
delta -= delta2;
/* Fails if buffer size was exceeded */
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
out [0] += in[0]*delta + in[half_width+0]*delta2;
out [1] += in[1]*delta + in[half_width+1]*delta2;
out [2] += in[2]*delta + in[half_width+2]*delta2;
out [3] += in[3]*delta + in[half_width+3]*delta2;
out [4] += in[4]*delta + in[half_width+4]*delta2;
out [5] += in[5]*delta + in[half_width+5]*delta2;
out [6] += in[6]*delta + in[half_width+6]*delta2;
out [7] += in[7]*delta + in[half_width+7]*delta2;
in = rev;
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
out [10] += in[5]*delta + in[5-half_width]*delta2;
out [11] += in[4]*delta + in[4-half_width]*delta2;
out [12] += in[3]*delta + in[3-half_width]*delta2;
out [13] += in[2]*delta + in[2-half_width]*delta2;
out [14] += in[1]*delta + in[1-half_width]*delta2;
out [15] += in[0]*delta + in[0-half_width]*delta2;
}
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
{
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
int delta2 = delta * interp;
/* Fails if buffer size was exceeded */
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
out [7] += delta * delta_unit - delta2;
out [8] += delta2;
}

72
waterbox/uzem/blip_buf.h Normal file
View File

@ -0,0 +1,72 @@
/** \file
Sample buffer that resamples from input clock rate to output sample rate */
/* blip_buf 1.1.0 */
#ifndef BLIP_BUF_H
#define BLIP_BUF_H
#ifdef __cplusplus
extern "C" {
#endif
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
is changed. */
typedef struct blip_t blip_t;
/** Creates new buffer that can hold at most sample_count samples. Sets rates
so that there are blip_max_ratio clocks per sample. Returns pointer to new
buffer, or NULL if insufficient memory. */
blip_t* blip_new( int sample_count );
/** Sets approximate input clock rate and output sample rate. For every
clock_rate input clocks, approximately sample_rate samples are generated. */
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
clock_rate must not be greater than sample_rate*blip_max_ratio. */
blip_max_ratio = 1 << 20 };
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
void blip_clear( blip_t* );
/** Adds positive/negative delta into buffer at specified clock time. */
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
/** Length of time frame, in clocks, needed to make sample_count additional
samples available. */
int blip_clocks_needed( const blip_t*, int sample_count );
enum { /** Maximum number of samples that can be generated from one time frame. */
blip_max_frame = 4000 };
/** Makes input clocks before clock_duration available for reading as output
samples. Also begins new time frame at clock_duration, so that clock time 0 in
the new time frame specifies the same clock as clock_duration in the old time
frame specified. Deltas can have been added slightly past clock_duration (up to
however many clocks there are in two output samples). */
void blip_end_frame( blip_t*, unsigned int clock_duration );
/** Number of buffered samples available for reading. */
int blip_samples_avail( const blip_t* );
/** Reads and removes at most 'count' samples and writes them to 'out'. If
'stereo' is true, writes output to every other element of 'out', allowing easy
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
samples. Returns number of samples actually read. */
int blip_read_samples( blip_t*, short out [], int count, int stereo );
/** Frees buffer. No effect if NULL is passed. */
void blip_delete( blip_t* );
/* Deprecated */
typedef blip_t blip_buffer_t;
#ifdef __cplusplus
}
#endif
#endif

173
waterbox/uzem/dump.c Normal file
View File

@ -0,0 +1,173 @@
/*
Copyright (c) 2009 Eric Anderton
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
struct SDPartitionEntry{
BYTE state;
BYTE startHead;
WORD startCylinder;
BYTE type;
BYTE endHead;
WORD endCylinder;
DWORD sectorOffset;
DWORD sectorCount;
};
// Partition 1 example
/*
entry.state = 0x00;
entry.startHead = 0x03;
entry.startCylinder = 0x003D;
entry.type = 0x06;
entry.endHead = 0x0D;
entry.endCylinder = 0xDBED;
entry.sectorOffset = 0x000000F9;
entry.sectorCount = 0x001E5F07;
*/
//Code mostly borrowed from: http://support.microsoft.com/kb/138434
#define SECTORS_PER_WRITE 4096
char drivePath[] = "\\\\.\\X:";
int main(int argc,char** argv)
{
HANDLE hCD, hFile;
DWORD dwNotUsed;
if (argc<3){
printf("Disk Image dumper - creates binary images of disks, suitable for SD media.\n");
printf("(c) 2009 Eric Anderton\n");
printf("\nUsage: dump DRIVELETTER FILENAME\n");
exit(1);
}
if(strlen(argv[1]) > 1){
printf("Invalid drive letter.\n");
exit(1);
}
// set the drive letter in the path specification
drivePath[4] = argv[1][0];
hFile = CreateFile (argv[2],GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hCD = CreateFile (drivePath, GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (hCD != INVALID_HANDLE_VALUE){
DISK_GEOMETRY disk;
PARTITION_INFORMATION partition;
PARTITION_INFORMATION_MBR mbr;
// Get sector size of compact disc
if (DeviceIoControl (hCD, IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL, 0, &disk, sizeof(disk),
&dwNotUsed, NULL))
{
LPBYTE lpSector;
DWORD dwSize = disk.BytesPerSector; // 2 sectors
DWORD dwReadSize = dwSize*SECTORS_PER_WRITE;
__int64 cylinders = *((__int64*)&disk);
__int64 sectors = cylinders * disk.TracksPerCylinder * disk.SectorsPerTrack;
__int64 totalSize = sectors*dwSize;
__int64 i;
printf("Cylinders %lld\nTracks Per Cylinder: %d\nSectors Per Track %d\nSector Size: %d\n",cylinders,disk.TracksPerCylinder,disk.SectorsPerTrack,dwSize);
printf("Total Sectors: %lld\n",sectors);
printf("Media Size: %lld\n",totalSize);
// Allocate buffer to hold sectors from compact disc. Note that
// the buffer will be allocated on a sector boundary because the
// allocation granularity is larger than the size of a sector on a
// compact disk.
lpSector = (LPBYTE)VirtualAlloc (NULL, dwReadSize,MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
SDPartitionEntry entry;
// query system about partition and fill out the partition structure
if(DeviceIoControl(hCD, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partition, sizeof(PARTITION_INFORMATION), &dwNotUsed, NULL)){
entry.state = 0x00;
entry.startCylinder = 0;//(*(__int64*)(&partition.StartingOffset))/dwSize;
entry.startHead = 0x00; //TODO
entry.startCylinder = 0x0000; //TODO
entry.type = partition.PartitionType;
entry.endHead = 0x00; //TODO
entry.endCylinder = 0x0000; //TODO
entry.sectorOffset = partition.HiddenSectors;
entry.sectorCount = (*(__int64*)(&partition.PartitionLength))/dwSize;
printf("----------\n");
printf("state: %0.4X\n",entry.state);
// printf("startHead: %0.4X\n",entry.startHead);
// printf("startCylinder: %0.4X\n",entry.startCylinder);
printf("type: %0.2X\n",entry.type);
// printf("endHead: %0.4X\n",entry.endHead);
// printf("endCylinder: %0.4X\n",entry.endCylinder);
printf("sectorCount: %0.8X\n",entry.sectorCount);
printf("sectorOffset: %0.8X\n",entry.sectorOffset);
}
else{
printf("Error reading parition info.\n");
exit(1);
}
// build a replica of the MBR for a single-partition image (common for SD media)
memset(lpSector,0,dwSize);
memcpy(lpSector + 0x1BE,&entry,sizeof(SDPartitionEntry));
// Executable Marker
lpSector[0x1FE] = 0x55;
lpSector[0x1FF] = 0xAA;
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
// write out hidden sectors (empty)
memset(lpSector,0,dwSize);
for(i = 1; i < entry.sectorOffset; i++){
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
}
// iteratively read all the sectors for the disk image
printf("Writing...");
for(i = 0; i < sectors/SECTORS_PER_WRITE; i++){
// Read sectors from the disc and write them to a file.
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
}
DWORD leftovers = sectors-i;
if(leftovers > 0){
dwReadSize = leftovers*dwSize;
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
}
VirtualFree (lpSector, 0, MEM_RELEASE);
}
CloseHandle (hCD);
CloseHandle (hFile);
}
}

181
waterbox/uzem/uzem.cpp Normal file
View File

@ -0,0 +1,181 @@
/*
(The MIT License)
Copyright (c) 2008-2016 by
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "uzem.h"
#include "avr8.h"
#include "uzerom.h"
#include "blip_buf.h"
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "../emulibc/emulibc.h"
#include "../emulibc/waterboxcore.h"
#define EXPORT extern "C" ECL_EXPORT
// header for use with UzeRom files
static RomHeader uzeRomHeader;
static avr8 uzebox;
static blip_t* blip;
void avr8::shutdown(int errcode)
{
printf("Oh no, that's bad!\n");
}
int main(void)
{
return 0;
}
EXPORT bool MouseEnabled()
{
return uzeRomHeader.mouse;
}
EXPORT bool Init()
{
const char *heximage = "romfile";
unsigned char *buffer = (unsigned char *)(uzebox.progmem);
if (isUzeromFile(heximage))
{
printf("-- Loading UzeROM Image --\n");
if (!loadUzeImage(heximage, &uzeRomHeader, buffer))
{
printf("Error: cannot load UzeRom file '%s'.\n\n", heximage);
return false;
}
// enable mouse support if required
if (uzeRomHeader.mouse)
{
printf("Mouse support enabled\n");
}
}
else
{
printf("Error: Doesn't seem to be an UzeROM image\n");
return false;
/*printf("Loading Hex Image...\n");
if (!loadHex(heximage, buffer))
{
printf("Error: cannot load HEX image '%s'.\n\n", heximage);
return false;
}*/
}
uzebox.decodeFlash();
if (!uzebox.init_gui())
return false;
uzebox.randomSeed = time(NULL);
srand(uzebox.randomSeed); //used for the watchdog timer entropy
blip = blip_new(2048);
blip_set_rates(blip, 28618182, 44100);
return true;
}
EXPORT void GetMemoryAreas(MemoryArea *m)
{
m[0].Data = uzebox.sram;
m[0].Name = "SRAM";
m[0].Size = sramSize;
m[0].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY;
m[1].Data = uzebox.eeprom;
m[1].Name = "EEPROM";
m[1].Size = eepromSize;
m[1].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE;
m[2].Data = uzebox.progmem;
m[2].Name = "ROM";
m[2].Size = progSize;
m[2].Flags = MEMORYAREA_FLAGS_WORDSIZE2;
}
struct MyFrameInfo : public FrameInfo
{
uint32_t Buttons[3];
};
static int cycles;
static int audio_value;
void SampleCallback(uint8_t val)
{
int v = (val - 128) * 100;
int delta = v - audio_value;
if (delta)
blip_add_delta(blip, cycles, delta);
audio_value = v;
}
EXPORT void FrameAdvance(MyFrameInfo* f)
{
cycles = 0;
uzebox.video_buffer = f->VideoBuffer;
uzebox.lagged = true;
uzebox.buttons[0] = ~f->Buttons[0];
uzebox.buttons[1] = ~f->Buttons[1];
if (f->Buttons[2] & 1) // power pressed
{
uzebox.PIND = uzebox.PIND & ~0b00001100;
}
else
{
uzebox.PIND |= 0b00001100;
}
while (uzebox.scanline_count == -999 && cycles < 700000)
{
cycles += uzebox.exec();
}
while (uzebox.scanline_count != -999 && cycles < 700000)
{
cycles += uzebox.exec();
}
uzebox.video_buffer = nullptr;
f->Cycles = cycles;
f->Width = VIDEO_DISP_WIDTH;
f->Height = 224;
blip_end_frame(blip, cycles);
f->Samples = blip_read_samples(blip, f->SoundBuffer, 2048, true);
for (int i = 0; i < f->Samples; i++)
f->SoundBuffer[i * 2 + 1] = f->SoundBuffer[i * 2];
f->Lagged = uzebox.lagged;
}
void (*InputCallback)();
EXPORT void SetInputCallback(void (*callback)())
{
InputCallback = callback;
}

31
waterbox/uzem/uzem.h Normal file
View File

@ -0,0 +1,31 @@
/*
(The MIT License)
Copyright (c) 2008-2016 by
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef UZEM_H
#define UZEM_H
#define VERSION "v2.0"
#endif

195
waterbox/uzem/uzerom.cpp Normal file
View File

@ -0,0 +1,195 @@
/*
(The MIT License)
Copyright (c) 2008-2016 by
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "uzerom.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
#define MAGIC_SIZE 6
const unsigned char magic[7] = "UZEBOX";
bool isUzeromFile(const char *in_filename)
{
unsigned char test[MAGIC_SIZE];
FILE *f = fopen(in_filename, "rb");
if (f)
{
if (fread(test, 1, MAGIC_SIZE, f) != MAGIC_SIZE)
{
printf("Error: failed to read the file %s.\n", in_filename);
return false;
}
for (int i = 0; i < MAGIC_SIZE; i++)
{
if (test[i] != magic[i])
return false;
}
fclose(f);
return true;
}
return false;
}
bool loadUzeImage(const char *in_filename, RomHeader *header, u8 *buffer)
{
FILE *f = fopen(in_filename, "rb");
size_t ret;
if (f)
{
ret = fread(header, 1, 512, f);
if (ret != 512)
{
printf("Error: failed to read the file %s.\n", in_filename);
return false;
}
if (header->version != HEADER_VERSION)
{
printf("Error: cannot parse version %d UzeROM files.\n", header->version);
}
printf("%s\n", header->name);
printf("%s\n", header->author);
printf("%d\n", header->year);
if (header->target == 0)
{
printf("Uzebox 1.0 - ATmega644\n");
}
else if (header->target == 1)
{
printf("Uzebox 2.0 - XTmega128\n");
printf("Error: Uzebox 2.0 ROM images are not supported.\n");
return false;
}
printf("\n");
if (fread(buffer, 1, header->progSize, f) != header->progSize)
{
printf("Erro: failed to read the file %s.\n", in_filename);
return false;
}
fclose(f);
return true;
}
return false;
}
static inline int parse_hex_nibble(char s)
{
if (s >= '0' && s <= '9')
return s - '0';
else if (s >= 'A' && s <= 'F')
return s - 'A' + 10;
else if (s >= 'a' && s <= 'a')
return s - 'a' + 10;
else
return -1;
}
static int parse_hex_byte(const char *s)
{
return (parse_hex_nibble(s[0]) << 4) | parse_hex_nibble(s[1]);
}
static int parse_hex_word(const char *s)
{
return (parse_hex_nibble(s[0]) << 12) | (parse_hex_nibble(s[1]) << 8) |
(parse_hex_nibble(s[2]) << 4) | parse_hex_nibble(s[3]);
}
bool loadHex(const char *in_filename, unsigned char *buffer, unsigned int *bytesRead)
{
(void)bytesRead;
//http://en.wikipedia.org/wiki/.hex
//(I've added the spaces for clarity, they don't exist in the real files)
//:10 65B0 00 661F771F881F991F1A9469F760957095 59
//:10 65C0 00 809590959B01AC01BD01CF010895F894 91
//:02 65D0 00 FFCF FB
//:02 65D2 00 0100 C6
//:00 0000 01 FF [EOF marker]
//First field is the byte count. Second field is the 16-bit address. Third field is the record type;
//00 is data, 01 is EOF. For record type zero, next "wide" field is the actual data, followed by a
//checksum.
u16 progmemLast = 0;
char line[128];
int lineNumber = 1;
FILE *in_file = fopen(in_filename, "rb");
if (!in_file)
return false;
while (fgets(line, sizeof(line), in_file) && line[0]==':')
{
int bytes = parse_hex_byte(line + 1);
int addr = parse_hex_word(line + 3);
int recordType = parse_hex_byte(line + 7);
if (recordType == 0)
{
char *lp = line + 9;
while (bytes > 0)
{
unsigned char value = parse_hex_byte(lp);
buffer[addr] = value;
addr++;
if (addr > progmemLast)
{
progmemLast = addr;
}
lp += 2;
bytes -= 1;
}
}
else if (recordType == 1)
{
break;
}
else
fprintf(stderr, "ignoring unknown record type %d in line %d of %s\n", recordType, lineNumber, in_filename);
++lineNumber;
}
/*
if(bytesRead != 0){
*bytesRead=progmemLast;
}
*/
fclose(in_file);
return true;
}

74
waterbox/uzem/uzerom.h Normal file
View File

@ -0,0 +1,74 @@
/*
(The MIT License)
Copyright (c) 2008-2016 by
David Etherton, Eric Anderton, Alec Bourque (Uze), Filipe Rinaldi,
Sandor Zsuga (Jubatian), Matt Pandina (Artcfox)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdint.h>
#ifndef UZEROM_H
#define HEADER_VERSION 1
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define MAX_PROG_SIZE 61440 //65536-4096
#define HEADER_SIZE 512
#pragma pack( 1 )
struct RomHeader{
//Header fields (512 bytes)
uint8_t marker[6]; //'UZEBOX'
uint8_t version; //header version
uint8_t target; //AVR target (ATmega644=0, ATmega1284=1)
uint32_t progSize; //program memory size in bytes
uint16_t year;
uint8_t name[32];
uint8_t author[32];
uint8_t icon[16*16];
uint32_t crc32;
uint8_t mouse;
uint8_t description[64];
uint8_t reserved[114];
};
#pragma pack()
/*
isUzeromFile - returns true if the file is indeed an .uze file
*/
bool isUzeromFile(const char* in_filename);
/*
readUzeImage - reads an .uze file into the header and buffer structures provided.
*/
bool loadUzeImage(const char* in_filename,RomHeader *header,unsigned char *buffer);
/*
load_hex - loads a hex image into the buffer provided, and provides the number of bytes read.
*/
bool loadHex(const char *in_filename,unsigned char *buffer,unsigned int *bytesRead = 0);
#endif