summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/formats/acorn_dsk.cpp96
-rw-r--r--src/lib/formats/acorn_dsk.h16
-rw-r--r--src/lib/formats/dsk_dsk.cpp5
-rw-r--r--src/lib/formats/hxcmfm_dsk.cpp30
-rw-r--r--src/lib/formats/jvc_dsk.cpp18
-rw-r--r--src/lib/formats/pc_dsk.cpp4
-rw-r--r--src/lib/util/disasmintf.cpp47
-rw-r--r--src/lib/util/disasmintf.h69
-rw-r--r--src/lib/util/timeconv.h83
9 files changed, 261 insertions, 107 deletions
diff --git a/src/lib/formats/acorn_dsk.cpp b/src/lib/formats/acorn_dsk.cpp
index 486cf20be54..55629e2c3c8 100644
--- a/src/lib/formats/acorn_dsk.cpp
+++ b/src/lib/formats/acorn_dsk.cpp
@@ -33,18 +33,23 @@ int acorn_ssd_format::find_size(io_generic *io, uint32_t form_factor)
{
uint8_t cat[8];
uint32_t sectors0, sectors2;
-
- // read sector count from side 0 catalogue
- io_generic_read(io, cat, 0x100, 8);
- sectors0 = ((cat[6] & 3) << 8) + cat[7];
- LOG_FORMATS("ssd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : "");
-
uint64_t size = io_generic_size(io);
+
for(int i=0; formats[i].form_factor; i++) {
const format &f = formats[i];
if(form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor)
continue;
+ // test for Torch CPN - test pattern at sector &0018
+ io_generic_read(io, cat, 0x32800, 8);
+ if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count)
+ return i;
+
+ // read sector count from side 0 catalogue
+ io_generic_read(io, cat, 0x100, 8);
+ sectors0 = ((cat[6] & 3) << 8) + cat[7];
+ LOG_FORMATS("ssd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : "");
+
if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) {
if (f.head_count == 2)
{
@@ -63,7 +68,7 @@ int acorn_ssd_format::find_size(io_generic *io, uint32_t form_factor)
sectors2 = sectors0;
}
- if (sectors0 > 0 && sectors0 % 10 == 0 && sectors2 > 0 && sectors2 % 10 == 0)
+ if (sectors0 > 0 && sectors0 % 10 == 0 && sectors2 > 0 && sectors2 % 10 == 0 && size <= (sectors0 + sectors2) * 256)
return i;
}
}
@@ -133,18 +138,23 @@ int acorn_dsd_format::find_size(io_generic *io, uint32_t form_factor)
{
uint8_t cat[8];
uint32_t sectors0, sectors2;
-
- // read sector count from side 0 catalogue
- io_generic_read(io, cat, 0x100, 8);
- sectors0 = ((cat[6] & 3) << 8) + cat[7];
- LOG_FORMATS("dsd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : "");
-
uint64_t size = io_generic_size(io);
+
for (int i = 0; formats[i].form_factor; i++) {
const format &f = formats[i];
if (form_factor != floppy_image::FF_UNKNOWN && form_factor != f.form_factor)
continue;
+ // test for Torch CPN - test pattern at sector &0018
+ io_generic_read(io, cat, 0x1200, 8);
+ if (memcmp(cat, "\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd", 4) == 0 && size == (uint64_t)compute_track_size(f) * f.track_count * f.head_count)
+ return i;
+
+ // read sector count from side 0 catalogue
+ io_generic_read(io, cat, 0x100, 8);
+ sectors0 = ((cat[6] & 3) << 8) + cat[7];
+ LOG_FORMATS("dsd: sector count 0: %d %s\n", sectors0, sectors0 % 10 != 0 ? "invalid" : "");
+
if ((size <= (uint64_t)compute_track_size(f) * f.track_count * f.head_count) && (sectors0 <= f.track_count * f.sector_count)) {
// read sector count from side 2 catalogue
io_generic_read(io, cat, 0xb00, 8); // interleaved
@@ -156,7 +166,7 @@ int acorn_dsd_format::find_size(io_generic *io, uint32_t form_factor)
LOG_FORMATS("dsd: sector count 2: %d %s\n", sectors2, sectors2 % 10 != 0 ? "invalid" : "");
- if (sectors0 > 0 && sectors0 % 10 == 0 && sectors2 > 0 && sectors2 % 10 == 0)
+ if (sectors0 > 0 && sectors0 % 10 == 0 && sectors2 > 0 && sectors2 % 10 == 0 && size <= (sectors0 + sectors2) * 256)
return i;
}
}
@@ -564,8 +574,9 @@ int opus_ddcpm_format::identify(io_generic *io, uint32_t form_factor)
io_generic_read(io, h, 0, 8);
- if (io_generic_size(io) == 811520 && memcmp(h, "Slogger ", 8) == 0)
+ if (io_generic_size(io) == 819200 && memcmp(h, "Slogger ", 8) == 0)
return 100;
+ LOG_FORMATS("ddcpm: no match\n");
return 0;
}
@@ -584,7 +595,6 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, floppy_image
// Sector interleave of 2
//
int spt, bps;
- uint64_t file_offset = 0;
for (int head = 0; head < 2; head++) {
for (int track = 0; track < 80; track++) {
@@ -594,7 +604,7 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, floppy_image
desc_pc_sector sects[10];
uint8_t sectdata[10*512];
- io_generic_read(io, sectdata, file_offset, spt * bps);
+ io_generic_read(io, sectdata, head * 80 * spt * 512 + track * spt * 512, spt * 512);
for (int i = 0; i < spt; i++) {
sects[i].track = track;
@@ -602,7 +612,7 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, floppy_image
sects[i].sector = i;
sects[i].size = mfm ? 2 : 1;
sects[i].actual_size = bps;
- sects[i].data = sectdata + bps * i;
+ sects[i].data = sectdata + i * 512;
sects[i].deleted = false;
sects[i].bad_crc = false;
}
@@ -611,8 +621,6 @@ bool opus_ddcpm_format::load(io_generic *io, uint32_t form_factor, floppy_image
build_wd_track_mfm(track, head, image, 100000, 10, sects, 60, 43, 22);
else
build_wd_track_fm(track, head, image, 50000, 10, sects, 40, 10, 10);
-
- file_offset += spt * bps;
}
}
@@ -625,53 +633,6 @@ bool opus_ddcpm_format::save(io_generic *io, floppy_image *image)
}
-torch_cpn_format::torch_cpn_format() : wd177x_format(formats)
-{
-}
-
-const char *torch_cpn_format::name() const
-{
- return "cpn";
-}
-
-const char *torch_cpn_format::description() const
-{
- return "Torch CPN disk image";
-}
-
-const char *torch_cpn_format::extensions() const
-{
- return "dsd";
-}
-
-int torch_cpn_format::identify(io_generic *io, uint32_t form_factor)
-{
- int type = find_size(io, form_factor);
-
- if (type != -1)
- return 50;
- LOG_FORMATS("cpn: no match\n");
- return 0;
-}
-
-int torch_cpn_format::get_image_offset(const format &f, int head, int track)
-{
- if (f.sector_base_id == -1)
- return (track * f.head_count + head) * compute_track_size(f);
- else
- return (f.track_count * head + track) * compute_track_size(f);
-}
-
-const torch_cpn_format::format torch_cpn_format::formats[] =
-{
- { // 400k 80 track double sided single density (interleaved) - gaps unverified
- floppy_image::FF_525, floppy_image::DSQD, floppy_image::FM,
- 4000, 10, 80, 2, 256, {}, -1, { 0,1,2,3,4,5,6,7,8,9 }, 40, 10, 10
- },
- {}
-};
-
-
const floppy_format_type FLOPPY_ACORN_SSD_FORMAT = &floppy_image_format_creator<acorn_ssd_format>;
const floppy_format_type FLOPPY_ACORN_DSD_FORMAT = &floppy_image_format_creator<acorn_dsd_format>;
const floppy_format_type FLOPPY_ACORN_DOS_FORMAT = &floppy_image_format_creator<acorn_dos_format>;
@@ -679,4 +640,3 @@ const floppy_format_type FLOPPY_ACORN_ADFS_OLD_FORMAT = &floppy_image_format_cre
const floppy_format_type FLOPPY_ACORN_ADFS_NEW_FORMAT = &floppy_image_format_creator<acorn_adfs_new_format>;
const floppy_format_type FLOPPY_OPUS_DDOS_FORMAT = &floppy_image_format_creator<opus_ddos_format>;
const floppy_format_type FLOPPY_OPUS_DDCPM_FORMAT = &floppy_image_format_creator<opus_ddcpm_format>;
-const floppy_format_type FLOPPY_TORCH_CPN_FORMAT = &floppy_image_format_creator<torch_cpn_format>;
diff --git a/src/lib/formats/acorn_dsk.h b/src/lib/formats/acorn_dsk.h
index ad4c67b79ee..2c71e4ee344 100644
--- a/src/lib/formats/acorn_dsk.h
+++ b/src/lib/formats/acorn_dsk.h
@@ -127,21 +127,6 @@ public:
virtual bool supports_save() const override;
};
-class torch_cpn_format : public wd177x_format
-{
-public:
- torch_cpn_format();
-
- virtual int identify(io_generic *io, uint32_t form_factor) override;
- virtual int get_image_offset(const format &f, int head, int track) override;
- virtual const char *name() const override;
- virtual const char *description() const override;
- virtual const char *extensions() const override;
-
-private:
- static const format formats[];
-};
-
extern const floppy_format_type FLOPPY_ACORN_SSD_FORMAT;
extern const floppy_format_type FLOPPY_ACORN_DSD_FORMAT;
@@ -150,6 +135,5 @@ extern const floppy_format_type FLOPPY_ACORN_ADFS_OLD_FORMAT;
extern const floppy_format_type FLOPPY_ACORN_ADFS_NEW_FORMAT;
extern const floppy_format_type FLOPPY_OPUS_DDOS_FORMAT;
extern const floppy_format_type FLOPPY_OPUS_DDCPM_FORMAT;
-extern const floppy_format_type FLOPPY_TORCH_CPN_FORMAT;
#endif // ACORN_DSK_H
diff --git a/src/lib/formats/dsk_dsk.cpp b/src/lib/formats/dsk_dsk.cpp
index 08f76c90127..493c503c223 100644
--- a/src/lib/formats/dsk_dsk.cpp
+++ b/src/lib/formats/dsk_dsk.cpp
@@ -398,6 +398,11 @@ bool dsk_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
continue;
track_header tr;
io_generic_read(io, &tr,track_offsets[(track<<1)+side],sizeof(tr));
+
+ // skip if there are no sectors in this track
+ if (tr.number_of_sector == 0)
+ continue;
+
desc_pc_sector sects[256];
uint8_t sect_data[65536];
int sdatapos = 0;
diff --git a/src/lib/formats/hxcmfm_dsk.cpp b/src/lib/formats/hxcmfm_dsk.cpp
index 274c8a7695f..dcc4718c114 100644
--- a/src/lib/formats/hxcmfm_dsk.cpp
+++ b/src/lib/formats/hxcmfm_dsk.cpp
@@ -75,19 +75,31 @@ bool mfm_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
// read header
io_generic_read(io, &header, 0, sizeof(header));
+
+ int drivecyl, driveheads;
+ image->get_maximal_geometry(drivecyl, driveheads);
+ bool skip_odd = (drivecyl < 50 && header.number_of_track >= 80);
+
int counter = 0;
std::vector<uint8_t> trackbuf;
for(int track=0; track < header.number_of_track; track++) {
for(int side=0; side < header.number_of_side; side++) {
- // read location of
- io_generic_read(io, &trackdesc,(header.mfmtracklistoffset)+( counter *sizeof(trackdesc)),sizeof(trackdesc));
-
- trackbuf.resize(trackdesc.mfmtracksize);
-
- // actual data read
- io_generic_read(io, &trackbuf[0], trackdesc.mfmtrackoffset, trackdesc.mfmtracksize);
-
- generate_track_from_bitstream(track, side, &trackbuf[0], trackdesc.mfmtracksize*8, image);
+ if (!skip_odd || track%2 == 0) {
+ // read location of
+ io_generic_read(io, &trackdesc,(header.mfmtracklistoffset)+( counter *sizeof(trackdesc)),sizeof(trackdesc));
+
+ trackbuf.resize(trackdesc.mfmtracksize);
+
+ // actual data read
+ io_generic_read(io, &trackbuf[0], trackdesc.mfmtrackoffset, trackdesc.mfmtracksize);
+
+ if (skip_odd) {
+ generate_track_from_bitstream(track/2, side, &trackbuf[0], trackdesc.mfmtracksize*8, image);
+ }
+ else {
+ generate_track_from_bitstream(track, side, &trackbuf[0], trackdesc.mfmtracksize*8, image);
+ }
+ }
counter++;
}
diff --git a/src/lib/formats/jvc_dsk.cpp b/src/lib/formats/jvc_dsk.cpp
index 3c230eed3cd..d2e7e503d3b 100644
--- a/src/lib/formats/jvc_dsk.cpp
+++ b/src/lib/formats/jvc_dsk.cpp
@@ -84,16 +84,20 @@ bool jvc_format::parse_header(io_generic *io, int &header_size, int &tracks, int
int os9_total_sectors = pick_integer_be(os9_header, 0x00, 3);
int os9_heads = BIT(os9_header[0x10], 0) ? 2 : 1;
int os9_sectors = pick_integer_be(os9_header, 0x11, 2);
- int os9_tracks = os9_total_sectors / os9_sectors / os9_heads;
- // now let's see if we have valid info
- if ((os9_tracks * os9_heads * os9_sectors * 256) == size)
+ if (os9_total_sectors > 0 && os9_heads > 0 && os9_sectors > 0)
{
- tracks = os9_tracks;
- heads = os9_heads;
- sectors = os9_sectors;
+ int os9_tracks = os9_total_sectors / os9_sectors / os9_heads;
- osd_printf_verbose("OS-9 format disk image detected.\n");
+ // now let's see if we have valid info
+ if ((os9_tracks * os9_heads * os9_sectors * 256) == size)
+ {
+ tracks = os9_tracks;
+ heads = os9_heads;
+ sectors = os9_sectors;
+
+ osd_printf_verbose("OS-9 format disk image detected.\n");
+ }
}
}
diff --git a/src/lib/formats/pc_dsk.cpp b/src/lib/formats/pc_dsk.cpp
index fa8f72f67d2..e4d7e02f47d 100644
--- a/src/lib/formats/pc_dsk.cpp
+++ b/src/lib/formats/pc_dsk.cpp
@@ -193,6 +193,10 @@ const pc_format::format pc_format::formats[] = {
floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
2000, 9, 40, 2, 512, {}, 1, {}, 80, 50, 22, 80
},
+ { /* 360K 5 1/4 inch double density, 41 tracks */
+ floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
+ 2000, 9, 41, 2, 512, {}, 1, {}, 80, 50, 22, 80
+ },
{ /* 360K 5 1/4 inch double density, 42 tracks */
floppy_image::FF_525, floppy_image::DSDD, floppy_image::MFM,
2000, 9, 42, 2, 512, {}, 1, {}, 80, 50, 22, 80
diff --git a/src/lib/util/disasmintf.cpp b/src/lib/util/disasmintf.cpp
new file mode 100644
index 00000000000..9699f68e823
--- /dev/null
+++ b/src/lib/util/disasmintf.cpp
@@ -0,0 +1,47 @@
+#include "disasmintf.h"
+
+util::u32 util::disasm_interface::interface_flags() const
+{
+ return 0;
+}
+
+util::u32 util::disasm_interface::page_address_bits() const
+{
+ throw ("unimplemented page_address_bits called");
+}
+
+util::u32 util::disasm_interface::page2_address_bits() const
+{
+ throw ("unimplemented page2_address_bits called");
+}
+
+util::disasm_interface::offs_t util::disasm_interface::pc_linear_to_real(offs_t pc) const
+{
+ throw ("unimplemented pc_linear_to_real called");
+}
+
+util::disasm_interface::offs_t util::disasm_interface::pc_real_to_linear(offs_t pc) const
+{
+ throw ("unimplemented pc_real_to_linear called");
+}
+
+util::u8 util::disasm_interface::decrypt8(u8 value, offs_t pc, bool opcode) const
+{
+ throw ("unimplemented decrypt8 called");
+}
+
+util::u16 util::disasm_interface::decrypt16(u16 value, offs_t pc, bool opcode) const
+{
+ throw ("unimplemented decrypt16 called");
+}
+
+util::u32 util::disasm_interface::decrypt32(u32 value, offs_t pc, bool opcode) const
+{
+ throw ("unimplemented decrypt32 called");
+}
+
+util::u64 util::disasm_interface::decrypt64(u64 value, offs_t pc, bool opcode) const
+{
+ throw ("unimplemented decrypt64 called");
+}
+
diff --git a/src/lib/util/disasmintf.h b/src/lib/util/disasmintf.h
new file mode 100644
index 00000000000..908bd762bdb
--- /dev/null
+++ b/src/lib/util/disasmintf.h
@@ -0,0 +1,69 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+/***************************************************************************
+
+ disasmintf.h
+
+ Generic disassembler interface.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef MAME_UTIL_DISASMINTF_H
+#define MAME_UTIL_DISASMINTF_H
+
+#include "coretmpl.h"
+
+namespace util {
+// class implementing a disassembler
+class disasm_interface
+{
+public:
+ using offs_t = u32;
+
+ // Disassembler constants for the return value
+ static constexpr u32 SUPPORTED = 0x80000000; // are disassembly flags supported?
+ static constexpr u32 STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
+ static constexpr u32 STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
+ static constexpr u32 OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
+ static constexpr u32 OVERINSTSHIFT = 27; // bits to shift after masking to get the value
+ static constexpr u32 LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
+
+ static inline u32 step_over_extra(u32 x) {
+ return x << OVERINSTSHIFT;
+ }
+
+ class data_buffer {
+ public:
+ virtual ~data_buffer() = default;
+ virtual u8 r8 (offs_t pc) const = 0;
+ virtual u16 r16(offs_t pc) const = 0;
+ virtual u32 r32(offs_t pc) const = 0;
+ virtual u64 r64(offs_t pc) const = 0;
+ };
+
+ enum {
+ NONLINEAR_PC = 0x00000001,
+ PAGED = 0x00000002,
+ PAGED2LEVEL = 0x00000006,
+ INTERNAL_DECRYPTION = 0x00000008,
+ SPLIT_DECRYPTION = 0x00000018
+ };
+
+ virtual u32 interface_flags() const;
+ virtual u32 page_address_bits() const;
+ virtual u32 page2_address_bits() const;
+ virtual offs_t pc_linear_to_real(offs_t pc) const;
+ virtual offs_t pc_real_to_linear(offs_t pc) const;
+ virtual u8 decrypt8 (u8 value, offs_t pc, bool opcode) const;
+ virtual u16 decrypt16(u16 value, offs_t pc, bool opcode) const;
+ virtual u32 decrypt32(u32 value, offs_t pc, bool opcode) const;
+ virtual u64 decrypt64(u64 value, offs_t pc, bool opcode) const;
+
+ virtual u32 opcode_alignment() const = 0;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) = 0;
+};
+}
+
+#endif
diff --git a/src/lib/util/timeconv.h b/src/lib/util/timeconv.h
index 7f9a7830b8e..365af8c19fb 100644
--- a/src/lib/util/timeconv.h
+++ b/src/lib/util/timeconv.h
@@ -17,6 +17,7 @@
#include "coreutil.h"
#include <chrono>
+#include <algorithm>
namespace util {
@@ -35,6 +36,21 @@ typedef std::chrono::duration<std::uint64_t, std::ratio<1, 10000000> > ntfs_dura
//---------------------------------------------------------
+// arbitrary_datetime
+//---------------------------------------------------------
+
+struct arbitrary_datetime
+{
+ int year; // absolute year (1900 AD = 1900)
+ int month; // month (1-12)
+ int day_of_month; // day of month (1-31)
+ int hour; // hour (0-23)
+ int minute; // minute (0-59)
+ int second; // second (0-59)
+};
+
+
+//---------------------------------------------------------
// arbitrary_clock - an std::chrono clock that "knows" the
// date of the epoch's begining
//---------------------------------------------------------
@@ -55,6 +71,17 @@ public:
static constexpr int base_second = S;
//---------------------------------------------------------
+ // from_arbitrary_datetime - converts an
+ // from_arbitrary_datetime to this arbitrary_clock's scale
+ //---------------------------------------------------------
+
+ static time_point from_arbitrary_datetime(const arbitrary_datetime &dt, bool clamp)
+ {
+ return time_point(duration_from_arbitrary_datetime(dt, clamp));
+ }
+
+
+ //---------------------------------------------------------
// from_arbitrary_time_point - converts an arbitrary_clock
// with a different scale to this arbitrary_clock's scale
//---------------------------------------------------------
@@ -62,13 +89,15 @@ public:
template<typename Rep2, int Y2, int M2, int D2, int H2, int N2, int S2, typename Ratio2>
static time_point from_arbitrary_time_point(const std::chrono::time_point<arbitrary_clock<Rep2, Y2, M2, D2, H2, N2, S2, Ratio2> > &tp)
{
- const int64_t our_absolute_day = absolute_day(Y, M, D);
- const int64_t their_absolute_day = absolute_day(Y2, M2, D2);
-
- const auto our_fract_day = std::chrono::hours(H) + std::chrono::minutes(N) + std::chrono::seconds(S);
- const auto their_fract_day = std::chrono::hours(H2) + std::chrono::minutes(N2) + std::chrono::seconds(S2);
-
- const std::chrono::duration<Rep, Ratio> adjustment(std::chrono::hours(24) * (their_absolute_day - our_absolute_day) + (their_fract_day - our_fract_day));
+ arbitrary_datetime dt;
+ dt.year = Y2;
+ dt.month = M2;
+ dt.day_of_month = D2;
+ dt.hour = H2;
+ dt.minute = N2;
+ dt.second = S2;
+
+ const duration adjustment = duration_from_arbitrary_datetime(dt, false);
const duration result_duration = std::chrono::duration_cast<duration>(tp.time_since_epoch() + adjustment);
return time_point(result_duration);
}
@@ -142,6 +171,46 @@ private:
// end of every quadcentury
typedef arbitrary_clock<std::int64_t, 1601, 1, 1, 0, 0, 0, std::ratio<1, 1> > tm_conversion_clock;
+
+ //---------------------------------------------------------
+ // clamp_or_throw
+ //---------------------------------------------------------
+
+ static int clamp_or_throw(int value, int minimum, int maximum, bool clamp, const char *out_of_range_message)
+ {
+ if (value < minimum || value > maximum)
+ {
+ if (clamp)
+ value = std::min(std::max(value, minimum), maximum);
+ else
+ throw std::out_of_range(out_of_range_message);
+ }
+ return value;
+ }
+
+ //---------------------------------------------------------
+ // duration_from_arbitrary_datetime - converts an
+ // arbitrary_datetime to this arbitrary_clock's duration
+ //---------------------------------------------------------
+
+ static duration duration_from_arbitrary_datetime(const arbitrary_datetime &dt, bool clamp)
+ {
+ // range checking
+ const int month = clamp_or_throw(dt.month, 1, 12, clamp, "invalid dt.month");
+ const int day_of_month = clamp_or_throw(dt.day_of_month, 1, gregorian_days_in_month(month, dt.year), clamp, "invalid dt.day_of_month");
+ const int hour = clamp_or_throw(dt.hour, 0, 23, clamp, "invalid dt.hour");
+ const int minute = clamp_or_throw(dt.minute, 0, 59, clamp, "invalid dt.minute");
+ const int second = clamp_or_throw(dt.second, 0, 59, clamp, "invalid dt.second");
+
+ const int64_t our_absolute_day = absolute_day(Y, M, D);
+ const int64_t their_absolute_day = absolute_day(dt.year, month, day_of_month);
+
+ const auto our_fract_day = std::chrono::hours(H) + std::chrono::minutes(N) + std::chrono::seconds(S);
+ const auto their_fract_day = std::chrono::hours(hour) + std::chrono::minutes(minute) + std::chrono::seconds(second);
+
+ return std::chrono::duration<Rep, Ratio>(std::chrono::hours(24) * (their_absolute_day - our_absolute_day) + (their_fract_day - our_fract_day));
+ }
+
//---------------------------------------------------------
// internal_to_tm - formats a structure of type 'struct tm'
// based on a normalized clock