Skip to content

Commit

Permalink
Merge branch 'libretro:master' into naive-disk-control
Browse files Browse the repository at this point in the history
  • Loading branch information
dszakallas authored Sep 8, 2024
2 parents ca9473d + 5121aa6 commit 383e5b4
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 79 deletions.
95 changes: 95 additions & 0 deletions libopera/discdata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "extern_c.h"

#include <stdint.h>

EXTERN_C_BEGIN

/*
Define the position of the primary label on each Opera disc, the
block offset between avatars, and the index of the last avatar
(i.e. the avatar count minus one). The latter figure *must* match
the ROOT_HIGHEST_AVATAR figure from "filesystem.h", as the same
File structure is use to read the label at boot time, and to provide
access to the root directory.
*/

#define DISC_LABEL_RECORD_TYPE 1
#define DISC_BLOCK_SIZE 2048
#define DISC_LABEL_OFFSET 225
#define DISC_LABEL_AVATAR_DELTA 32786
#define DISC_LABEL_HIGHEST_AVATAR 7
#define DISC_TOTAL_BLOCKS 330000

#define ROOT_HIGHEST_AVATAR 7
#define FILESYSTEM_MAX_NAME_LEN 32

#define VOLUME_STRUCTURE_OPERA_READONLY 1
#define VOLUME_STRUCTURE_LINKED_MEM 2

#define NVRAM_VOLUME_UNIQUE_ID -1
#define NVRAM_ROOT_UNIQUE_ID -2
#define VOLUME_SYNC_BYTE 'Z'
#define VOLUME_SYNC_BYTE_LEN 5
#define VOLUME_COM_LEN 32
#define VOLUME_ID_LEN 32

/*
// This disc won't necessarily cause a reboot when inserted. This flag is
// advisory ONLY. Only by checking with cdromdipir can you be really sure.
// Place in dl_VolumeFlags. Note: the first volume gets this flag also.
*/
#define VOLUME_FLAGS_DATADISC 0x01

/*
Data structures written on CD disc (Compact Disc disc?)
*/
typedef struct DiscLabel DiscLabel;
struct DiscLabel
{
uint8_t dl_RecordType; /* Should contain 1 */
uint8_t dl_VolumeSyncBytes[VOLUME_SYNC_BYTE_LEN]; /* Synchronization byte */
uint8_t dl_VolumeStructureVersion; /* Should contain 1 */
uint8_t dl_VolumeFlags; /* Should contain 0 */
uint8_t dl_VolumeCommentary[VOLUME_COM_LEN]; /* Random comments about volume */
uint8_t dl_VolumeIdentifier[VOLUME_ID_LEN]; /* Should contain disc name */
uint32_t dl_VolumeUniqueIdentifier; /* Roll a billion-sided die */
uint32_t dl_VolumeBlockSize; /* Usually contains 2048 */
uint32_t dl_VolumeBlockCount; /* # of blocks on disc */
uint32_t dl_RootUniqueIdentifier; /* Roll a billion-sided die */
uint32_t dl_RootDirectoryBlockCount; /* # of blocks in root */
uint32_t dl_RootDirectoryBlockSize; /* usually same as vol blk size */
uint32_t dl_RootDirectoryLastAvatarIndex; /* should contain 7 */
uint32_t dl_RootDirectoryAvatarList[ROOT_HIGHEST_AVATAR+1];
};

typedef struct DirectoryHeader DirectoryHeader;
struct DirectoryHeader
{
int32_t dh_NextBlock;
int32_t dh_PrevBlock;
uint32_t dh_Flags;
uint32_t dh_FirstFreeByte;
uint32_t dh_FirstEntryOffset;
};

#define DIRECTORYRECORD(AVATARCOUNT) \
uint32_t dir_Flags; \
uint32_t dir_UniqueIdentifier; \
uint32_t dir_Type; \
uint32_t dir_BlockSize; \
uint32_t dir_ByteCount; \
uint32_t dir_BlockCount; \
uint32_t dir_Burst; \
uint32_t dir_Gap; \
char dir_FileName[FILESYSTEM_MAX_NAME_LEN]; \
uint32_t dir_LastAvatarIndex; \
uint32_t dir_AvatarList[AVATARCOUNT];

typedef struct DirectoryRecord {
DIRECTORYRECORD(1)
} DirectoryRecord;

#define DIRECTORY_LAST_IN_DIR 0x80000000
#define DIRECTORY_LAST_IN_BLOCK 0x40000000

EXTERN_C_END
5 changes: 5 additions & 0 deletions libopera/endianness.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,14 @@
#if IS_BIG_ENDIAN

#define swap32_if_little_endian(X) (X)
#define swap32_if_le(X) (X)
#define swap32_array_if_little_endian(X,Y)
#define swap32_array_if_le(X,Y)

#else

#define swap32_if_little_endian(X) (SWAP32(X))
#define swap32_if_le(X) (SWAP32(X))

static
INLINE
Expand All @@ -93,6 +96,8 @@ swap32_array_if_little_endian(uint32_t *array_,
array_[i] = SWAP32(array_[i]);
}

#define swap32_array_if_le(X,Y) swap32_array_if_little_endian(X,Y)

#endif /* IS_BIG_ENDIAN */

#endif /* LIBOPERA_ENDIANNESS_H_INCLUDED */
27 changes: 27 additions & 0 deletions libopera/linkedmemblock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <stdint.h>

/*
LinkedMemDisk defines a high-level "disk" which consists of a
doubly-linked list of storage blocks in memory (RAM, ROM, NVRAM,
or out on a gamesaver cartridge. LinkedMemDisks have a standard
Opera label at offset 0, with a type code of 2. The linked list
normally begins immediately after the label; its offset is given
by the zero'th avatar of the root directory. LinkedMemDisks are,
by definition, flat file systems and cannot contain directories.
*/

#define FINGERPRINT_FILEBLOCK 0xBE4F32A6
#define FINGERPRINT_FREEBLOCK 0x7AA565BD
#define FINGERPRINT_ANCHORBLOCK 0x855A02B6

typedef struct LinkedMemBlock LinkedMemBlock;
struct LinkedMemBlock
{
uint32_t fingerprint;
uint32_t flinkoffset;
uint32_t blinkoffset;
uint32_t blockcount;
uint32_t headerblockcount;
};
31 changes: 16 additions & 15 deletions libopera/opera_clio.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static
void
opera_clio_set_rom()
{
opera_mem_rom_select((CLIO.regs[0x84] & 0x4) ? ROM2 : ROM1);
opera_mem_rom_select((CLIO.regs[0x84] & ADBIO_OTHERROM) ? ROM2 : ROM1);
}

uint32_t
Expand Down Expand Up @@ -253,17 +253,18 @@ clio_handle_dma(uint32_t val_)

static
void
if_set_set_reset(uint32_t *output_,
uint32_t val_,
uint32_t mask_chk_,
uint32_t mask_set_)
adbio_set(uint32_t *output_,
uint32_t val_,
uint32_t bit_)
{
if((val_ & mask_chk_) == mask_chk_)
{
*output_ = ((val_ & mask_set_) ?
(*output_ | mask_set_) :
(*output_ & ~mask_set_));
}
uint32_t mask;

mask = (1 << bit_);

if((val_ & mask) == 0)
*output_ &= ~mask;
else if(val_ & (mask | (mask << 4)))
*output_ |= mask;
}

int
Expand Down Expand Up @@ -360,10 +361,10 @@ opera_clio_poke(uint32_t addr_,
}
else if(addr_ == 0x84)
{
if_set_set_reset(&CLIO.regs[0x84],val_,0x10,0x01);
if_set_set_reset(&CLIO.regs[0x84],val_,0x20,0x02);
if_set_set_reset(&CLIO.regs[0x84],val_,0x40,0x04);
if_set_set_reset(&CLIO.regs[0x84],val_,0x80,0x08);
adbio_set(&CLIO.regs[0x84],val_,0);
adbio_set(&CLIO.regs[0x84],val_,1);
adbio_set(&CLIO.regs[0x84],val_,2);
adbio_set(&CLIO.regs[0x84],val_,3);

opera_clio_set_rom();

Expand Down
3 changes: 3 additions & 0 deletions libopera/opera_clio.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@

#include <stdint.h>

#define ADBIO_OTHERROM 0x04
#define ADBIO_OTHERROM_EN (ADBIO_OTHERROM << 4)

EXTERN_C_BEGIN

void opera_clio_init(int reason_);
Expand Down
2 changes: 1 addition & 1 deletion libopera/opera_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ opera_mem_rom2_byteswap32_if_le()
void
opera_mem_rom_select(void *rom_)
{
if((rom_ != ROM1) || (rom_ != ROM2))
if((rom_ != ROM1) && (rom_ != ROM2))
rom_ = ROM1;

ROM = rom_;
Expand Down
126 changes: 64 additions & 62 deletions libopera/opera_nvram.c
Original file line number Diff line number Diff line change
@@ -1,79 +1,81 @@
#include "discdata.h"
#include "linkedmemblock.h"

#include "opera_mem.h"

#include "endianness.h"

#include "boolean.h"

#include <stdint.h>
#include <string.h>

#pragma pack(push,1)
#define NVRAM_BLOCKSIZE 1
#define NVRAM_BLOCKCOUNT (32 * 1024)

typedef struct nvram_header_t nvram_header_t;
struct nvram_header_t
bool
opera_nvram_initialized(void *buf_,
const int bufsize_)
{
uint8_t record_type;
uint8_t sync_bytes[5];
uint8_t record_version;
uint8_t flags;
uint8_t comment[32];
uint8_t label[32];
uint32_t id;
uint32_t block_size;
uint32_t block_count;
uint32_t root_dir_id;
uint32_t root_dir_blocks;
uint32_t root_dir_block_size;
uint32_t last_root_dir_copy;
uint32_t root_dir_copies[8];
int i;
DiscLabel *dl;

uint32_t unknown_value0;
uint32_t unknown_value1;
uint32_t unknown_value2;
uint32_t unknown_value3;
uint32_t unknown_value4;
uint32_t unknown_value5;
uint32_t unknown_value6;
uint32_t unknown_value7;
uint32_t blocks_remaining;
uint32_t unknown_value8;
};
dl = (DiscLabel*)buf_;

#pragma pack(pop)
if(dl->dl_RecordType != DISC_LABEL_RECORD_TYPE)
return false;
if(dl->dl_VolumeStructureVersion != VOLUME_STRUCTURE_LINKED_MEM)
return false;
for(i = 0; i < VOLUME_SYNC_BYTE_LEN; i++)
{
if(dl->dl_VolumeSyncBytes[i] != VOLUME_SYNC_BYTE)
return false;
}

return true;
}

// The below code mimics the official 3DO formatting tool "format"
// https://github.com/trapexit/portfolio_os/blob/master/src/filesystem/format.c
// https://github.com/trapexit/portfolio_os/blob/master/src/filesystem/lmadm.c
void
opera_nvram_init(void)
opera_nvram_init(void *buf_,
const int bufsize_)
{
nvram_header_t *nvram_hdr = (nvram_header_t*)NVRAM;
DiscLabel *disc_label;
LinkedMemBlock *anchor_block;
LinkedMemBlock *free_block;

disc_label = (DiscLabel*)buf_;
anchor_block = (LinkedMemBlock*)&disc_label[1];
free_block = &anchor_block[1];

memset(buf_,0,bufsize_);

disc_label->dl_RecordType = DISC_LABEL_RECORD_TYPE;
memset(disc_label->dl_VolumeSyncBytes,VOLUME_SYNC_BYTE,VOLUME_SYNC_BYTE_LEN);
disc_label->dl_VolumeStructureVersion = VOLUME_STRUCTURE_LINKED_MEM;
disc_label->dl_VolumeFlags = 0;
strncpy((char*)disc_label->dl_VolumeCommentary,"opera formatted", VOLUME_COM_LEN);
strncpy((char*)disc_label->dl_VolumeIdentifier,"nvram", VOLUME_ID_LEN);
disc_label->dl_VolumeUniqueIdentifier = swap32_if_le(NVRAM_VOLUME_UNIQUE_ID); // ???
disc_label->dl_VolumeBlockSize = swap32_if_le(NVRAM_BLOCKSIZE);
disc_label->dl_VolumeBlockCount = swap32_if_le(bufsize_);
disc_label->dl_RootUniqueIdentifier = swap32_if_le(NVRAM_ROOT_UNIQUE_ID);
disc_label->dl_RootDirectoryBlockCount = 0;
disc_label->dl_RootDirectoryBlockSize = swap32_if_le(NVRAM_BLOCKSIZE);
disc_label->dl_RootDirectoryLastAvatarIndex = 0;
disc_label->dl_RootDirectoryAvatarList[0] = swap32_if_le(sizeof(DiscLabel));

memset(nvram_hdr,0,sizeof(nvram_header_t));
anchor_block->fingerprint = swap32_if_le(FINGERPRINT_ANCHORBLOCK);
anchor_block->flinkoffset = swap32_if_le(sizeof(DiscLabel) + sizeof(LinkedMemBlock));
anchor_block->blinkoffset = swap32_if_le(sizeof(DiscLabel) + sizeof(LinkedMemBlock));
anchor_block->blockcount = swap32_if_le(sizeof(LinkedMemBlock));
anchor_block->headerblockcount = swap32_if_le(sizeof(LinkedMemBlock));

nvram_hdr->record_type = 0x01;
nvram_hdr->sync_bytes[0] = 'Z';
nvram_hdr->sync_bytes[1] = 'Z';
nvram_hdr->sync_bytes[2] = 'Z';
nvram_hdr->sync_bytes[3] = 'Z';
nvram_hdr->sync_bytes[4] = 'Z';
nvram_hdr->record_version = 0x02;
nvram_hdr->label[0] = 'N';
nvram_hdr->label[1] = 'V';
nvram_hdr->label[2] = 'R';
nvram_hdr->label[3] = 'A';
nvram_hdr->label[4] = 'M';
nvram_hdr->id = swap32_if_little_endian(0xFFFFFFFF);
nvram_hdr->block_size = swap32_if_little_endian(0x00000001);
nvram_hdr->block_count = swap32_if_little_endian(0x00008000);
nvram_hdr->root_dir_id = swap32_if_little_endian(0xFFFFFFFE);
nvram_hdr->root_dir_blocks = swap32_if_little_endian(0x00000000);
nvram_hdr->root_dir_block_size = swap32_if_little_endian(0x00000001);
nvram_hdr->last_root_dir_copy = swap32_if_little_endian(0x00000000);
nvram_hdr->root_dir_copies[0] = swap32_if_little_endian(0x00000084);
nvram_hdr->unknown_value0 = swap32_if_little_endian(0x855A02B6);
nvram_hdr->unknown_value1 = swap32_if_little_endian(0x00000098);
nvram_hdr->unknown_value2 = swap32_if_little_endian(0x00000098);
nvram_hdr->unknown_value3 = swap32_if_little_endian(0x00000014);
nvram_hdr->unknown_value4 = swap32_if_little_endian(0x00000014);
nvram_hdr->unknown_value5 = swap32_if_little_endian(0x7AA565BD);
nvram_hdr->unknown_value6 = swap32_if_little_endian(0x00000084);
nvram_hdr->unknown_value7 = swap32_if_little_endian(0x00000084);
nvram_hdr->blocks_remaining = swap32_if_little_endian(0x00007F68);
nvram_hdr->unknown_value8 = swap32_if_little_endian(0x00000014);
free_block->fingerprint = swap32_if_le(FINGERPRINT_FREEBLOCK);
free_block->flinkoffset = swap32_if_le(sizeof(DiscLabel));
free_block->blinkoffset = swap32_if_le(sizeof(DiscLabel));
free_block->blockcount = swap32_if_le(bufsize_ - sizeof(DiscLabel) - sizeof(LinkedMemBlock));
free_block->headerblockcount = swap32_if_le(sizeof(LinkedMemBlock));
}
5 changes: 4 additions & 1 deletion libopera/opera_nvram.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef OPERA_NVRAM_H_INCLUDED
#define OPERA_NVRAM_H_INCLUDED

void opera_nvram_init(void);
#include "boolean.h"

bool opera_nvram_initialized(void *buf, const int bufsize);
void opera_nvram_init(void *buf, const int bufsize);

#endif
5 changes: 5 additions & 0 deletions opera_lr_nvram.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ opera_lr_nvram_save(const char *gamepath_,
}
}

// Try to load. If it fails ensure the NVRAM is initialized.
// Not all games will force a format if the NVRAM is corrupt.
void
opera_lr_nvram_load(const char *gamepath_,
const bool shared_,
Expand All @@ -400,4 +402,7 @@ opera_lr_nvram_load(const char *gamepath_,

opera_lr_nvram_load_pergame(NVRAM,NVRAM_SIZE,filename,version_);
}

if(!opera_nvram_initialized(NVRAM,NVRAM_SIZE))
opera_nvram_init(NVRAM,NVRAM_SIZE);
}

0 comments on commit 383e5b4

Please sign in to comment.