mirror of
https://github.com/holub/mame
synced 2025-06-07 05:13:46 +03:00
-homebrew/linux4004.cpp: Emulated Linux/4004 board.
* VFD is not emulated, but all other features are present. -machine/sc16is741.cpp: Emulated basic SC16IS741A UART functionality in SPI interface mode. -macine/spi_sdcard.cpp: Improved interface logic: * Start in unprotected mode as specified by the standard. * Ignore stop bits in unprotected mode - apparenty real cards do this. * Set protected or unprotected mode in response to CMD59. * Reset SPI logic when initially selected. -machine/spi_psram.cpp: Started adding PSRAM QPI functionality. -emu/diserial.cpp: Got rid of the per-instance parity lookup table. New working systems ------------------- Dmitry Grinberg Linux/4004 New working software list items (lnux4004.xml) ---------------------------------------------- uMIPS Linux 4.4.292+
This commit is contained in:
parent
3a7d7252ef
commit
aeaf19f264
20
hash/lnux4004.xml
Normal file
20
hash/lnux4004.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
|
||||
<!--
|
||||
license:CC0-1.0
|
||||
-->
|
||||
|
||||
<softwarelist name="lnux4004" description="Linux/4004 SD Card images">
|
||||
|
||||
<software name="linux">
|
||||
<description>uMIPS Linux 4.4.292+</description>
|
||||
<year>2024</year>
|
||||
<publisher>Dmitry Grinberg</publisher>
|
||||
<part name="linux4004" interface="sdcard">
|
||||
<diskarea name="harddriv">
|
||||
<disk name="linux4004" sha1="6458018636d21845c95e1076b81c615e16a97975" writeable="yes" />
|
||||
</diskarea>
|
||||
</part>
|
||||
</software>
|
||||
|
||||
</softwarelist>
|
@ -3320,6 +3320,17 @@ if (MACHINES["SAA5070"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/sc16is741.h,MACHINES["SC16IS741"] = true
|
||||
---------------------------------------------------
|
||||
if (MACHINES["SC16IS741"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/sc16is741.cpp",
|
||||
MAME_DIR .. "src/devices/machine/sc16is741.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/scc66470.h,MACHINES["SCC66470"] = true
|
||||
|
1238
src/devices/machine/sc16is741.cpp
Normal file
1238
src/devices/machine/sc16is741.cpp
Normal file
File diff suppressed because it is too large
Load Diff
132
src/devices/machine/sc16is741.h
Normal file
132
src/devices/machine/sc16is741.h
Normal file
@ -0,0 +1,132 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
// I²C/SPI UART with 64-byte transmit and receive FIFOs
|
||||
#ifndef MAME_MACHINE_SC16IS741_H
|
||||
#define MAME_MACHINE_SC16IS741_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class sc16is741a_device : public device_t
|
||||
{
|
||||
public:
|
||||
sc16is741a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
virtual ~sc16is741a_device();
|
||||
|
||||
auto so_cb() { return m_so_cb.bind(); }
|
||||
auto irq_cb() { return m_irq_cb.bind(); }
|
||||
auto tx_cb() { return m_tx_cb.bind(); }
|
||||
auto rts_cb() { return m_rts_cb.bind(); }
|
||||
|
||||
void sclk_w(int state);
|
||||
void cs_w(int state);
|
||||
void si_w(int state);
|
||||
void rx_w(int state);
|
||||
void cts_w(int state);
|
||||
|
||||
protected:
|
||||
virtual void device_resolve_objects() override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_post_load() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
static inline constexpr u8 FIFO_LENGTH = 64;
|
||||
|
||||
enum class phase : u8;
|
||||
enum class parity : u8;
|
||||
enum interrupt : u8;
|
||||
|
||||
void update_irq();
|
||||
void update_tx();
|
||||
void set_rts(u8 state);
|
||||
|
||||
void reg_r(bool first);
|
||||
void reg_w();
|
||||
|
||||
void iir_r(bool first);
|
||||
void lsr_r(bool first);
|
||||
void msr_r(bool first);
|
||||
void txlvl_r(bool first);
|
||||
void rxlvl_r(bool first);
|
||||
void xon_xoff_r(bool first);
|
||||
|
||||
void thr_w();
|
||||
void ier_w();
|
||||
void fcr_w();
|
||||
void lcr_w();
|
||||
void mcr_w();
|
||||
void tcr_w();
|
||||
void tlr_w();
|
||||
void reserved_w();
|
||||
void uart_reset_w();
|
||||
void dl_w();
|
||||
void efr_w();
|
||||
void xon_xoff_w();
|
||||
|
||||
void pop_rx_fifo();
|
||||
bool check_tx();
|
||||
|
||||
u8 fifo_spaces(unsigned n) const;
|
||||
u8 fifo_fill_level(unsigned n) const;
|
||||
void fifo_reset(unsigned n);
|
||||
u8 fifo_push(unsigned n);
|
||||
u8 fifo_pop(unsigned n);
|
||||
|
||||
TIMER_CALLBACK_MEMBER(rx_shift);
|
||||
TIMER_CALLBACK_MEMBER(tx_shift);
|
||||
TIMER_CALLBACK_MEMBER(rx_timeout);
|
||||
|
||||
void update_trigger_levels();
|
||||
void update_data_frame();
|
||||
void update_divisor();
|
||||
|
||||
devcb_write_line m_so_cb;
|
||||
devcb_write_line m_irq_cb;
|
||||
devcb_write_line m_tx_cb;
|
||||
devcb_write_line m_rts_cb;
|
||||
|
||||
emu_timer *m_shift_timer[2];
|
||||
emu_timer *m_rx_timeout_timer;
|
||||
|
||||
u8 m_irq, m_tx, m_rts;
|
||||
u8 m_rx, m_cts;
|
||||
|
||||
u8 m_sclk, m_cs, m_si;
|
||||
phase m_phase;
|
||||
u8 m_bits, m_buffer;
|
||||
u8 m_command;
|
||||
|
||||
u8 m_ier;
|
||||
u8 m_fcr;
|
||||
u8 m_lcr;
|
||||
u8 m_mcr;
|
||||
u8 m_spr;
|
||||
u8 m_tcr;
|
||||
u8 m_tlr;
|
||||
u16 m_dl;
|
||||
u8 m_efr;
|
||||
u8 m_xon_xoff[4];
|
||||
|
||||
u16 m_shift_reg[2];
|
||||
u8 m_rx_remain, m_rx_count;
|
||||
u8 m_tx_remain, m_tx_count;
|
||||
|
||||
u8 m_fifo_head[2], m_fifo_tail[2];
|
||||
bool m_fifo_empty[2];
|
||||
u8 m_fifo_data[3][FIFO_LENGTH];
|
||||
u8 m_fifo_errors;
|
||||
|
||||
u8 m_interrupts;
|
||||
|
||||
u32 m_divisor;
|
||||
u8 m_word_length;
|
||||
parity m_parity;
|
||||
u8 m_rx_intervals, m_tx_intervals;
|
||||
u8 m_rx_trigger, m_tx_trigger;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SC16IS741A, sc16is741a_device)
|
||||
|
||||
#endif // MAME_MACHINE_SC16IS741_H
|
@ -30,9 +30,13 @@
|
||||
|
||||
Example PSRAM:
|
||||
* AP Memory APS1604L-SQ (2 MiB)
|
||||
* AP Memory APS1604M-SQ (2 MiB)
|
||||
* AP Memory APS3204L-SQ (4 MiB)
|
||||
* AP Memory APS3204M-SQ (4 MiB)
|
||||
* AP Memory APS6404L-SQ (8 MiB)
|
||||
* AP Memory APS6404M-SQ (8 MiB)
|
||||
* AP Memory APS12804L-SQ (16 MiB)
|
||||
* AP Memory APS12804M-SQ (16 MiB)
|
||||
* ISS IS66WVS1M8 (1 MiB)
|
||||
* ISS IS66WVS2M8 (2 MiB)
|
||||
* ISS IS66WVS8M8 (8 MiB)
|
||||
@ -54,30 +58,20 @@
|
||||
#include "spi_psram.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device, "spi_psram", "Generic SPI RAM")
|
||||
DEFINE_DEVICE_TYPE(SPI_RAM, spi_ram_device, "spi_ram", "Generic SPI RAM")
|
||||
DEFINE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device, "spi_psram", "Generic SPI/QPI Pseudo-SRAM")
|
||||
|
||||
|
||||
ALLOW_SAVE_TYPE(spi_psram_device::phase)
|
||||
|
||||
enum class spi_psram_device::phase : u8
|
||||
{
|
||||
IDLE,
|
||||
COMMAND,
|
||||
ADDRESS,
|
||||
WAIT,
|
||||
READ,
|
||||
WRITE
|
||||
};
|
||||
|
||||
|
||||
enum spi_psram_device::command : u8
|
||||
enum spi_ram_device::command : u8
|
||||
{
|
||||
COMMAND_READ = 0x03,
|
||||
COMMAND_FAST_READ = 0x0b, // 8 wait cycles in SPI mode, 4 wait cycles in QPI mode
|
||||
COMMAND_FAST_READ_QUAD = 0xeb, // 6 wait cycles, always 4-bit address and data
|
||||
COMMAND_WRAPPED_READ = 0x8b, // 8 wait cycles in SPI mode, 5 wait cycles in QPI mode
|
||||
|
||||
COMMAND_WRITE = 0x02,
|
||||
COMMAND_WRITE_QUAD = 0x38, // always 4-bit address and data
|
||||
COMMAND_WRAPPED_WRITE = 0x82,
|
||||
|
||||
COMMAND_QPI_ENTER = 0x35,
|
||||
COMMAND_QPI_EXIT = 0xf5,
|
||||
@ -100,20 +94,38 @@ enum spi_psram_device::command : u8
|
||||
};
|
||||
|
||||
|
||||
spi_psram_device::spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, SPI_PSRAM, tag, owner, clock),
|
||||
ALLOW_SAVE_TYPE(spi_ram_device::phase)
|
||||
|
||||
enum class spi_ram_device::phase : u8
|
||||
{
|
||||
IDLE,
|
||||
COMMAND,
|
||||
ADDRESS,
|
||||
WAIT,
|
||||
READ,
|
||||
WRITE
|
||||
};
|
||||
|
||||
|
||||
spi_ram_device::spi_ram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
spi_ram_device(mconfig, SPI_RAM, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
spi_ram_device::spi_ram_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, type, tag, owner, clock),
|
||||
m_sio_cb(*this),
|
||||
m_ram(),
|
||||
m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
spi_psram_device::~spi_psram_device()
|
||||
spi_ram_device::~spi_ram_device()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void spi_psram_device::ce_w(int state)
|
||||
void spi_ram_device::ce_w(int state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
@ -130,7 +142,7 @@ void spi_psram_device::ce_w(int state)
|
||||
m_ce = state ? 1 : 0;
|
||||
}
|
||||
|
||||
void spi_psram_device::sclk_w(int state)
|
||||
void spi_ram_device::sclk_w(int state)
|
||||
{
|
||||
switch (m_phase)
|
||||
{
|
||||
@ -139,12 +151,13 @@ void spi_psram_device::sclk_w(int state)
|
||||
case phase::WRITE:
|
||||
if (state && !m_sclk)
|
||||
{
|
||||
m_buffer = (m_buffer << m_cmd_width) | (m_sio & util::make_bitmask<u8>(m_cmd_width));
|
||||
m_buffer = (m_buffer << m_data_width) | (m_sio & util::make_bitmask<u8>(m_data_width));
|
||||
m_bits -= m_data_width;
|
||||
if (!m_bits)
|
||||
{
|
||||
if (phase::COMMAND == m_phase)
|
||||
{
|
||||
m_phase = phase::IDLE;
|
||||
m_cmd = u8(m_buffer);
|
||||
start_command();
|
||||
}
|
||||
@ -187,25 +200,37 @@ void spi_psram_device::sclk_w(int state)
|
||||
}
|
||||
break;
|
||||
|
||||
case phase::WAIT:
|
||||
if (state && !m_sclk)
|
||||
{
|
||||
m_bits -= m_data_width;
|
||||
if (!m_bits)
|
||||
{
|
||||
m_bits = 8;
|
||||
m_phase = m_next_phase;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_sclk = state ? 1 : 0;
|
||||
}
|
||||
|
||||
void spi_psram_device::sio_w(offs_t offset, u8 data, u8 mem_mask)
|
||||
void spi_ram_device::sio_w(offs_t offset, u8 data, u8 mem_mask)
|
||||
{
|
||||
m_sio = data & 0xf;
|
||||
}
|
||||
|
||||
|
||||
void spi_psram_device::device_validity_check(validity_checker &valid) const
|
||||
void spi_ram_device::device_validity_check(validity_checker &valid) const
|
||||
{
|
||||
if (!m_size || (m_size & (m_size - 1)) || (m_size > 0x0100'0000))
|
||||
osd_printf_error("Unsupported size %u (must be a power of 2 not larger than 16M)\n", m_size);
|
||||
}
|
||||
|
||||
void spi_psram_device::device_resolve_objects()
|
||||
void spi_ram_device::device_resolve_objects()
|
||||
{
|
||||
m_wrap_mask = util::make_bitmask<u32>(10);
|
||||
m_addr = 0;
|
||||
@ -213,15 +238,17 @@ void spi_psram_device::device_resolve_objects()
|
||||
m_cmd_width = 1;
|
||||
m_data_width = 1;
|
||||
m_bits = 0;
|
||||
m_wait = 0;
|
||||
|
||||
m_ce = 1;
|
||||
m_sclk = 0;
|
||||
m_sio = 0xf;
|
||||
m_phase = phase::IDLE;
|
||||
m_next_phase = phase::IDLE;
|
||||
m_cmd = 0;
|
||||
}
|
||||
|
||||
void spi_psram_device::device_start()
|
||||
void spi_ram_device::device_start()
|
||||
{
|
||||
if (!m_size || (m_size & (m_size - 1)) || (m_size > 0x0100'0000))
|
||||
osd_printf_error("%s: Unsupported size %u (must be a power of 2 not larger than 16M)\n", tag(), m_size);
|
||||
@ -235,64 +262,77 @@ void spi_psram_device::device_start()
|
||||
save_item(NAME(m_cmd_width));
|
||||
save_item(NAME(m_data_width));
|
||||
save_item(NAME(m_bits));
|
||||
save_item(NAME(m_wait));
|
||||
save_item(NAME(m_ce));
|
||||
save_item(NAME(m_sclk));
|
||||
save_item(NAME(m_sio));
|
||||
save_item(NAME(m_phase));
|
||||
save_item(NAME(m_next_phase));
|
||||
save_item(NAME(m_cmd));
|
||||
}
|
||||
|
||||
|
||||
void spi_psram_device::start_command()
|
||||
void spi_ram_device::start_command()
|
||||
{
|
||||
switch (m_cmd)
|
||||
{
|
||||
case COMMAND_READ:
|
||||
// FIXME: AP Memory devices don't support this command in QPI mode
|
||||
m_buffer = 0;
|
||||
m_data_width = m_cmd_width;
|
||||
m_bits = 24;
|
||||
m_phase = phase::ADDRESS;
|
||||
break;
|
||||
|
||||
case COMMAND_WRITE:
|
||||
m_buffer = 0;
|
||||
m_data_width = m_cmd_width;
|
||||
m_bits = 24;
|
||||
m_phase = phase::ADDRESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("unimplemented command 0x%02x\n", m_cmd);
|
||||
m_phase = phase::IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void spi_psram_device::address_complete()
|
||||
{
|
||||
switch (m_cmd)
|
||||
switch (cmd())
|
||||
{
|
||||
case COMMAND_READ:
|
||||
// FIXME: wait cycles depend on mode and device family
|
||||
m_buffer = m_ram[m_addr];
|
||||
m_data_width = m_cmd_width;
|
||||
m_bits = 8;
|
||||
m_phase = phase::READ;
|
||||
break;
|
||||
start_read(m_cmd_width, 0);
|
||||
return;
|
||||
|
||||
case COMMAND_WRITE:
|
||||
m_buffer = 0;
|
||||
m_data_width = m_cmd_width;
|
||||
m_bits = 8;
|
||||
m_phase = phase::WRITE;
|
||||
break;
|
||||
start_write(m_cmd_width);
|
||||
return;
|
||||
|
||||
default:
|
||||
throw false; // if we get here, there's a bug in the code
|
||||
logerror("unimplemented command 0x%02x in %u-bit mode\n", cmd(), m_cmd_width);
|
||||
}
|
||||
}
|
||||
|
||||
inline void spi_psram_device::next_address()
|
||||
void spi_ram_device::address_complete()
|
||||
{
|
||||
if (m_wait)
|
||||
{
|
||||
m_phase = phase::WAIT;
|
||||
m_bits = m_wait;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buffer = (phase::READ == m_next_phase) ? m_ram[m_addr] : 0;
|
||||
m_bits = 8;
|
||||
m_phase = m_next_phase;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void spi_ram_device::set_cmd_width(u8 width)
|
||||
{
|
||||
m_cmd_width = width;
|
||||
}
|
||||
|
||||
inline void spi_ram_device::start_read(u8 width, u8 wait)
|
||||
{
|
||||
m_buffer = 0;
|
||||
m_data_width = width;
|
||||
m_bits = 24;
|
||||
m_wait = wait * width;
|
||||
m_phase = phase::ADDRESS;
|
||||
m_next_phase = phase::READ;
|
||||
}
|
||||
|
||||
inline void spi_ram_device::start_write(u8 width)
|
||||
{
|
||||
m_buffer = 0;
|
||||
m_data_width = width;
|
||||
m_bits = 24;
|
||||
m_wait = 0;
|
||||
m_phase = phase::ADDRESS;
|
||||
m_next_phase = phase::WRITE;
|
||||
}
|
||||
|
||||
|
||||
inline void spi_ram_device::next_address()
|
||||
{
|
||||
if (m_wrap_mask)
|
||||
{
|
||||
@ -304,3 +344,84 @@ inline void spi_psram_device::next_address()
|
||||
m_phase = phase::IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
spi_psram_device::spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
spi_ram_device(mconfig, SPI_PSRAM, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
spi_psram_device::~spi_psram_device()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void spi_psram_device::device_resolve_objects()
|
||||
{
|
||||
spi_ram_device::device_resolve_objects();
|
||||
|
||||
m_reset_enable = false;
|
||||
}
|
||||
|
||||
void spi_psram_device::device_start()
|
||||
{
|
||||
spi_ram_device::device_start();
|
||||
|
||||
save_item(NAME(m_reset_enable));
|
||||
}
|
||||
|
||||
|
||||
void spi_psram_device::start_command()
|
||||
{
|
||||
bool const reset_enable(std::exchange(m_reset_enable, false));
|
||||
switch (cmd())
|
||||
{
|
||||
case COMMAND_READ:
|
||||
if (cmd_width() == 4)
|
||||
{
|
||||
// FIXME: AP Memory and Vilsion Technology devices don't support command 0x03 in QPI mode
|
||||
start_read(4, 4);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMAND_FAST_READ:
|
||||
start_read(cmd_width(), (cmd_width() == 4) ? 4 : 8);
|
||||
return;
|
||||
|
||||
case COMMAND_FAST_READ_QUAD:
|
||||
start_read(4, 6);
|
||||
return;
|
||||
|
||||
case COMMAND_WRITE_QUAD:
|
||||
start_write(4);
|
||||
return;
|
||||
|
||||
case COMMAND_QPI_ENTER:
|
||||
if (cmd_width() == 1)
|
||||
{
|
||||
set_cmd_width(4);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMAND_QPI_EXIT:
|
||||
if (cmd_width() == 4)
|
||||
{
|
||||
set_cmd_width(1);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMAND_RESET_ENABLE:
|
||||
m_reset_enable = true;
|
||||
return;
|
||||
|
||||
case COMMAND_RESET:
|
||||
if (reset_enable)
|
||||
set_cmd_width(1);
|
||||
return;
|
||||
}
|
||||
spi_ram_device::start_command();
|
||||
}
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include <memory>
|
||||
|
||||
|
||||
class spi_psram_device : public device_t
|
||||
class spi_ram_device : public device_t
|
||||
{
|
||||
public:
|
||||
spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
|
||||
virtual ~spi_psram_device();
|
||||
spi_ram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
|
||||
virtual ~spi_ram_device();
|
||||
|
||||
void set_size(u32 size) { m_size = size; }
|
||||
auto sio_cb() { return m_sio_cb.bind(); }
|
||||
@ -24,17 +24,28 @@ public:
|
||||
void si_w(int state) { sio_w(0, state ? 0xf : 0xe, 0x1); }
|
||||
|
||||
protected:
|
||||
enum command : u8;
|
||||
|
||||
spi_ram_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
virtual void device_validity_check(validity_checker &valid) const override ATTR_COLD;
|
||||
virtual void device_resolve_objects() override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
|
||||
void start_command();
|
||||
void address_complete();
|
||||
void next_address();
|
||||
virtual void start_command();
|
||||
|
||||
u8 cmd_width() const { return m_cmd_width; }
|
||||
u8 cmd() const { return m_cmd; }
|
||||
|
||||
void set_cmd_width(u8 width);
|
||||
void start_read(u8 width, u8 wait);
|
||||
void start_write(u8 width);
|
||||
|
||||
private:
|
||||
enum class phase : u8;
|
||||
enum command : u8;
|
||||
|
||||
void address_complete();
|
||||
void next_address();
|
||||
|
||||
devcb_write8 m_sio_cb;
|
||||
|
||||
@ -45,13 +56,32 @@ private:
|
||||
u32 m_buffer;
|
||||
u8 m_cmd_width, m_data_width;
|
||||
u8 m_bits;
|
||||
u8 m_wait;
|
||||
|
||||
u8 m_ce, m_sclk, m_sio;
|
||||
phase m_phase;
|
||||
phase m_phase, m_next_phase;
|
||||
u8 m_cmd;
|
||||
};
|
||||
|
||||
|
||||
class spi_psram_device : public spi_ram_device
|
||||
{
|
||||
public:
|
||||
spi_psram_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0U);
|
||||
virtual ~spi_psram_device();
|
||||
|
||||
protected:
|
||||
virtual void device_resolve_objects() override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
|
||||
virtual void start_command() override;
|
||||
|
||||
private:
|
||||
bool m_reset_enable;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPI_RAM, spi_ram_device)
|
||||
DECLARE_DEVICE_TYPE(SPI_PSRAM, spi_psram_device)
|
||||
|
||||
#endif // MAME_MACHINE_SPI_PSRAM_H
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u8 DATA_RESPONSE_OK = 0x05;
|
||||
@ -152,16 +153,17 @@ spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, device_type
|
||||
write_miso(*this),
|
||||
m_image(*this, "image"),
|
||||
m_preferred_type(SD_TYPE_V2),
|
||||
m_ignore_stop_bit(false),
|
||||
m_blksize(512),
|
||||
m_type(SD_TYPE_V2),
|
||||
m_state(SD_STATE_IDLE),
|
||||
m_ss(0), m_in_bit(0), m_clk_state(0),
|
||||
m_in_latch(0), m_out_latch(0xff), m_cur_bit(0),
|
||||
m_out_delay(0), m_out_count(0), m_out_ptr(0), m_write_ptr(0), m_xferblk(512), m_blknext(0),
|
||||
m_crc_off(true),
|
||||
m_bACMD(false)
|
||||
{
|
||||
std::fill(std::begin(m_csd), std::end(m_csd), 0);
|
||||
std::fill(std::begin(m_cmd), std::end(m_cmd), 0xff);
|
||||
}
|
||||
|
||||
spi_sdcard_device::~spi_sdcard_device()
|
||||
@ -187,6 +189,7 @@ void spi_sdcard_device::device_start()
|
||||
save_item(NAME(m_write_ptr));
|
||||
save_item(NAME(m_xferblk));
|
||||
save_item(NAME(m_blknext));
|
||||
save_item(NAME(m_crc_off));
|
||||
save_item(NAME(m_bACMD));
|
||||
}
|
||||
|
||||
@ -238,6 +241,7 @@ std::error_condition spi_sdcard_device::image_loaded(device_image_interface &ima
|
||||
}
|
||||
|
||||
m_blksize = m_xferblk = info.sectorbytes;
|
||||
m_crc_off = true;
|
||||
|
||||
// set up common CSD fields
|
||||
m_csd[0] = 0x00; // 127: CSD_STRUCTURE:2 (00b) 0:6
|
||||
@ -354,6 +358,26 @@ void spi_sdcard_device::spi_clock_w(int state)
|
||||
m_clk_state = state;
|
||||
}
|
||||
|
||||
void spi_sdcard_device::spi_ss_w(int state)
|
||||
{
|
||||
if (!m_ss && state)
|
||||
{
|
||||
LOGMASKED(LOG_SPI, "SDCARD: selected\n");
|
||||
std::fill(std::begin(m_cmd), std::end(m_cmd), 0xff);
|
||||
m_state = SD_STATE_IDLE;
|
||||
m_in_latch = 0;
|
||||
m_cur_bit = 0;
|
||||
m_out_latch = 0xff;
|
||||
m_out_delay = 0;
|
||||
m_out_count = 0;
|
||||
}
|
||||
else if (m_ss && !state)
|
||||
{
|
||||
LOGMASKED(LOG_SPI, "SDCARD: deselected\n");
|
||||
}
|
||||
m_ss = state;
|
||||
}
|
||||
|
||||
void spi_sdcard_device::latch_in()
|
||||
{
|
||||
m_in_latch &= ~0x01;
|
||||
@ -446,7 +470,7 @@ void spi_sdcard_device::shift_out()
|
||||
|
||||
void spi_sdcard_device::do_command()
|
||||
{
|
||||
if (((m_cmd[0] & 0xc0) == 0x40) && ((m_cmd[5] & 1) || m_ignore_stop_bit))
|
||||
if (((m_cmd[0] & 0xc0) == 0x40) && ((m_cmd[5] & 1) || m_crc_off))
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "SDCARD: cmd %02d %02x %02x %02x %02x %02x\n", m_cmd[0] & 0x3f, m_cmd[1], m_cmd[2], m_cmd[3], m_cmd[4], m_cmd[5]);
|
||||
bool clean_cmd = true;
|
||||
@ -682,8 +706,8 @@ void spi_sdcard_device::do_command()
|
||||
break;
|
||||
|
||||
case 59: // CMD59 - CRC_ON_OFF
|
||||
m_crc_off = !BIT(m_cmd[4], 0);
|
||||
m_data[0] = 0;
|
||||
// TODO CRC 1-on, 0-off
|
||||
send_data(1, SD_STATE_STBY);
|
||||
break;
|
||||
|
||||
|
@ -18,12 +18,11 @@ public:
|
||||
|
||||
void set_prefer_sd() { m_preferred_type = SD_TYPE_V2; }
|
||||
void set_prefer_sdhc() { m_preferred_type = SD_TYPE_HC; }
|
||||
void set_ignore_stop_bit(bool ignore) { m_ignore_stop_bit = ignore; }
|
||||
|
||||
// SPI 4-wire interface
|
||||
auto spi_miso_callback() { return write_miso.bind(); }
|
||||
void spi_clock_w(int state);
|
||||
void spi_ss_w(int state) { m_ss = state; }
|
||||
void spi_ss_w(int state);
|
||||
void spi_mosi_w(int state) { m_in_bit = state; }
|
||||
|
||||
bool get_card_present() { return m_image->exists(); }
|
||||
@ -62,7 +61,6 @@ private:
|
||||
|
||||
// configuration
|
||||
sd_type m_preferred_type;
|
||||
bool m_ignore_stop_bit;
|
||||
|
||||
// mounted image info
|
||||
std::vector<u8> m_sectorbuf;
|
||||
@ -80,6 +78,7 @@ private:
|
||||
u16 m_out_count, m_out_ptr, m_write_ptr;
|
||||
u16 m_xferblk;
|
||||
u32 m_blknext;
|
||||
bool m_crc_off;
|
||||
bool m_bACMD;
|
||||
};
|
||||
|
||||
|
@ -45,21 +45,6 @@ device_serial_interface::device_serial_interface(const machine_config &mconfig,
|
||||
m_tra_clock_state(false),
|
||||
m_rcv_clock_state(false)
|
||||
{
|
||||
/* if sum of all bits in the byte is even, then the data
|
||||
has even parity, otherwise it has odd parity */
|
||||
for (int i=0; i<256; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
int data = i;
|
||||
|
||||
for (int b=0; b<8; b++)
|
||||
{
|
||||
sum+=data & 0x01;
|
||||
data = data>>1;
|
||||
}
|
||||
|
||||
m_serial_parity_table[i] = sum & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
device_serial_interface::~device_serial_interface()
|
||||
@ -317,13 +302,13 @@ void device_serial_interface::receive_register_extract()
|
||||
receive_register_reset();
|
||||
|
||||
/* strip off stop bits and parity */
|
||||
assert(m_rcv_bit_count >0 && m_rcv_bit_count <= 16);
|
||||
data = m_rcv_register_data>>(16-m_rcv_bit_count);
|
||||
assert(m_rcv_bit_count > 0 && m_rcv_bit_count <= 16);
|
||||
data = m_rcv_register_data >> (16 - m_rcv_bit_count);
|
||||
|
||||
/* mask off other bits so data byte has 0's in unused bits */
|
||||
data &= ~(0xff<<m_df_word_length);
|
||||
data &= ~(0xff << m_df_word_length);
|
||||
|
||||
m_rcv_byte_received = data;
|
||||
m_rcv_byte_received = data;
|
||||
LOGMASKED(LOG_RX, "Receive data 0x%02x\n", m_rcv_byte_received);
|
||||
|
||||
if(m_df_parity == PARITY_NONE)
|
||||
@ -336,12 +321,12 @@ void device_serial_interface::receive_register_extract()
|
||||
switch (m_df_parity)
|
||||
{
|
||||
case PARITY_ODD:
|
||||
if (parity_received == serial_helper_get_parity(data))
|
||||
if (parity_received == BIT(population_count_32(data), 0))
|
||||
m_rcv_parity_error = true;
|
||||
break;
|
||||
|
||||
case PARITY_EVEN:
|
||||
if (parity_received != serial_helper_get_parity(data))
|
||||
if (parity_received != BIT(population_count_32(data), 0))
|
||||
m_rcv_parity_error = true;
|
||||
break;
|
||||
|
||||
@ -369,9 +354,8 @@ void device_serial_interface::transmit_register_reset()
|
||||
void device_serial_interface::transmit_register_add_bit(int bit)
|
||||
{
|
||||
/* combine bit */
|
||||
m_tra_register_data = m_tra_register_data<<1;
|
||||
m_tra_register_data &=~1;
|
||||
m_tra_register_data|=(bit & 0x01);
|
||||
m_tra_register_data = m_tra_register_data << 1;
|
||||
m_tra_register_data |= (bit & 0x01);
|
||||
m_tra_bit_count++;
|
||||
}
|
||||
|
||||
@ -379,10 +363,9 @@ void device_serial_interface::transmit_register_add_bit(int bit)
|
||||
/* generate data in stream format ready for transfer */
|
||||
void device_serial_interface::transmit_register_setup(u8 data_byte)
|
||||
{
|
||||
int i;
|
||||
u8 transmit_data;
|
||||
|
||||
if(m_tra_clock && !m_tra_rate.is_never())
|
||||
if (m_tra_clock && !m_tra_rate.is_never())
|
||||
m_tra_clock->adjust(m_tra_rate, 0, m_tra_rate);
|
||||
|
||||
m_tra_bit_count_transmitted = 0;
|
||||
@ -390,40 +373,35 @@ void device_serial_interface::transmit_register_setup(u8 data_byte)
|
||||
m_tra_flags &=~TRANSMIT_REGISTER_EMPTY;
|
||||
|
||||
/* start bit */
|
||||
for (i=0; i<m_df_start_bit_count; i++)
|
||||
for (int i = 0; i < m_df_start_bit_count; i++)
|
||||
{
|
||||
transmit_register_add_bit(0);
|
||||
}
|
||||
|
||||
/* data bits */
|
||||
transmit_data = data_byte;
|
||||
for (i=0; i<m_df_word_length; i++)
|
||||
for (int i = 0; i < m_df_word_length; i++)
|
||||
{
|
||||
int databit;
|
||||
|
||||
/* get bit from data */
|
||||
databit = transmit_data & 0x01;
|
||||
/* add bit to formatted byte */
|
||||
transmit_register_add_bit(databit);
|
||||
transmit_data = transmit_data>>1;
|
||||
transmit_register_add_bit(BIT(transmit_data, 0));
|
||||
transmit_data >>= 1;
|
||||
}
|
||||
|
||||
/* parity */
|
||||
if (m_df_parity!=PARITY_NONE)
|
||||
if (m_df_parity != PARITY_NONE)
|
||||
{
|
||||
/* odd or even parity */
|
||||
u8 parity = 0;
|
||||
switch (m_df_parity)
|
||||
{
|
||||
case PARITY_ODD:
|
||||
|
||||
/* get parity */
|
||||
/* if parity = 0, data has even parity - i.e. there is an even number of one bits in the data */
|
||||
/* if parity = 1, data has odd parity - i.e. there is an odd number of one bits in the data */
|
||||
parity = serial_helper_get_parity(data_byte) ^ 1;
|
||||
// get parity
|
||||
// if parity[0] = 0, data has even parity - i.e. there is an even number of one bits in the data
|
||||
// if parity[0] = 1, data has odd parity - i.e. there is an odd number of one bits in the data
|
||||
parity = BIT(population_count_32(data_byte), 0) ^ 1;
|
||||
break;
|
||||
case PARITY_EVEN:
|
||||
parity = serial_helper_get_parity(data_byte);
|
||||
parity = BIT(population_count_32(data_byte), 0);
|
||||
break;
|
||||
case PARITY_MARK:
|
||||
parity = 1;
|
||||
@ -436,7 +414,7 @@ void device_serial_interface::transmit_register_setup(u8 data_byte)
|
||||
}
|
||||
|
||||
/* TX stop bit(s) */
|
||||
for (i=0; i<m_df_stop_bit_count; i++)
|
||||
for (int i = 0; i < m_df_stop_bit_count; i++)
|
||||
transmit_register_add_bit(1);
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,6 @@ protected:
|
||||
void transmit_register_setup(u8 data_byte);
|
||||
u8 transmit_register_get_data_bit();
|
||||
|
||||
u8 serial_helper_get_parity(u8 data) { return m_serial_parity_table[data]; }
|
||||
|
||||
bool is_receive_register_full() const { return m_rcv_flags & RECEIVE_REGISTER_FULL; }
|
||||
bool is_transmit_register_empty() const { return m_tra_flags & TRANSMIT_REGISTER_EMPTY; }
|
||||
bool is_receive_register_synchronized() const { return m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED; }
|
||||
@ -132,8 +130,6 @@ private:
|
||||
TIMER_CALLBACK_MEMBER(rcv_clock) { rx_clock_w(!m_rcv_clock_state); }
|
||||
TIMER_CALLBACK_MEMBER(tra_clock) { tx_clock_w(!m_tra_clock_state); }
|
||||
|
||||
u8 m_serial_parity_table[256];
|
||||
|
||||
// Data frame
|
||||
// number of start bits
|
||||
int m_df_start_bit_count;
|
||||
|
278
src/mame/homebrew/linux4004.cpp
Normal file
278
src/mame/homebrew/linux4004.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/*
|
||||
Linux/4004
|
||||
|
||||
http://dmitry.gr/?r=05.Projects&proj=35.%20Linux4004
|
||||
|
||||
A MIPS-I emulator with paravirtualised hardware running on an Intel
|
||||
4004 CPU. It looks enough like a DECstation 3100 with an R3000 CPU to
|
||||
satisfy Linux.
|
||||
|
||||
TODO:
|
||||
* Emulate the VFD (Futaba M402SD10FJ or Noritake CU40025-UW6J)
|
||||
*/
|
||||
#include "emu.h"
|
||||
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "cpu/mcs40/mcs40.h"
|
||||
#include "machine/sc16is741.h"
|
||||
#include "machine/spi_psram.h"
|
||||
#include "machine/spi_sdcard.h"
|
||||
|
||||
#include "softlist_dev.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "lnux4004.lh"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class linux4004_state : public driver_device
|
||||
{
|
||||
public:
|
||||
static constexpr feature_type unemulated_features() { return feature::GRAPHICS; }
|
||||
|
||||
linux4004_state(machine_config const &mconfig, device_type type, char const *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_cpu(*this, "u1")
|
||||
, m_psram(*this, "u%u", 5U)
|
||||
, m_sdcard(*this, "sd")
|
||||
, m_uart(*this, "u9")
|
||||
, m_memory(*this, "memory")
|
||||
, m_status(*this, "status")
|
||||
, m_rom_bank(*this, "rom")
|
||||
, m_led_pc(*this, "pc%u", 0U)
|
||||
, m_led_sdcard(*this, "storage")
|
||||
{
|
||||
}
|
||||
|
||||
void linux4004(machine_config &config) ATTR_COLD;
|
||||
|
||||
protected:
|
||||
virtual void machine_start() override ATTR_COLD;
|
||||
virtual void machine_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
template <unsigned N> void psram_sio_w(offs_t offset, u8 data, u8 mem_mask);
|
||||
template <unsigned N> void miso_w(int state);
|
||||
|
||||
u8 u3_r();
|
||||
void u4002_1_3_w(u8 data);
|
||||
void u4002_1_4_w(u8 data);
|
||||
void u4002_2_3_w(u8 data);
|
||||
template <unsigned N> void led_pc_w(offs_t offset, u8 data);
|
||||
|
||||
void umips_rom(address_map &map) ATTR_COLD;
|
||||
void umips_ram(address_map &map) ATTR_COLD;
|
||||
void umips_status(address_map &map) ATTR_COLD;
|
||||
void umips_rom_ports(address_map &map) ATTR_COLD;
|
||||
void umips_ram_ports(address_map &map) ATTR_COLD;
|
||||
|
||||
required_device<i4004_cpu_device> m_cpu;
|
||||
required_device_array<spi_psram_device, 2> m_psram;
|
||||
required_device<spi_sdcard_device> m_sdcard;
|
||||
required_device<sc16is741a_device> m_uart;
|
||||
required_shared_ptr<u8> m_memory;
|
||||
required_shared_ptr<u8> m_status;
|
||||
required_memory_bank m_rom_bank;
|
||||
|
||||
output_finder<32> m_led_pc;
|
||||
output_finder<> m_led_sdcard;
|
||||
|
||||
u8 m_psram_so[2];
|
||||
u8 m_u3_in;
|
||||
};
|
||||
|
||||
|
||||
INPUT_PORTS_START(linux4004)
|
||||
PORT_START("CONF")
|
||||
PORT_CONFNAME(0x03, 0x00, "TLB Entries")
|
||||
PORT_CONFSETTING( 0x03, "4")
|
||||
PORT_CONFSETTING( 0x02, "8")
|
||||
PORT_CONFSETTING( 0x01, "12")
|
||||
PORT_CONFSETTING( 0x00, "16")
|
||||
PORT_CONFNAME(0x04, 0x00, "U4002-2-4 Installed")
|
||||
PORT_CONFSETTING( 0x00, DEF_STR(No))
|
||||
PORT_CONFSETTING( 0x04, DEF_STR(Yes))
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
void linux4004_state::linux4004(machine_config &config)
|
||||
{
|
||||
config.set_default_layout(layout_lnux4004);
|
||||
|
||||
I4004(config, m_cpu, 5.5296_MHz_XTAL / 7);
|
||||
m_cpu->set_rom_map(&linux4004_state::umips_rom);
|
||||
m_cpu->set_ram_memory_map(&linux4004_state::umips_ram);
|
||||
m_cpu->set_ram_status_map(&linux4004_state::umips_status);
|
||||
m_cpu->set_rom_ports_map(&linux4004_state::umips_rom_ports);
|
||||
m_cpu->set_ram_ports_map(&linux4004_state::umips_ram_ports);
|
||||
|
||||
SPI_PSRAM(config, m_psram[0]);
|
||||
m_psram[0]->set_size(8 << 20); // supports 4 MiB to 16 MiB
|
||||
m_psram[0]->sio_cb().set(FUNC(linux4004_state::psram_sio_w<0>));
|
||||
|
||||
SPI_PSRAM(config, m_psram[1]);
|
||||
m_psram[1]->set_size(4 << 20); // supports 128 KiB to 16 MiB
|
||||
m_psram[1]->sio_cb().set(FUNC(linux4004_state::psram_sio_w<1>));
|
||||
|
||||
SPI_SDCARD(config, m_sdcard, 0U);
|
||||
m_sdcard->spi_miso_callback().set(FUNC(linux4004_state::miso_w<3>));
|
||||
|
||||
SC16IS741A(config, m_uart, 3.072_MHz_XTAL);
|
||||
m_uart->so_cb().set(FUNC(linux4004_state::miso_w<2>));
|
||||
m_uart->irq_cb().set_inputline(m_cpu, I4004_TEST_LINE).invert();
|
||||
m_uart->tx_cb().set("rs232", FUNC(rs232_port_device::write_txd));
|
||||
m_uart->rts_cb().set("rs232", FUNC(rs232_port_device::write_rts));
|
||||
|
||||
auto &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
|
||||
rs232.rxd_handler().set(m_uart, FUNC(sc16is741a_device::rx_w));
|
||||
rs232.cts_handler().set(m_uart, FUNC(sc16is741a_device::cts_w));
|
||||
|
||||
SOFTWARE_LIST(config, "sdcard_list").set_original("lnux4004");
|
||||
}
|
||||
|
||||
|
||||
void linux4004_state::machine_start()
|
||||
{
|
||||
m_rom_bank->configure_entries(0, 2, memregion("4004firmware")->base(), 0x1000);
|
||||
m_led_pc.resolve();
|
||||
m_led_sdcard.resolve();
|
||||
|
||||
std::fill(std::begin(m_psram_so), std::end(m_psram_so), 1);
|
||||
m_u3_in = 0;
|
||||
|
||||
save_item(NAME(m_psram_so));
|
||||
save_item(NAME(m_u3_in));
|
||||
}
|
||||
|
||||
void linux4004_state::machine_reset()
|
||||
{
|
||||
ioport_value const conf(ioport("CONF")->read());
|
||||
auto const tlb_empty(BIT(conf, 0, 2));
|
||||
auto const u4002_2_4(BIT(conf, 2));
|
||||
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).unmap_readwrite(0x0000, 0x02ff);
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).unmap_readwrite(0x00, 0xbf);
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_PORTS).unmap_readwrite(0x08, 0x0b);
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).install_ram(0x0000, 0x02ff - (tlb_empty * 0x40), m_memory.target());
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).install_ram(0x00, 0xbf - (tlb_empty * 0x10), m_status.target());
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_PORTS).install_write_handler(0x08, 0x0b - tlb_empty, emu::rw_delegate(*this, FUNC(linux4004_state::led_pc_w<4>)));
|
||||
if (!u4002_2_4)
|
||||
{
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_MEMORY).unmap_readwrite(0x01c0, 0x01ff);
|
||||
m_cpu->space(i4004_cpu_device::AS_RAM_STATUS).unmap_readwrite(0x70, 0x7f);
|
||||
}
|
||||
|
||||
std::fill(m_memory.begin(), m_memory.end(), 0);
|
||||
std::fill(m_status.begin(), m_status.end(), 0);
|
||||
|
||||
u4002_1_3_w(0);
|
||||
u4002_1_4_w(0);
|
||||
u4002_2_3_w(0);
|
||||
for (auto &led : m_led_pc)
|
||||
led = 0;
|
||||
}
|
||||
|
||||
|
||||
template <unsigned N>
|
||||
void linux4004_state::psram_sio_w(offs_t offset, u8 data, u8 mem_mask)
|
||||
{
|
||||
m_psram_so[N] = BIT(data | ~mem_mask, 1);
|
||||
miso_w<0>(m_psram_so[0] & m_psram_so[1]);
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
void linux4004_state::miso_w(int state)
|
||||
{
|
||||
m_u3_in = (m_u3_in & ~(u8(1) << N)) | (u8(state ? 1 : 0) << N);
|
||||
}
|
||||
|
||||
|
||||
u8 linux4004_state::u3_r()
|
||||
{
|
||||
return m_u3_in;
|
||||
}
|
||||
|
||||
void linux4004_state::u4002_1_3_w(u8 data)
|
||||
{
|
||||
m_sdcard->spi_mosi_w(BIT(~data, 0));
|
||||
m_sdcard->spi_clock_w(BIT(~data, 1));
|
||||
m_sdcard->spi_ss_w(BIT(data, 2) ? ASSERT_LINE : CLEAR_LINE);
|
||||
m_led_sdcard = BIT(~data, 2);
|
||||
m_rom_bank->set_entry(BIT(data, 3) ^ 0x01);
|
||||
}
|
||||
|
||||
void linux4004_state::u4002_1_4_w(u8 data)
|
||||
{
|
||||
m_uart->si_w(BIT(~data, 0)); // TODO: also connected to VFD
|
||||
m_uart->sclk_w(BIT(~data, 1)); // TODO: also connected to VFD
|
||||
// VFD_NCS_HV
|
||||
m_uart->cs_w(BIT(~data, 3));
|
||||
}
|
||||
|
||||
void linux4004_state::u4002_2_3_w(u8 data)
|
||||
{
|
||||
m_psram[0]->si_w(BIT(~data, 0));
|
||||
m_psram[1]->si_w(BIT(~data, 0));
|
||||
m_psram[0]->sclk_w(BIT(~data, 1));
|
||||
m_psram[1]->sclk_w(BIT(~data, 1));
|
||||
m_psram[0]->ce_w(BIT(~data, 2));
|
||||
m_psram[1]->ce_w(BIT(~data, 3));
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
void linux4004_state::led_pc_w(offs_t offset, u8 data)
|
||||
{
|
||||
for (unsigned i = 0; 4 > i; ++i)
|
||||
m_led_pc[i | ((N + offset) << 2)] = BIT(data, i);
|
||||
}
|
||||
|
||||
|
||||
void linux4004_state::umips_rom(address_map &map)
|
||||
{
|
||||
map.unmap_value_low();
|
||||
map.global_mask(0x0fff);
|
||||
map(0x0000, 0x0fff).bankr(m_rom_bank);
|
||||
}
|
||||
|
||||
void linux4004_state::umips_ram(address_map &map)
|
||||
{
|
||||
map.unmap_value_low();
|
||||
map(0x0000, 0x02ff).ram().share(m_memory); // up to twelve 4002 chips
|
||||
}
|
||||
|
||||
void linux4004_state::umips_status(address_map &map)
|
||||
{
|
||||
map.unmap_value_low();
|
||||
map(0x00, 0xbf).ram().share(m_status); // up to twelve 4002 chips
|
||||
}
|
||||
|
||||
void linux4004_state::umips_rom_ports(address_map &map)
|
||||
{
|
||||
map.unmap_value_high();
|
||||
map.global_mask(0x0ff);
|
||||
map(0x000, 0x0ff).r(FUNC(linux4004_state::u3_r));
|
||||
}
|
||||
|
||||
void linux4004_state::umips_ram_ports(address_map &map)
|
||||
{
|
||||
map(0x00, 0x03).w(FUNC(linux4004_state::led_pc_w<0>));
|
||||
map(0x04, 0x04).w(FUNC(linux4004_state::u4002_1_3_w));
|
||||
map(0x05, 0x05).w(FUNC(linux4004_state::u4002_1_4_w));
|
||||
map(0x06, 0x06).w(FUNC(linux4004_state::u4002_2_3_w));
|
||||
map(0x08, 0x0b).w(FUNC(linux4004_state::led_pc_w<4>));
|
||||
}
|
||||
|
||||
|
||||
ROM_START(lnux4004)
|
||||
ROM_REGION(0x2000, "4004firmware", 0)
|
||||
ROM_LOAD("umips.u4", 0x0000, 0x2000, CRC(27dd98c1) SHA1(a9d2b1990e7ae8ce4a53950430c5186d4cf55a01)) // AT28C64B
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
SYST( 2024, lnux4004, 0, 0, linux4004, linux4004, linux4004_state, empty_init, "Dmitry Grinberg", "Linux/4004", MACHINE_NO_SOUND_HW | MACHINE_SUPPORTS_SAVE )
|
79
src/mame/layout/lnux4004.lay
Normal file
79
src/mame/layout/lnux4004.lay
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
license:CC0-1.0
|
||||
|
||||
Linux/4004 LED display
|
||||
-->
|
||||
<mamelayout version="2">
|
||||
|
||||
<element name="blank">
|
||||
<rect />
|
||||
</element>
|
||||
|
||||
<element name="led">
|
||||
<disk state="0">
|
||||
<color red="0.15" green="0.0" blue="0.0" />
|
||||
</disk>
|
||||
<disk state="1">
|
||||
<color red="1.0" green="0.0" blue="0.0" />
|
||||
</disk>
|
||||
</element>
|
||||
|
||||
<element name="lbl_sdcard">
|
||||
<text string="STORAGE" align="2" />
|
||||
</element>
|
||||
|
||||
<element name="lbl_pc">
|
||||
<text string="MIPS PC" align="1" />
|
||||
</element>
|
||||
|
||||
<group name="leds">
|
||||
<element ref="blank">
|
||||
<bounds x="0" y="0" width="500" height="50" />
|
||||
<color red="0" green="0" blue="0" />
|
||||
</element>
|
||||
|
||||
<element ref="lbl_sdcard">
|
||||
<bounds x="415" y="10" width="60" height="10" />
|
||||
</element>
|
||||
|
||||
<element ref="lbl_pc">
|
||||
<bounds x="10" y="15" width="60" height="10" />
|
||||
</element>
|
||||
|
||||
<element ref="led" name="storage">
|
||||
<bounds x="480" y="10" width="10" height="10" />
|
||||
</element>
|
||||
|
||||
<repeat count="32">
|
||||
<param name="n" start="31" increment="-1" />
|
||||
<param name="x" start="10" increment="15" />
|
||||
<element ref="led" name="pc~n~">
|
||||
<bounds x="~x~" y="30" width="10" height="10" />
|
||||
</element>
|
||||
</repeat>
|
||||
</group>
|
||||
|
||||
<view name="LEDs">
|
||||
<group ref="leds" />
|
||||
</view>
|
||||
|
||||
<view name="Terminal Below">
|
||||
<group ref="leds">
|
||||
<bounds x="0" y="0" width="500" height="50" />
|
||||
</group>
|
||||
<screen index="0">
|
||||
<bounds x="0" y="50" width="500" height="375" />
|
||||
</screen>
|
||||
</view>
|
||||
|
||||
<view name="Terminal Above">
|
||||
<group ref="leds">
|
||||
<bounds x="0" y="375" width="500" height="50" />
|
||||
</group>
|
||||
<screen index="0">
|
||||
<bounds x="0" y="0" width="500" height="375" />
|
||||
</screen>
|
||||
</view>
|
||||
|
||||
</mamelayout>
|
@ -19767,6 +19767,9 @@ gsz80 // Grant Searle's Simple Z-80 Machine
|
||||
@source:homebrew/homez80.cpp
|
||||
homez80 //
|
||||
|
||||
@source:homebrew/linux4004.cpp
|
||||
lnux4004
|
||||
|
||||
@source:homebrew/lft_chiptune.cpp
|
||||
powernin // Power Ninja Action Challenge, by [lft] (2009)
|
||||
hwchiptn // The Hardware Chiptune Project, by [lft] and kryo (2007)
|
||||
|
Loading…
Reference in New Issue
Block a user