// license:BSD-3-Clause // copyright-holders: Dirk Best /************************************************************************* RAM device Provides a configurable amount of RAM to drivers **************************************************************************/ #include "emu.h" #include "ram.h" #include "emuopts.h" #include #include #include #include #include namespace { //------------------------------------------------- // parse_string - convert a ram string to an // integer value //------------------------------------------------- u32 parse_string(const char *s) { static constexpr struct { const char *suffix; unsigned multiple; } s_suffixes[] = { { "", 1 }, { "k", 1024 }, { "kb", 1024 }, { "kib", 1024 }, { "m", 1024 * 1024 }, { "mb", 1024 * 1024 }, { "mib", 1024 * 1024 } }; // parse the string unsigned ram = 0; char suffix[8] = { 0, }; sscanf(s, "%u%7s", &ram, suffix); // perform the lookup auto const iter(std::find_if( std::begin(s_suffixes), std::end(s_suffixes), [&suffix](const auto &potential_suffix) { return !core_stricmp(suffix, potential_suffix.suffix); })); // identify the multiplier (or 0 if not recognized, signalling a parse failure) unsigned const multiplier((iter != std::end(s_suffixes)) ? iter->multiple : 0); // return the result return ram * multiplier; } //------------------------------------------------- // calculate_extra_options //------------------------------------------------- ram_device::extra_option_vector calculate_extra_options(const char *extra_options_string, std::string *bad_option) { ram_device::extra_option_vector result; std::string const options(extra_options_string); bool done(false); for (std::string::size_type start = 0, end = options.find_first_of(','); !done; start = end + 1, end = options.find_first_of(',', start)) { // ignore spaces while ((end > start) && (options.length() > start) && ((' ' == options[start]) || ('\t' == options[start]))) ++start; // parse the option std::string ram_option_string(options.substr(start, (end == -1) ? -1 : end - start)); u32 const ram_option = parse_string(ram_option_string.c_str()); if (ram_option == 0) { if (bad_option) *bad_option = std::move(ram_option_string); return result; } // and add it to the results result.emplace_back(std::move(ram_option_string), ram_option); done = std::string::npos == end; } return result; } }; /***************************************************************************** LIVE DEVICE *****************************************************************************/ // device type definition DEFINE_DEVICE_TYPE(RAM, ram_device, "ram", "RAM") //------------------------------------------------- // ram_device - constructor //------------------------------------------------- ram_device::ram_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, RAM, tag, owner, clock) , m_size(0) , m_default_size(0) , m_default_value(0xCD) , m_extra_options_string(nullptr) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void ram_device::device_start() { // the device named 'ram' can get ram options from command line u32 const defsize(default_size()); m_size = 0; if (strcmp(tag(), ":" RAM_TAG) == 0) { char const *const ramsize_string(machine().options().ram_size()); if (ramsize_string && *ramsize_string) { m_size = parse_string(ramsize_string); if (!is_valid_size(m_size)) { extra_option_vector::const_iterator found(std::find_if(m_extra_options.begin(), m_extra_options.end(), [defsize] (extra_option const &opt) { return opt.second == defsize; })); std::ostringstream output; util::stream_format(output, "Cannot recognize the RAM option %s (valid options are ", ramsize_string); if (!m_extra_options_string) util::stream_format(output, "%s).\n", m_default_size); else if (m_extra_options.end() != found) util::stream_format(output, "%s).\n", m_extra_options_string); else util::stream_format(output, "%s,%s).\n", m_default_size, m_extra_options_string); osd_printf_error("%s", output.str().c_str()); osd_printf_warning("Setting value to default %s\n", m_default_size); m_size = 0; } } } // if we didn't get a size yet, use the default if (m_size == 0) m_size = defsize; // allocate space for the ram m_pointer = std::make_unique(m_size); std::fill_n(m_pointer.get(), m_size, m_default_value); // register for state saving save_item(NAME(m_size)); save_pointer(NAME(m_pointer), m_size); } //------------------------------------------------- // device_validity_check - device-specific validity // checks //------------------------------------------------- void ram_device::device_validity_check(validity_checker &valid) const { // verify default ram value if (default_size() == 0) osd_printf_error("Invalid default RAM option: %s\n", m_default_size); // calculate any extra options if (m_extra_options_string) { std::string bad_option; extra_option_vector const extras(calculate_extra_options(m_extra_options_string, &bad_option)); // report any errors if (!bad_option.empty()) osd_printf_error("Invalid RAM option: %s\n", bad_option.c_str()); // report duplicates using extra_option_ref_set = std::set, bool (*)(extra_option const &, extra_option const &)>; extra_option_ref_set sorted([] (extra_option const &a, extra_option const &b) { return a.second < b.second; }); for (extra_option const &opt : extras) { auto const ins(sorted.emplace(opt)); if (!ins.second) osd_printf_error("Duplicate RAM options: %s == %s (%u)\n", ins.first->get().first.c_str(), opt.first.c_str(), opt.second); } } } //------------------------------------------------- // is_valid_size //------------------------------------------------- bool ram_device::is_valid_size(u32 size) const { return size == default_size() || std::find_if(extra_options().begin(), extra_options().end(), [size] (extra_option const &opt) { return opt.second == size; }) != extra_options().end(); } //------------------------------------------------- // default_size //------------------------------------------------- u32 ram_device::default_size() const { return parse_string(m_default_size); } //------------------------------------------------- // extra_options //------------------------------------------------- const ram_device::extra_option_vector &ram_device::extra_options() const { if (m_extra_options_string && m_extra_options.empty()) m_extra_options = calculate_extra_options(m_extra_options_string, nullptr); return m_extra_options; }