Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions SabreTools.Data.Models/PCEngineCDROM/BootSector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace SabreTools.Data.Models.PCEngineCDROM
{
/// <summary>
/// Standard format for the first sector of the CD-ROM header
/// This is likely read by the system to verify the disc's authenticity
/// </summary>
public sealed class BootSector
{
/// <summary>
/// Copyright notice and credits
/// </summary>
/// <remarks>Shift-JIS format, lines separated by NULL character, ends in NULL</remarks>
public byte[] CopyrightString { get; set; } = new byte[806];

/// <summary>
/// HuC6280 machine code, presumably for initialization
/// Note that the actual Boot ROM is on the System Card
/// </summary>
public byte[] BootROM { get; set; } = new byte[432];

/// <summary>
/// Reserved zeroed padding bytes to fill remainder of sector
/// </summary>
public byte[] Padding { get; set; } = new byte[810];
}
}
23 changes: 23 additions & 0 deletions SabreTools.Data.Models/PCEngineCDROM/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace SabreTools.Data.Models.PCEngineCDROM
{
/// <summary>
/// PC Engine CDROM constant values and arrays
/// </summary>
public static class Constants
{
/// <summary>
/// Standard block size for PC Engine CDROM disc images
/// </summary>
public static readonly int SectorSize = 2048;

/// <summary>
/// Start of a PC Engine CDROM Header
/// </summary>
public static readonly byte[] MagicBytes = [0x82, 0xB1, 0x82, 0xCC, 0x83, 0x76, 0x83, 0x8D, 0x83, 0x4F, 0x83, 0x89, 0x83, 0x80, 0x82, 0xCC];

/// <summary>
/// Start of an empty CD-ROM pregap sector
/// </summary>
public static readonly byte[] PregapBytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
}
}
49 changes: 49 additions & 0 deletions SabreTools.Data.Models/PCEngineCDROM/Enums.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;

namespace SabreTools.Data.Models.PCEngineCDROM
{
/// <summary>
/// Opening Mode flags
/// </summary>
[Flags]
public enum OpenMode : byte
{
/// <summary>
/// "Data Read to VRAM"
/// Bit set if data is to be read to VRAM
/// </summary>
READ_TO_VRAM = 0x01,

/// <summary>
/// "Data Read to ADPCM Buffer"
/// Bit set if data is to be read to the ADPCM buffer
/// </summary>
READ_TO_ADPCM = 0x02,

/// <summary>
/// "BG Display"
/// Bit set if background display is off
/// Unset if it should be on
/// </summary>
DISPLAY_OFF = 0x20,

/// <summary>
/// "ADPCM Play"
/// Bit set if ADPCM should not play
/// Unset if it should play
/// </summary>
ADCPM_DISABLED = 0x40,

/// <summary>
/// "ADPCM Play Mode"
/// Bit set if ADPCM should play on repeat
/// Unset if it should play only once
/// </summary>
ADPCM_REPEAT = 0x80,

/// <summary>
/// Mask for bits that are reserved
/// </summary>
RESERVED_MASK = 0x1C,
}
}
19 changes: 19 additions & 0 deletions SabreTools.Data.Models/PCEngineCDROM/Header.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace SabreTools.Data.Models.PCEngineCDROM
{
/// <summary>
/// This is the standard header of PC Engine CD-ROM
/// Located at the first non-zero user data sector of the first data track
/// </summary>
public sealed class Header
{
/// <summary>
/// Standard sector of data to verify the disc
/// </summary>
public BootSector BootSector { get; set; } = new();

/// <summary>
/// Initial Program Loader for the PC Engine
/// </summary>
public IPL IPL { get; set; } = new();
}
}
133 changes: 133 additions & 0 deletions SabreTools.Data.Models/PCEngineCDROM/IPL.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using SabreTools.Numerics;

namespace SabreTools.Data.Models.PCEngineCDROM
{
/// <summary>
/// IPL (Initial Program Loader) Block Data Format
/// Format information from the Hu7 CD System BIOS Manual "CD-ROM BIOS Ver1.00"
/// </summary>
public sealed class IPL
{
/// <summary>
/// "Load Start Record Number of CD"
/// "Top record no. where the program is contained"
/// The offset (entry point) of the initial start up program machine code
/// </summary>
/// <remarks>Big-Endian</remarks>
public UInt24 IPLBLK { get; set; } = new();

/// <summary>
/// "Load Block Length of CD"
/// "No. of records for program to read"
/// Number of sectors to read for the start up program, from the entry point
/// </summary>
public byte IPLBLN { get; set; }

/// <summary>
/// "Program Load Address"
/// "Main memory address for program read"
/// Address for where the program code should be placed into memory
/// </summary>
/// <remarks>Little-Endian</remarks>
public ushort IPLSTA { get; set; }

/// <summary>
/// "Program Execute Address"
/// "Starting address of execution after program read"
/// Address for where the program code should be executed from memory, after reading
/// </summary>
/// <remarks>Little-Endian</remarks>
public ushort IPLJMP { get; set; }

/// <summary>
/// "IPL Set MPR2-6 (+ max_mapping)"
/// "Bank no. to set to MPR before program read"
/// "When calling BIOS or using interrupt routine from BIOS, MPR0,1,7 cannot be changed"
/// Memory Page Register
/// MPR0 (I/O, $0000 to $1FFF)
/// MPR1 (WORK RAM, $2000 to $3FFF)
/// MPR2-6 (USER AREA, $4000 to $5FFF, ..., $C000 to $DFFF)
/// MPR7 (BIOS ROM, $E000 to $FFFF)
/// </summary>
public byte[] IPLMPR { get; set; } = new byte[5];

/// <summary>
/// "Opening mode"
/// </summary>
public OpenMode OpenMode { get; set; }

/// <summary>
/// "Opening Graphic Data Record Number"
/// "Specifies the top record of data to load"
/// </summary>
/// <remarks>Big-Endian</remarks>
public UInt24 GRPBLK { get; set; } = new();

/// <summary>
/// "Opening Graphic Data Length"
/// "Specifies the total record that contains color palette data, BAT data, and BG font data"
/// </summary>
public byte GRPBLN { get; set; }

/// <summary>
/// "Opening Graphic Data Read Address"
/// "Specifies the top VRAM address into which BG font data is read"
/// </summary>
/// <remarks>Little-Endian</remarks>
public ushort GRPADR { get; set; }

/// <summary>
/// "Opening ADPCM Data Record Number"
/// "Specifies the top record of data to load"
/// </summary>
/// <remarks>Big-Endian</remarks>
public UInt24 ADPBLK { get; set; } = new();

/// <summary>
/// "Opening ADPCM Data Length"
/// "Specifies the number of ADPCM data record"
/// </summary>
public byte ADPBLN { get; set; }

/// <summary>
/// "Opening ADPCM Sampling Rate"
/// "Specifies the ADPCM sampling rate"
/// </summary>
public byte ADPRATE { get; set; }

/// <summary>
/// Reserved bytes, zeroed
/// </summary>
/// <remarks>7 bytes</remarks>
public byte[] Reserved { get; set; } = new byte[7];

/// <summary>
/// "ID String"
/// Null-terminated ASCII string
/// "PC Engine CD-ROM SYSTEM\0"
/// </summary>
/// <remarks>24 bytes, NULL terminated</remarks>
public byte[] SystemString { get; set; } = new byte[24];

/// <summary>
/// Null-terminated ASCII string
/// "Copyright HUDSON SOFT / NEC Home Electronics,Ltd.\0"
/// </summary>
/// <remarks>50 bytes, NULL terminated</remarks>
public byte[] CopyrightString { get; set; } = new byte[50];

/// <summary>
/// "Program Name"
/// ASCII string, not null-terminated
/// </summary>
/// <remarks>16 bytes, padding with trailing SPACE \x20</remarks>
public byte[] ProgramName { get; set; } = new byte[16];

/// <summary>
/// Additional optional string
/// ASCII string, not null-terminated
/// </summary>
/// <remarks>6 bytes, padding with trailing SPACE \x20</remarks>
public byte[] AdditionalString { get; set; } = new byte[16];
}
}
72 changes: 72 additions & 0 deletions SabreTools.Serialization.Readers.Test/PCEngineCDROMTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.IO;
using System.Linq;
using Xunit;

namespace SabreTools.Serialization.Readers.Test
{
public class PCEngineCDROMTests
{
[Fact]
public void NullArray_Null()
{
byte[]? data = null;
int offset = 0;
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}

[Fact]
public void EmptyArray_Null()
{
byte[]? data = [];
int offset = 0;
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}

[Fact]
public void InvalidArray_Null()
{
byte[]? data = [.. Enumerable.Repeat<byte>(0xFF, 1024)];
int offset = 0;
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data, offset);
Assert.Null(actual);
}

[Fact]
public void NullStream_Null()
{
Stream? data = null;
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}

[Fact]
public void EmptyStream_Null()
{
Stream? data = new MemoryStream([]);
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}

[Fact]
public void InvalidStream_Null()
{
Stream? data = new MemoryStream([.. Enumerable.Repeat<byte>(0xFF, 1024)]);
var deserializer = new PCEngineCDROM();

var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
}
}
Loading