alto2: refactor display and CROM/RAM config (nw)

Refactor the display to use a buffer of the size of the total margins.
Remove the deprecated MCFG_SCREEN_REFRESH_RATE().
Try to synchronize the CPU on the vertical sync generated by mame
calling the screen_update() function.

Instead of a fixed CROM/CRAM configuration defined through macros,
make this a machine configuration parameter. You can now choose
between the 3 setups:
1 = 1K CROM, 1K CRAM, 1 S register bank
2 = 2K CROM, 1K CRAM, 1 S register bank
3 = 1K CROM, 3K CRAM, 8 S register banks

TODO: Some games which used to work in Salto do no longer work with
this driver, e.g. pacman7 from the allgames.chd
This commit is contained in:
Juergen Buchmueller 2016-08-13 16:06:37 +02:00
parent 32acbb190b
commit de6745296b
12 changed files with 385 additions and 371 deletions

View File

@ -37,31 +37,11 @@ void alto2_cpu_device::f2_late_load_csr()
/**
* @brief curt_activate: called by the CPU when the cursor task becomes active
*
* Shift CSR to xpreg % 16 position to make it easier to
* to handle the word xor in unload_word().
* <PRE>
* xpreg % 16 cursor bits
* [ first word ][ second word ]
* ----------------------------------------------
* 0 xxxxxxxxxxxxxxxx0000000000000000
* 1 0xxxxxxxxxxxxxxxx000000000000000
* 2 00xxxxxxxxxxxxxxxx00000000000000
* ...
* 14 00000000000000xxxxxxxxxxxxxxxx00
* 15 000000000000000xxxxxxxxxxxxxxxx0
* </PRE>
*/
void alto2_cpu_device::activate_curt()
{
m_task_wakeup &= ~(1 << m_task);
m_dsp.curt_wakeup = false;
int x = 01777 - m_dsp.xpreg;
UINT32 bits = m_dsp.csr << (16 - (x & 15));
m_dsp.cursor0 = static_cast<UINT16>(bits >> 16);
m_dsp.cursor1 = static_cast<UINT16>(bits);
m_dsp.curxpos = x / 16;
}
/** @brief initialize the cursor task F1 and F2 functions */
@ -79,6 +59,4 @@ void alto2_cpu_device::reset_curt()
m_dsp.curt_blocks = false;
m_dsp.xpreg = 0;
m_dsp.csr = 0;
m_dsp.curxpos = 0;
m_dsp.cursor0 = m_dsp.cursor1 = 0;
}

View File

@ -245,11 +245,12 @@ static const UINT16 double_bits[256] = {
//! update the internal frame buffer and draw the scanline segment if changed
void alto2_cpu_device::update_framebuf_word(UINT16* framebuf, int x, int y, UINT16 word)
{
int xpword = (m_dsp.xpreg ^ 01777) / 16;
// mixing with the cursor
if (x == m_dsp.curxpos + 0)
word ^= m_dsp.cursor0;
if (x == m_dsp.curxpos + 1)
word ^= m_dsp.cursor1;
if (x == xpword++)
word ^= (m_dsp.csr << (m_dsp.xpreg % 16)) >> 16;
if (x == xpword)
word ^= (m_dsp.csr << (m_dsp.xpreg % 16)) & 0xffff;
// no change?
if (word == framebuf[x])
return;
@ -263,14 +264,14 @@ void alto2_cpu_device::update_framebuf_word(UINT16* framebuf, int x, int y, UINT
void alto2_cpu_device::unload_word()
{
int x = m_unload_word;
int y = ((m_dsp.hlc - m_dsp.vblank) & ~02001) ^ HLC1024;
int y = m_dsp.scanline;
if (y < 0 || y >= ALTO2_DISPLAY_HEIGHT || x >= ALTO2_DISPLAY_VISIBLE_WORDS)
if (y < 0 || y >= ALTO2_DISPLAY_TOTAL_HEIGHT || x >= ALTO2_DISPLAY_VISIBLE_WORDS)
{
m_unload_time = -1;
return;
}
UINT16* framebuf = m_dsp.framebuf.get() + y * ALTO2_DISPLAY_SCANLINE_WORDS;
UINT16* framebuf = m_dsp.framebuf.get() + y * ALTO2_DISPLAY_SCANLINE_WORDS;
UINT16 word = m_dsp.inverse;
UINT8 a38 = m_disp_a38[m_dsp.ra * 16 + m_dsp.wa];
if (FIFO_MBEMPTY(a38))
@ -329,8 +330,14 @@ void alto2_cpu_device::display_state_machine()
{
// count horizontal line counters and wrap
m_dsp.hlc += 1;
if (m_dsp.hlc > ALTO2_DISPLAY_HLC_END)
if (m_dsp.hlc > ALTO2_DISPLAY_HLC_END) {
m_dsp.hlc = ALTO2_DISPLAY_HLC_START;
m_dsp.scanline = 30;
m_dsp.vsync = true;
} else if (m_dsp.hlc == 1024) {
m_dsp.vsync = true;
m_dsp.scanline = 31;
}
// wake up the memory refresh task _twice_ on each scanline
m_task_wakeup |= 1 << task_mrt;
}
@ -342,9 +349,6 @@ void alto2_cpu_device::display_state_machine()
if (A66_VBLANK(a66))
{
// Rising edge of VBLANK: remember HLC[1-10] where the VBLANK starts
m_dsp.vblank = m_dsp.hlc & ~(1 << 10);
LOG((this,LOG_DISPL,1, " VBLANK"));
// VSYNC is always within VBLANK, thus we handle it only here
@ -357,6 +361,7 @@ void alto2_cpu_device::display_state_machine()
*/
m_task_wakeup |= 1 << task_dvt;
}
m_dsp.inverse = 0xffff;
}
else
{
@ -385,9 +390,10 @@ void alto2_cpu_device::display_state_machine()
}
if (!A63_HBLANK(a63) && A63_HBLANK(m_dsp.a63))
{
m_dsp.scanline += 2;
// Falling edge of a63 HBLANK starts unloading of FIFO words
LOG((this,LOG_DISPL,1, " HBLANK\\ UNLOAD"));
m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 32 : 16);
m_unload_time = ALTO2_DISPLAY_BITTIME(m_dsp.halfclock ? 40+32 : 40+16);
m_unload_word = 0;
}
}
@ -470,7 +476,7 @@ void alto2_cpu_device::display_state_machine()
*/
void alto2_cpu_device::f2_late_evenfield()
{
UINT16 r = HLC1024 ^ 1;
UINT16 r = m_dsp.odd ? 0 : 1;
LOG((this,LOG_DISPL,2," EVENFIELD branch (%#o | %#o)\n", m_next2, r));
m_next2 |= r;
}
@ -499,12 +505,8 @@ void alto2_cpu_device::init_disp()
save_item(NAME(m_dsp.dwt_blocks));
save_item(NAME(m_dsp.curt_blocks));
save_item(NAME(m_dsp.curt_wakeup));
save_item(NAME(m_dsp.vblank));
save_item(NAME(m_dsp.xpreg));
save_item(NAME(m_dsp.csr));
save_item(NAME(m_dsp.curxpos));
save_item(NAME(m_dsp.cursor0));
save_item(NAME(m_dsp.cursor1));
m_disp_a38 = prom_load(machine(), &pl_displ_a38, memregion("displ_a38")->base());
m_disp_a63 = prom_load(machine(), &pl_displ_a63, memregion("displ_a63")->base());
@ -512,7 +514,7 @@ void alto2_cpu_device::init_disp()
m_dsp.hlc = ALTO2_DISPLAY_HLC_START;
m_dsp.framebuf = std::make_unique<UINT16[]>(ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS);
m_dsp.framebuf = std::make_unique<UINT16[]>(ALTO2_DISPLAY_TOTAL_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS);
m_dsp.patterns = auto_alloc_array(machine(), UINT8, 65536 * 16);
for (int y = 0; y < 65536; y++) {
UINT8* dst = m_dsp.patterns + y * 16;
@ -520,7 +522,8 @@ void alto2_cpu_device::init_disp()
*dst++ = (~y >> (15 - x)) & 1;
}
m_dsp.bitmap = std::make_unique<bitmap_ind16>(ALTO2_DISPLAY_WIDTH, ALTO2_DISPLAY_HEIGHT);
// Allocate a bitmap including the V/H blank areas
m_dsp.bitmap = std::make_unique<bitmap_ind16>(ALTO2_DISPLAY_TOTAL_WIDTH, ALTO2_DISPLAY_TOTAL_HEIGHT);
m_dsp.state = 0;
}
@ -537,6 +540,7 @@ void alto2_cpu_device::reset_disp()
m_dsp.a66 = 0;
m_dsp.setmode = 0;
m_dsp.inverse = 0;
m_dsp.scanline = 30;
m_dsp.halfclock = false;
m_dsp.wa = 0;
m_dsp.ra = 0;
@ -544,12 +548,10 @@ void alto2_cpu_device::reset_disp()
m_dsp.dwt_blocks = false;
m_dsp.curt_blocks = false;
m_dsp.curt_wakeup = false;
m_dsp.vblank = 0;
m_dsp.vsync = false;
m_dsp.odd = false;
m_dsp.xpreg = 0;
m_dsp.csr = 0;
m_dsp.curxpos = 0;
m_dsp.cursor0 = 0;
m_dsp.cursor1 = 0;
memset(m_dsp.framebuf.get(), 1, sizeof(UINT16) * ALTO2_DISPLAY_HEIGHT * ALTO2_DISPLAY_SCANLINE_WORDS);
}
@ -557,10 +559,7 @@ void alto2_cpu_device::reset_disp()
UINT32 alto2_cpu_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
copybitmap(bitmap, *m_dsp.bitmap, 0, 0, 0, 0, cliprect);
m_dsp.vsync = false;
m_dsp.odd = !m_dsp.odd;
return 0;
}
void alto2_cpu_device::screen_eof(screen_device &screen, bool state)
{
// FIXME: do we need this in some way?
}

View File

@ -39,7 +39,7 @@
* scanlines to the monitor. The frame rate is 60Hz, which is actually the rate
* of the half-frames. The rate for full frames is thus 30Hz.
*/
#define ALTO2_DISPLAY_TOTAL_HEIGHT ((ALTO2_DISPLAY_HLC_END - ALTO2_DISPLAY_HLC_START) / 2)
#define ALTO2_DISPLAY_TOTAL_HEIGHT ((ALTO2_DISPLAY_HLC_END + 1 - ALTO2_DISPLAY_HLC_START) / 2)
/**
* @brief display total width, including horizontal blanking
@ -80,7 +80,8 @@
#define ALTO2_DISPLAY_HEIGHT 808
//! Visible width of the display; 38 x 16 bit words - 2 pixels.
#define ALTO2_DISPLAY_WIDTH 606
//#define ALTO2_DISPLAY_WIDTH 606
#define ALTO2_DISPLAY_WIDTH 608
//! Visible words per scanline.
#define ALTO2_DISPLAY_VISIBLE_WORDS ((ALTO2_DISPLAY_WIDTH+15)/16)
@ -197,7 +198,10 @@ struct {
UINT32 hlc; //!< horizontal line counter
UINT32 setmode; //!< value written by last SETMODE<-
UINT32 inverse; //!< set to 0xffff if line is inverse, 0x0000 otherwise
UINT32 scanline; //!< current scanline
bool halfclock; //!< false for normal pixel clock, true for half pixel clock
bool vsync; //!< true after vsync, false when end_of_frame was called
bool odd; //!< true if odd field
UINT16 fifo[ALTO2_DISPLAY_FIFO]; //!< display word fifo
UINT32 wa; //!< fifo input pointer (write address; 4-bit)
UINT32 ra; //!< fifo output pointer (read address; 4-bit)
@ -207,12 +211,8 @@ struct {
bool dwt_blocks; //!< set true, if the DWT executed BLOCK
bool curt_blocks; //!< set true, if the CURT executed BLOCK
bool curt_wakeup; //!< set true, if CURT wakeups are generated
UINT32 vblank; //!< most recent HLC with VBLANK still high (11-bit)
UINT32 xpreg; //!< cursor cursor x position register (10-bit)
UINT32 csr; //!< cursor shift register (16-bit)
UINT32 curxpos; //!< helper: first cursor word in scanline
UINT32 cursor0; //!< helper: shifted cursor data for left word
UINT32 cursor1; //!< helper: shifted cursor data for right word
std::unique_ptr<UINT16[]> framebuf; //!< array of words of the raw bitmap that is displayed
UINT8 *patterns; //!< array of 65536 patterns (16 bytes) with 1 byte per pixel
std::unique_ptr<bitmap_ind16> bitmap; //!< MAME bitmap with 16 bit indices

View File

@ -42,25 +42,27 @@
#define FIFO_STOPWAKE(a38) (0 == (a38 & disp_a38_STOPWAKE) ? true : false)
/**
* @brief block the display word task
* @brief Block the display word task.
*/
void alto2_cpu_device::f1_early_dwt_block()
{
m_dsp.dwt_blocks = true;
/* clear the wakeup for the display word task */
// Clear the wakeup for the display word task
m_task_wakeup &= ~(1 << m_task);
LOG((this,LOG_DWT,2," BLOCK %s\n", task_name(m_task)));
/* wakeup the display horizontal task, if it didn't block itself */
// Wakeup the display horizontal task, if it didn't block itself
if (!m_dsp.dht_blocks)
m_task_wakeup |= 1 << task_dht;
}
/**
* @brief load the display data register
* @brief Load the display data register
* Pushes the word on the bus to the display FIFO.
* If the FIFO becomes full, the wakeup flag for task_dwt is reset.
*/
void alto2_cpu_device::f2_late_dwt_load_ddr()
void alto2_cpu_device::f2_late_load_ddr()
{
LOG((this,LOG_DWT,2," DDR<- BUS (%#o)\n", m_bus));
m_dsp.fifo[m_dsp.wa] = m_bus;

View File

@ -17,7 +17,7 @@ enum {
};
void f1_early_dwt_block(); //!< F1 func: block the display word task
void f2_late_dwt_load_ddr(); //!< F2 func: load the display data register
void f2_late_load_ddr(); //!< F2 func: load the display data register
void init_dwt(int task = task_dwt); //!< initialize the display word task
void exit_dwt(); //!< deinitialize the display word task
void reset_dwt(); //!< reset the display word task

View File

@ -230,7 +230,7 @@ WRITE16_MEMBER( alto2_cpu_device::mouse_buttons_w ) { X_WRBITS(m_hw.utilin,16,13
/**
* @brief read the UTILIN port
*
* @param addr memory mapped I/O address to be read
* @param offset memory mapped I/O address to be read
* @return current value on the UTILIN port
*/
READ16_MEMBER( alto2_cpu_device::utilin_r )
@ -250,7 +250,7 @@ READ16_MEMBER( alto2_cpu_device::utilin_r )
/**
* @brief read the XBUS port
*
* @param addr memory mapped I/O address to be read
* @param offset memory mapped I/O address to be read
* @return current value on the XBUS port latch
*/
READ16_MEMBER( alto2_cpu_device::xbus_r )

View File

@ -7,16 +7,13 @@
*****************************************************************************/
#include "alto2cpu.h"
#define DEBUG_WRTRAM 0 //!< define to 1 to printf disassembled CRAM writes
#define DEBUG_WRTRAM 1 //!< define to 1 to print CRAM writes
#define DEBUG_RDRAM 1 //!< define to 1 to print CRAM reads
#define DEBUG_BRANCH 1 //!< define to 1 to print branching to ROM/RAM
//! direct read access to the microcode CRAM
#define RD_CRAM(addr) (*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + addr * 4))
//! direct write access to the microcode CRAM
#define WR_CRAM(addr,data) do { \
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + addr * 4) = data; \
} while (0)
/**
* @brief read the microcode ROM/RAM halfword
*
@ -88,17 +85,30 @@ void alto2_cpu_device::rdram()
}
m_rdram_flag = false;
if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) {
if (m_ucode_ram_base + addr >= m_ucode_size) {
value = 0177777; /* ??? */
LOG((this,LOG_CPU,0,"invalid address (%06o)\n", addr));
#if DEBUG_RDRAM
printf("RD CRAM_BANKSEL=%d RAM%d [%04o] invalid address!\n",
GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr);
#endif
return;
}
value = RD_CRAM(addr) ^ ALTO2_UCODE_INVERTED;
value = *reinterpret_cast<UINT32 *>(m_ucode_cram.get() + addr * 4) ^ ALTO2_UCODE_INVERTED;
#if DEBUG_RDRAM
char buffer[256];
UINT8* oprom = m_ucode_cram.get() + 4 * wordaddr;
disasm_disassemble(buffer, wordaddr, oprom, oprom, 0);
printf("RD CRAM_BANKSEL=%d RAM%d [%04o] upper:%06o lower:%06o value:%011o '%s'\n",
GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr, m_myl, m_alu,
value, buffer);
#endif
if (GET_CRAM_HALFSEL(m_cram_addr)) {
value = value >> 16;
LOG((this,LOG_CPU,0,"upper:%06o\n", value & 0177777));
value >>= 16;
LOG((this,LOG_CPU,0,"upper:%06o\n", value));
} else {
LOG((this,LOG_CPU,0,"lower:%06o\n", value & 0177777));
value &= 0177777;
LOG((this,LOG_CPU,0,"lower:%06o\n", value));
}
m_bus &= value;
}
@ -115,25 +125,29 @@ void alto2_cpu_device::rdram()
*/
void alto2_cpu_device::wrtram()
{
UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr);
UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr);
UINT32 value = ((m_myl << 16) | m_alu) ^ ALTO2_UCODE_INVERTED;
const UINT32 bank = GET_CRAM_BANKSEL(m_cram_addr);
const UINT32 wordaddr = GET_CRAM_WORDADDR(m_cram_addr);
const UINT32 addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; // write RAM 0,1,2
const UINT32 value = (m_myl << 16) | m_alu;
UINT32 addr = bank * ALTO2_UCODE_PAGE_SIZE + wordaddr; // write RAM 0,1,2
LOG((this,LOG_CPU,0," wrtram: RAM%d [%04o] upper:%06o lower:%06o", bank, wordaddr, m_myl, m_alu));
#if DEBUG_WRTRAM
printf("WR CRAM_BANKSEL=%d RAM%d [%04o] upper:%06o lower:%06o\n",
GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr, m_myl, m_alu);
#endif
m_wrtram_flag = false;
if (ALTO2_UCODE_RAM_BASE + addr >= ALTO2_UCODE_SIZE) {
if (m_ucode_ram_base + addr >= m_ucode_size) {
LOG((this,LOG_CPU,0," invalid address %06o\n", addr));
return;
}
LOG((this,LOG_CPU,0,"\n"));
WR_CRAM(addr, value);
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + addr * 4) = value ^ ALTO2_UCODE_INVERTED;
#if DEBUG_WRTRAM
char buffer[256];
UINT8* oprom = m_ucode_cram.get() + 4 * wordaddr;
disasm_disassemble(buffer, wordaddr, oprom, oprom, 0);
printf("WR CRAM_BANKSEL=%d RAM%d [%04o] upper:%06o lower:%06o value:%011o '%s'\n",
GET_CRAM_BANKSEL(m_cram_addr), bank, wordaddr, m_myl, m_alu,
value, buffer);
#endif
}
/**
@ -183,6 +197,9 @@ void alto2_cpu_device::bs_late_load_sreg()
void alto2_cpu_device::branch_ROM(const char *from, int page)
{
(void)from;
#if DEBUG_BRANCH
printf("SWMODE: branch from %s to ROM%d (%#o)\n", from, page, m_next2);
#endif
m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + page * ALTO2_UCODE_PAGE_SIZE;
LOG((this,LOG_RAM,2," SWMODE: branch from %s to ROM%d (%#o)\n", from, page, m_next2));
}
@ -193,7 +210,10 @@ void alto2_cpu_device::branch_ROM(const char *from, int page)
void alto2_cpu_device::branch_RAM(const char *from, int page)
{
(void)from;
m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + ALTO2_UCODE_RAM_BASE + page * ALTO2_UCODE_PAGE_SIZE;
#if DEBUG_BRANCH
printf("SWMODE: branch from %s to RAM%d (%#o)\n", from, page, m_next2);
#endif
m_next2 = (m_next2 & ALTO2_UCODE_PAGE_MASK) + m_ucode_ram_base + page * ALTO2_UCODE_PAGE_SIZE;
LOG((this,LOG_RAM,2," SWMODE: branch from %s to RAM%d\n", from, page, m_next2));
}
@ -211,147 +231,152 @@ void alto2_cpu_device::branch_RAM(const char *from, int page)
*/
void alto2_cpu_device::f1_late_swmode()
{
/* currently executing in what page? */
UINT16 current = m_mpc / ALTO2_UCODE_PAGE_SIZE;
// Currently executing in what CROM/CRAM page?
UINT16 page = m_mpc / ALTO2_UCODE_PAGE_SIZE;
UINT16 next;
#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 1)
switch (current) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_ROM("RAM0", 0);
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
}
#endif
#if (ALTO2_UCODE_ROM_PAGES == 2 && ALTO2_UCODE_RAM_PAGES == 1)
UINT16 next = X_RDBITS(m_next2,10,1,1);
switch (current) {
case 0: /* ROM0 to RAM0 or ROM1 */
switch (next) {
switch (m_cram_config) {
case 1: // 1K CROM, 1K CRAM
switch (page) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_ROM("ROM0", 1);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 1: /* ROM1 to ROM0 or RAM0 */
switch (next) {
case 0:
branch_ROM("ROM1", 0);
break;
case 1:
branch_RAM("ROM1", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 2: /* RAM0 to ROM0 or ROM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
break;
case 1:
branch_ROM("RAM0", 1);
break;
default:
fatal(1, "Impossible next %d\n", next);
fatal(1, "Impossible current mpc %u\n", page);
}
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
}
#endif
#if (ALTO2_UCODE_ROM_PAGES == 1 && ALTO2_UCODE_RAM_PAGES == 3)
UINT16 next = X_RDBITS(m_next2,10,1,2);
switch (current) {
case 0: /* ROM0 to RAM0, RAM2, RAM1, RAM0 */
switch (next) {
case 0:
branch_RAM("ROM0", 0);
case 2: // 2K CROM, 1K CRAM
next = X_RDBITS(m_next2,10,1,1);
switch (page) {
case 0: /* ROM0 to RAM0 or ROM1 */
switch (next) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_ROM("ROM0", 1);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
case 1:
branch_RAM("ROM0", 2);
case 1: /* ROM1 to ROM0 or RAM0 */
switch (next) {
case 0:
branch_ROM("ROM1", 0);
break;
case 1:
branch_RAM("ROM1", 0);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
case 2:
branch_RAM("ROM0", 1);
break;
case 3:
branch_RAM("ROM0", 0);
case 2: /* RAM0 to ROM0 or ROM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
break;
case 1:
branch_ROM("RAM0", 1);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
default:
fatal(1, "Impossible next %d\n", next);
fatal(1, "Impossible current mpc %u\n", page);
}
break;
case 1: /* RAM0 to ROM0, RAM2, RAM1, RAM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
case 3: // 1K CROM, 3K CRAM
next = X_RDBITS(m_next2,10,1,2);
switch (page) {
case 0: /* ROM0 to RAM0, RAM2, RAM1, RAM0 */
switch (next) {
case 0:
branch_RAM("ROM0", 0);
break;
case 1:
branch_RAM("ROM0", 2);
break;
case 2:
branch_RAM("ROM0", 1);
break;
case 3:
branch_RAM("ROM0", 0);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
case 1:
branch_RAM("RAM0", 2);
case 1: /* RAM0 to ROM0, RAM2, RAM1, RAM1 */
switch (next) {
case 0:
branch_ROM("RAM0", 0);
break;
case 1:
branch_RAM("RAM0", 2);
break;
case 2:
branch_RAM("RAM0", 1);
break;
case 3:
branch_RAM("RAM0", 1);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
case 2:
branch_RAM("RAM0", 1);
case 2: /* RAM1 to ROM0, RAM2, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM1", 0);
break;
case 1:
branch_RAM("RAM1", 2);
break;
case 2:
branch_RAM("RAM1", 0);
break;
case 3:
branch_RAM("RAM1", 0);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
case 3:
branch_RAM("RAM0", 1);
case 3: /* RAM2 to ROM0, RAM1, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM2", 0);
break;
case 1:
branch_RAM("RAM2", 1);
break;
case 2:
branch_RAM("RAM2", 0);
break;
case 3:
branch_RAM("RAM2", 0);
break;
default:
fatal(1, "Impossible next %u\n", next);
}
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 2: /* RAM1 to ROM0, RAM2, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM1", 0);
break;
case 1:
branch_RAM("RAM1", 2);
break;
case 2:
branch_RAM("RAM1", 0);
break;
case 3:
branch_RAM("RAM1", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
}
break;
case 3: /* RAM2 to ROM0, RAM1, RAM0, RAM0 */
switch (next) {
case 0:
branch_ROM("RAM2", 0);
break;
case 1:
branch_RAM("RAM2", 1);
break;
case 2:
branch_RAM("RAM2", 0);
break;
case 3:
branch_RAM("RAM2", 0);
break;
default:
fatal(1, "Impossible next %d\n", next);
fatal(1, "Impossible current mpc %u\n", page);
}
break;
default:
fatal(1, "Impossible current mpc %d\n", current);
fatal(1, "Impossible control ROM/RAM config %u (%u CROM pages, %u CRAM pages)\n",
m_cram_config, m_ucode_rom_pages, m_ucode_ram_pages);
}
#else
fatal(1, "Impossible control ROM/RAM combination %d/%d\n", ALTO2_UCODE_ROM_PAGES, ALTO2_UCODE_RAM_PAGES);
#endif
}
/**
@ -372,8 +397,6 @@ void alto2_cpu_device::f1_late_rdram()
LOG((this,LOG_RAM,2," RDRAM\n"));
}
#if (ALTO2_UCODE_RAM_PAGES == 3)
/**
* @brief f1_load_rmr late: load the reset mode register
*
@ -386,16 +409,17 @@ void alto2_cpu_device::f1_late_load_rmr()
LOG((this,LOG_RAM,2," RMR<-; BUS (%#o)\n", m_bus));
m_reset_mode = m_bus;
}
#else // ALTO2_UCODE_RAM_PAGES != 3
/**
* @brief f1_load_srb late: load the S register bank from BUS[12-14]
* F1=013 corresponds to SRB<- in the emulator, if the RAM size is
* just 1K. It sets the S register bank for the current task.
*/
void alto2_cpu_device::f1_late_load_srb()
{
m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14) % ALTO2_SREG_BANKS;
m_s_reg_bank[m_task] = X_RDBITS(m_bus,16,12,14) % m_sreg_banks;
LOG((this,LOG_RAM,2," SRB<-; srb[%d] := %#o\n", m_task, m_s_reg_bank[m_task]));
}
#endif
/**
* @brief RAM related task slots initialization

View File

@ -7,35 +7,8 @@
*****************************************************************************/
#ifdef ALTO2_DEFINE_CONSTANTS
#if (ALTO2_CRAM_CONFIG==1)
#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages
#elif (ALTO2_CRAM_CONFIG==2)
#define ALTO2_UCODE_ROM_PAGES 2 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 1 //!< number of microcode RAM pages
#elif (ALTO2_CRAM_CONFIG==3)
#define ALTO2_UCODE_ROM_PAGES 1 //!< number of microcode ROM pages
#define ALTO2_UCODE_RAM_PAGES 3 //!< number of microcode RAM pages
#else
#error "Undefined CROM/CRAM configuration"
#endif
/**
* \brief number of S register banks
* This depends on the number of RAM pages
* 8 pages in 3K CRAM configuration
* 1 page in 1K CRAM configurations
*/
#if (ALTO2_UCODE_RAM_PAGES == 3)
#define ALTO2_SREG_BANKS 8
#else
#define ALTO2_SREG_BANKS 1
#endif
#define ALTO2_UCODE_PAGE_SIZE 02000 //!< number of words of microcode
#define ALTO2_UCODE_PAGE_MASK (ALTO2_UCODE_PAGE_SIZE-1) //!< mask for microcode ROM/RAM address
#define ALTO2_UCODE_SIZE ((ALTO2_UCODE_ROM_PAGES + ALTO2_UCODE_RAM_PAGES) * ALTO2_UCODE_PAGE_SIZE) //!< total number of words of microcode
#define ALTO2_UCODE_RAM_BASE (ALTO2_UCODE_ROM_PAGES * ALTO2_UCODE_PAGE_SIZE) //!< base offset for the RAM page(s)
#else // ALTO2_DEFINE_CONSTANTS
#ifndef _A2RAM_H_
@ -51,11 +24,8 @@ enum {
f1_ram_swmode = f1_task_10, //!< f1 10: switch mode to CROM/CRAM in same page
f1_ram_wrtram = f1_task_11, //!< f1 11: start WRTRAM cycle
f1_ram_rdram = f1_task_12, //!< f1 12: start RDRAM cycle
#if (ALTO2_UCODE_RAM_PAGES == 3)
f1_ram_load_rmr = f1_task_13, //!< f1 13: load the reset mode register
#else // ALTO2_UCODE_RAM_PAGES != 3
f1_ram_load_srb = f1_task_13 //!< f1 14: load the S register bank from BUS[12-14]
#endif
f1_ram_load_srb = f1_task_13 //!< f1 13: load the S register bank from BUS[12-14]
};
void bs_early_read_sreg(); //!< bus source: drive bus by S register or M (MYL), if rsel is = 0
@ -66,11 +36,8 @@ void branch_RAM(const char *from, int page); //!< branch to RAM page
void f1_late_swmode(); //!< F1 func: switch to micro program counter BUS[6-15] in other bank
void f1_late_wrtram(); //!< F1 func: start WRTRAM cycle
void f1_late_rdram(); //!< F1 func: start RDRAM cycle
#if (ALTO2_UCODE_RAM_PAGES == 3)
void f1_late_load_rmr(); //!< F1 func: load the reset mode register
#else // ALTO2_UCODE_RAM_PAGES != 3
void f1_late_load_srb(); //!< F1 func: load the S register bank from BUS[12-14]
#endif
void init_ram(int task); //!< called by RAM related tasks
void exit_ram(); //!< deinitialize the RAM related tasks
void reset_ram(); //!< reset the RAM related tasks

View File

@ -60,8 +60,7 @@ alto2_log_t logprintf;
//**************************************************************************
DEVICE_ADDRESS_MAP_START( ucode_map, 32, alto2_cpu_device )
AM_RANGE(0, ALTO2_UCODE_RAM_BASE - 1) AM_READ ( crom_r )
AM_RANGE(ALTO2_UCODE_RAM_BASE, ALTO2_UCODE_SIZE - 1) AM_READWRITE( cram_r, cram_w )
AM_RANGE(0, 4*ALTO2_UCODE_PAGE_SIZE - 1) AM_READWRITE( crom_cram_r, crom_cram_w )
ADDRESS_MAP_END
DEVICE_ADDRESS_MAP_START( const_map, 16, alto2_cpu_device )
@ -126,6 +125,12 @@ alto2_cpu_device::alto2_cpu_device(const machine_config& mconfig, const char* ta
m_ucode_config("ucode", ENDIANNESS_BIG, 32, 12, -2 ),
m_const_config("const", ENDIANNESS_BIG, 16, 8, -1 ),
m_iomem_config("iomem", ENDIANNESS_BIG, 16, 17, -1 ),
m_cram_config(2),
m_ucode_rom_pages(1),
m_ucode_ram_pages(2),
m_ucode_ram_base(ALTO2_UCODE_PAGE_SIZE),
m_ucode_size(3*ALTO2_UCODE_PAGE_SIZE),
m_sreg_banks(1),
m_ucode_crom(nullptr),
m_const_data(nullptr),
m_icount(0),
@ -471,10 +476,8 @@ static const prom_load_t pl_ucode[] = {
/* dmap */ DMAP_DEFAULT,
/* dand */ KEEP,
/* type */ sizeof(UINT32)
}
#if (ALTO2_UCODE_ROM_PAGES > 1)
,
},
// NOTE: the Mesa 5.1 ucode PROM may be used as RAM, if m_cram_config == 3
{ // 02000-03777 RSEL(0)',RSEL(1)',RSEL(2)',RSEL(3)'
"xm51.u54",
nullptr,
@ -595,7 +598,6 @@ static const prom_load_t pl_ucode[] = {
/* dand */ KEEP,
/* type */ sizeof(UINT32)
}
#endif // (UCODE_ROM_PAGES > 1)
};
/**
@ -811,13 +813,14 @@ void alto2_cpu_device::device_start()
// get a pointer to the IO address space
m_iomem = &space(AS_2);
// decode ALTO2_UCODE_PAGES = 1 or 2 pages of micro code PROMs to CROM
m_ucode_crom = prom_load(machine(), pl_ucode, memregion("ucode_proms")->base(), ALTO2_UCODE_ROM_PAGES, 8);
// Decode 2 pages of micro code PROMs to CROM
// If m_cram_config == 1 or 3, only the first page will be used
m_ucode_crom = prom_load(machine(), pl_ucode, memregion("ucode_proms")->base(), 2, 8);
// allocate micro code CRAM
m_ucode_cram = std::make_unique<UINT8[]>(sizeof(UINT32) * ALTO2_UCODE_RAM_PAGES * ALTO2_UCODE_PAGE_SIZE);
// allocate micro code CRAM for max 3 pages
m_ucode_cram = std::make_unique<UINT8[]>(sizeof(UINT32) * 3 * ALTO2_UCODE_PAGE_SIZE);
// fill with the micro code inverted bits value
for (offs_t offset = 0; offset < ALTO2_UCODE_RAM_PAGES * ALTO2_UCODE_PAGE_SIZE; offset++)
for (offs_t offset = 0; offset < 3 * ALTO2_UCODE_PAGE_SIZE; offset++)
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + offset * 4) = ALTO2_UCODE_INVERTED;
// decode constant PROMs to m_const_data
@ -1015,22 +1018,20 @@ void alto2_cpu_device::state_string_export(const device_state_entry &entry, std:
}
}
//! read microcode CROM
READ32_MEMBER ( alto2_cpu_device::crom_r )
//! read microcode CROM or CRAM
READ32_MEMBER ( alto2_cpu_device::crom_cram_r )
{
return *reinterpret_cast<UINT32 *>(m_ucode_crom + offset * 4);
if (offset < m_ucode_ram_base)
return *reinterpret_cast<UINT32 *>(m_ucode_crom + offset * 4);
return *reinterpret_cast<UINT32 *>(m_ucode_cram.get() + (offset - m_ucode_ram_base) * 4);
}
//! read microcode CRAM
READ32_MEMBER ( alto2_cpu_device::cram_r )
//! write microcode CROM or CRAM (CROM of course can't be written)
WRITE32_MEMBER( alto2_cpu_device::crom_cram_w )
{
return *reinterpret_cast<UINT32 *>(m_ucode_cram.get() + offset * 4);
}
//! write microcode CRAM
WRITE32_MEMBER( alto2_cpu_device::cram_w )
{
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + offset * 4) = data;
if (offset < m_ucode_ram_base)
return;
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + (offset - m_ucode_ram_base) * 4) = data;
}
//! read constants PROM
@ -1040,9 +1041,9 @@ READ16_MEMBER ( alto2_cpu_device::const_r )
}
//! direct read access to the microcode CROM or CRAM
#define RD_UCODE(addr) (addr < ALTO2_UCODE_RAM_BASE ? \
#define RD_UCODE(addr) (addr < m_ucode_ram_base ? \
*reinterpret_cast<UINT32 *>(m_ucode_crom + addr * 4) : \
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + (addr - ALTO2_UCODE_RAM_BASE) * 4))
*reinterpret_cast<UINT32 *>(m_ucode_cram.get() + (addr - m_ucode_ram_base) * 4))
//-------------------------------------------------
// device_reset - device-specific reset
@ -1055,6 +1056,7 @@ void alto2_cpu_device::device_reset()
ioport_port* etherid = ioport(":ETHERID");
if (etherid)
m_ether_id = etherid->read() & 0377;
// call all sub-devices' reset_...
reset_memory();
reset_disp();
@ -2268,13 +2270,18 @@ UINT32 alto2_cpu_device::alu_74181(UINT32 a, UINT32 b, UINT8 smc)
/** @brief flag that tells wheter operation was 0: arithmetic (M=0) or 1: logic (M=1) */
#define ALUM A10_ALUM
/** @brief execute the CPU for at most nsecs nano seconds */
/** @brief execute the CPU for the number of cycles in m_icount */
void alto2_cpu_device::execute_run()
{
m_next = m_task_mpc[m_task]; // get current task's next mpc and address modifier
m_next2 = m_task_next2[m_task];
do {
if (m_dsp.vsync) {
// synchronizing to the vsync signal
continue;
}
m_mpc = m_next; // next instruction's micro program counter
m_mir = RD_UCODE(m_mpc); // fetch the micro code
@ -2283,15 +2290,16 @@ void alto2_cpu_device::execute_run()
debugger_instruction_hook(this, m_mpc);
m_cycle++;
if (f1() == f1_load_mar && check_mem_load_mar_stall(m_rsel)) {
LOG((this,LOG_CPU,3, " MAR<- stall\n"));
continue;
}
if (f2() == f2_load_md && check_mem_write_stall()) {
LOG((this,LOG_CPU,3, " MD<- stall\n"));
continue;
}
/*
* Bus source decoding is not performed if f1 == f1_const
* or f2 == f2_const. These functions use the MIR BS field to
@ -2320,33 +2328,32 @@ void alto2_cpu_device::execute_run()
// The constant memory is gated to the bus by F1 == f1_const, F2 == f2_const, or BS >= 4
if (!do_bs || bs() >= bs_task_4) {
const UINT32 addr = 8 * m_rsel + bs();
// FIXME: is the format of m_const_data endian safe?
const UINT16 data = m_const_data[2*addr] | (m_const_data[2*addr+1] << 8);
m_bus &= data;
LOG((this,LOG_CPU,2," %#o; BUS &= %#o CONST[%03o]\n", m_bus, data, addr));
}
/*
* early F2 function has to be called before early BS,
* Early F2 function has to be called before early BS,
* because the emulator task F2 acsource or acdest may
* change the m_rsel
* change the value of m_rsel
*/
switch (f2()) {
case f2_task_12: // f2 12 task specific
case f2_task_12: // f2 12 task specific
switch (m_task) {
case task_emu: // emulator task
f2_early_load_dns();
break;
}
break;
case f2_task_13: // f2 13 task specific
case f2_task_13: // f2 13 task specific
switch (m_task) {
case task_emu: // emulator task
f2_early_acdest();
break;
}
break;
case f2_task_16: // f2 16 task specific
case f2_task_16: // f2 16 task specific
switch (m_task) {
case task_emu: // emulator task
f2_early_acsource();
@ -2366,22 +2373,22 @@ void alto2_cpu_device::execute_run()
break;
case bs_task_3: // BUS source is task specific
switch (m_task) {
case task_emu: // emulator task
case task_emu: // emulator task
bs_early_read_sreg();
break;
case task_ksec: // disk sector task
case task_kwd: // disk word task
case task_ksec: // disk sector task
case task_kwd: // disk word task
bs_early_read_kstat();
break;
case task_ether: // ethernet task
case task_ether: // ethernet task
bs_early_eidfct();
break;
case task_mrt: // memory refresh task
case task_dwt: // display word task
case task_curt: // cursor task
case task_dht: // display horizontal task
case task_dvt: // display vertical task
case task_part: // parity task
case task_mrt: // memory refresh task
case task_dwt: // display word task
case task_curt: // cursor task
case task_dht: // display horizontal task
case task_dvt: // display vertical task
case task_part: // parity task
break;
default:
bs_early_bad();
@ -2389,20 +2396,20 @@ void alto2_cpu_device::execute_run()
break;
case bs_task_4: // BUS source is task specific
switch (m_task) {
case task_emu: // emulator task
case task_emu: // emulator task
bs_early_load_sreg();
break;
case task_ksec: // disk sector task
case task_kwd: // disk word task
case task_ksec: // disk sector task
case task_kwd: // disk word task
bs_early_read_kdata();
break;
case task_ether: // ethernet task
case task_mrt: // memory refresh task
case task_dwt: // display word task
case task_curt: // cursor task
case task_dht: // display horizontal task
case task_dvt: // display vertical task
case task_part: // parity task
case task_ether: // ethernet task
case task_mrt: // memory refresh task
case task_dwt: // display word task
case task_curt: // cursor task
case task_dht: // display horizontal task
case task_dvt: // display vertical task
case task_part: // parity task
break;
default:
bs_early_bad();
@ -2414,9 +2421,9 @@ void alto2_cpu_device::execute_run()
case bs_mouse: // BUS source is mouse data
bs_early_mouse();
break;
case bs_disp: // BUS source displacement (emulator task)
case bs_disp: // BUS source displacement (emulator task)
switch (m_task) {
case task_emu: // emulator task
case task_emu: // emulator task
bs_early_emu_disp();
break;
default:
@ -2428,10 +2435,10 @@ void alto2_cpu_device::execute_run()
// early F1 function
switch (f1()) {
case f1_task: // f1 02 task switch
case f1_task: // f1 02 task switch
f1_early_task();
break;
case f1_block: // f1 03 task block
case f1_block: // f1 03 task block
switch (m_task) {
case task_emu: // emulator task
f1_early_emu_block();
@ -2466,28 +2473,28 @@ void alto2_cpu_device::execute_run()
}
break;
case f1_task_13: // f1 13 task specific
case f1_task_13: // f1 13 task specific
switch (m_task) {
case task_ether: // ethernet task
f1_early_eilfct();
break;
}
break;
case f1_task_14: // f1 14 task specific
case f1_task_14: // f1 14 task specific
switch (m_task) {
case task_ether: // ethernet task
f1_early_epfct();
break;
}
break;
case f1_task_16: // f1 16 task specific
case f1_task_16: // f1 16 task specific
switch (m_task) {
case task_emu: // emulator task
f1_early_rsnf();
break;
}
break;
case f1_task_17: // f1 17 task specific
case f1_task_17: // f1 17 task specific
switch (m_task) {
case task_emu: // emulator task
f1_early_startf();
@ -2520,27 +2527,27 @@ void alto2_cpu_device::execute_run()
// late F1 function call now
switch (f1()) {
case f1_load_mar: // f1 01 load memory address register
case f1_load_mar: // f1 01 load memory address register
f1_late_load_mar();
break;
case f1_l_lsh_1: // f1 04 left shift L once
case f1_l_lsh_1: // f1 04 left shift L once
f1_late_l_lsh_1();
break;
case f1_l_rsh_1: // f1 05 right shift L once
case f1_l_rsh_1: // f1 05 right shift L once
f1_late_l_rsh_1();
break;
case f1_l_lcy_8: // f1 06 cycle L 8 times
case f1_l_lcy_8: // f1 06 cycle L 8 times
f1_late_l_lcy_8();
break;
case f1_task_10: // f1 10 task specific
case f1_task_10: // f1 10 task specific
switch (m_task) {
case task_emu: // emulator task
f1_late_swmode();
break;
}
break;
case f1_task_11: // f1 11 task specific
case f1_task_11: // f1 11 task specific
switch (m_task) {
case task_emu: // emulator task
f1_late_wrtram();
@ -2551,7 +2558,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_12: // f1 12 task specific
case f1_task_12: // f1 12 task specific
switch (m_task) {
case task_emu: // emulator task
f1_late_rdram();
@ -2562,14 +2569,13 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_13: // f1 13 task specific
case f1_task_13: // f1 13 task specific
switch (m_task) {
case task_emu: // emulator task
#if (ALTO2_UCODE_RAM_PAGES == 3)
f1_late_load_rmr();
#else
f1_late_load_srb();
#endif
if (m_cram_config == 3) // 3K CRAM available?
f1_late_load_rmr();
else
f1_late_load_srb();
break;
case task_ksec: // disk sector task
case task_kwd: // disk word task
@ -2577,7 +2583,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_14: // f1 14 task specific
case f1_task_14: // f1 14 task specific
switch (m_task) {
case task_ksec: // disk sector task
case task_kwd: // disk word task
@ -2585,7 +2591,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_15: // f1 15 task specific
case f1_task_15: // f1 15 task specific
switch (m_task) {
case task_emu: // emulator task
f1_late_emu_load_esrb();
@ -2599,7 +2605,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_16: // f1 16 task specific
case f1_task_16: // f1 16 task specific
switch (m_task) {
case task_ksec: // disk sector task
case task_kwd: // disk word task
@ -2607,7 +2613,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f1_task_17: // f1 17 task specific
case f1_task_17: // f1 17 task specific
switch (m_task) {
case task_ksec: // disk sector task
case task_kwd: // disk word task
@ -2619,26 +2625,26 @@ void alto2_cpu_device::execute_run()
// late F2 function call now
switch (f2()) {
case f2_bus_eq_zero: // f2 01 branch on bus equals 0
case f2_bus_eq_zero: // f2 01 branch on bus equals 0
f2_late_bus_eq_zero();
break;
case f2_shifter_lt_zero: // f2 02 branch on shifter less than 0
case f2_shifter_lt_zero: // f2 02 branch on shifter less than 0
f2_late_shifter_lt_zero();
break;
case f2_shifter_eq_zero: // f2 03 branch on shifter equals 0
case f2_shifter_eq_zero: // f2 03 branch on shifter equals 0
f2_late_shifter_eq_zero();
break;
case f2_bus: // f2 04 branch on BUS[6-15]
case f2_bus: // f2 04 branch on BUS[6-15]
f2_late_bus();
break;
case f2_alucy: // f2 05 branch on (latched) ALU carry
case f2_alucy: // f2 05 branch on (latched) ALU carry
f2_late_alucy();
break;
case f2_load_md: // f2 06 load memory data
case f2_load_md: // f2 06 load memory data
f2_late_load_md();
break;
case f2_task_10: // f2 10 task specific
case f2_task_10: // f2 10 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_busodd();
@ -2651,7 +2657,7 @@ void alto2_cpu_device::execute_run()
f2_late_eodfct();
break;
case task_dwt: // display word task
f2_late_dwt_load_ddr();
f2_late_load_ddr();
break;
case task_curt: // cursor task
f2_late_load_xpreg();
@ -2664,7 +2670,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_11: // f2 11 task specific
case f2_task_11: // f2 11 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_magic();
@ -2684,7 +2690,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_12: // f2 12 task specific
case f2_task_12: // f2 12 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_load_dns();
@ -2698,7 +2704,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_13: // f2 13 task specific
case f2_task_13: // f2 13 task specific
switch (m_task) {
case task_ksec: // disk sector task
case task_kwd: // disk word task
@ -2709,7 +2715,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_14: // f2 14 task specific
case f2_task_14: // f2 14 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_load_ir();
@ -2723,7 +2729,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_15: // f2 15 task specific
case f2_task_15: // f2 15 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_idisp();
@ -2737,7 +2743,7 @@ void alto2_cpu_device::execute_run()
break;
}
break;
case f2_task_16: // f2 16 task specific
case f2_task_16: // f2 16 task specific
switch (m_task) {
case task_emu: // emulator task
f2_late_acsource();
@ -2761,7 +2767,7 @@ void alto2_cpu_device::execute_run()
break;
case bs_task_4: // BUS source is task specific
switch (m_task) {
case task_emu: // emulator task
case task_emu: // emulator task
bs_late_load_sreg();
break;
}
@ -2771,7 +2777,7 @@ void alto2_cpu_device::execute_run()
// update T register, if LOADT is set
if (loadt()) {
m_cram_addr = m_alu; // latch CRAM address
m_cram_addr = m_alu; // latch CRAM address
if (flags & TSELECT) {
m_t = m_alu; // T source is ALU
LOG((this,LOG_CPU,2, " T<- ALU (%#o)\n", m_alu));
@ -2783,7 +2789,7 @@ void alto2_cpu_device::execute_run()
// update L register and LALUC0 if LOADL is set
if (loadl()) {
m_l = m_alu; // load L from ALU
m_l = m_alu; // load L from ALU
if (flags & ALUM) {
m_laluc0 = 0; // logic operation - put 0 into latched carry
LOG((this,LOG_CPU,2, " L<- ALU (%#o); LALUC0<- %o\n", m_alu, 0));
@ -2794,7 +2800,8 @@ void alto2_cpu_device::execute_run()
// update M (MYL) register, if a RAM related task is active
if (m_ram_related[m_task]) {
m_myl = m_alu; // load M from ALU, if 'GOODTASK'
m_s[m_s_reg_bank[m_task]][0] = m_alu; // also writes to S[bank][0], which can't be read
// also writes to S[_task][0], which can't be read
m_s[m_s_reg_bank[m_task]][0] = m_alu;
LOG((this,LOG_CPU,2, " M<- ALU (%#o)\n", m_alu));
}
}
@ -2811,14 +2818,19 @@ void alto2_cpu_device::execute_run()
m_task_next2[m_task] = m_next2;
m_task = m_next_task;
LOG((this,LOG_CPU,1, "task switch to %02o:%s (cycle %lld)\n", m_task, task_name(m_task), cycle()));
m_next = m_task_mpc[m_task]; // get new task's mpc
m_next2 = m_task_next2[m_task]; // get address modifier after task switch (needed?)
// Get the new task's mpc
m_next = m_task_mpc[m_task];
// Get address modifier after task switch.
m_next2 = m_task_next2[m_task];
// let the task know it becomes active now and (most probably) reset the wakeup
// Let the task know it becomes active now and
// (most probably) reset the wakeup
switch (m_task) {
case task_emu: // emulator task
// No activate_emu();
break;
case task_ksec: // disk sector task
// No activate_ksec();
break;
case task_ether: // ethernet task
activate_eth();
@ -2827,6 +2839,7 @@ void alto2_cpu_device::execute_run()
activate_mrt();
break;
case task_dwt: // display word task
// No activate_dwt();
break;
case task_curt: // cursor task
activate_curt();
@ -2841,6 +2854,7 @@ void alto2_cpu_device::execute_run()
activate_part();
break;
case task_kwd: // disk word task
// No activate_kwd();
break;
}
}
@ -2849,8 +2863,8 @@ void alto2_cpu_device::execute_run()
if (m_dsp_time >= 0) {
/**
* Subtract the microcycle time from the display time accu.
* If it underflows, call the display state machine and add
* the time for 32(!) pixel clocks to the accu.
* If it underflows, call the display state machine which
* adds the time for 32 pixel clocks to the accu.
* This is very close to every seventh CPU cycle
*/
m_dsp_time -= ALTO2_UCYCLE;
@ -2863,7 +2877,7 @@ void alto2_cpu_device::execute_run()
* Subtract the microcycle time from the unload time accu.
* If it underflows, call the unload word function which adds
* the time for 16 or 32 pixel clocks to the accu, or ends
* the unloading by leaving m_unload_time at -1.
* the FIFO unloading by leaving m_unload_time at -1.
*/
m_unload_time -= ALTO2_UCYCLE;
if (m_unload_time < 0)
@ -2874,7 +2888,7 @@ void alto2_cpu_device::execute_run()
/**
* Subtract the microcycle time from the bitclk time accu.
* If it underflows, call the disk bitclk function which adds
* the time for one bit as clocks to the accu, or ends
* the time for one bit as clock cycles to the accu, or ends
* the bitclk sequence by leaving m_bitclk_time at -1.
*/
m_bitclk_time -= ALTO2_UCYCLE;
@ -2882,7 +2896,7 @@ void alto2_cpu_device::execute_run()
}
} while (m_icount-- > 0);
/* save this task's mpc and address modifier */
// Save this task's mpc and address modifier
m_task_mpc[m_task] = m_next;
m_task_next2[m_task] = m_next2;
}
@ -2900,7 +2914,7 @@ void alto2_cpu_device::hard_reset()
// every task starts at mpc = task number, in either ROM0 or RAM0
m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017;
if (0 == (m_reset_mode & (1 << task)))
m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE;
m_task_mpc[task] |= m_ucode_ram_base;
}
init_memory();
@ -2931,11 +2945,36 @@ void alto2_cpu_device::hard_reset()
/** @brief software initiated reset (STARTF) */
void alto2_cpu_device::soft_reset()
{
// Setup the CROM and CRAM configuration
ioport_port* config = ioport(":CONFIG");
if (config)
m_cram_config = (config->read() >> 1) & 3;
switch (m_cram_config) {
case 0: // invalid, default to 1
case 1: // 1K CROM, 1K CRAM, 1 S register bank
m_ucode_rom_pages = 1;
m_ucode_ram_pages = 1;
m_sreg_banks = 1;
break;
case 2: // 2K CROM, 1K CRAM, 1 S register bank
m_ucode_rom_pages = 2;
m_ucode_ram_pages = 1;
m_sreg_banks = 1;
break;
case 3: // 1K CROM, 3K CRAM, 8 S register banks
m_ucode_rom_pages = 1;
m_ucode_ram_pages = 3;
m_sreg_banks = 8;
break;
}
m_ucode_ram_base = m_ucode_rom_pages * ALTO2_UCODE_PAGE_SIZE;
m_ucode_size = (m_ucode_rom_pages + m_ucode_ram_pages) * ALTO2_UCODE_PAGE_SIZE;
for (int task = 0; task < ALTO2_TASKS; task++) {
// every task starts at mpc = task number, in either ROM0 or RAM0
m_task_mpc[task] = (m_ctl2k_u38[task] >> 4) ^ 017;
if (0 == (m_reset_mode & (1 << task)))
m_task_mpc[task] |= ALTO2_UCODE_RAM_BASE;
m_task_mpc[task] |= m_ucode_ram_base;
}
m_next2_task = task_emu; // switch to task 0 (emulator)
m_reset_mode = 0xffff; // all tasks start in ROM0 again

View File

@ -46,11 +46,6 @@ enum {
#define ALTO2_DEBUG 1
#endif
#ifndef ALTO2_CRAM_CONFIG
//! Use default CROM/CRAM configuration 2.
#define ALTO2_CRAM_CONFIG 2
#endif
//!< Define to 1 to use the F9318 priority encoder code (broken).
#define USE_PRIO_F9318 0
@ -200,9 +195,6 @@ public:
//! update the screen bitmap
UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
//! screen VBLANK handler
void screen_eof(screen_device &screen, bool state);
DECLARE_ADDRESS_MAP( ucode_map, 32 );
DECLARE_ADDRESS_MAP( const_map, 16 );
DECLARE_ADDRESS_MAP( iomem_map, 16 );
@ -255,18 +247,22 @@ private:
address_space* m_iomem;
UINT32 m_cram_config; //!< CROM/CRAM configuration (1 .. 3)
UINT32 m_ucode_rom_pages; //!< Number of CROM pages; derived from m_cram_config
UINT32 m_ucode_ram_pages; //!< Number of CRAM pages; derived from m_cram_config
UINT32 m_ucode_ram_base; //!< Base offset of the CRAM addresses
UINT32 m_ucode_size; //!< Size of both, CROM and CRAM together
UINT32 m_sreg_banks; //!< Number of S register banks; derived from m_cram_config
UINT8* m_ucode_crom;
std::unique_ptr<UINT8[]> m_ucode_cram;
UINT8* m_const_data;
//! read microcode CROM
DECLARE_READ32_MEMBER ( crom_r );
//! read microcode CROM or CRAM, depending on m_ucode_ram_base
DECLARE_READ32_MEMBER ( crom_cram_r );
//! read microcode CRAM
DECLARE_READ32_MEMBER ( cram_r );
//! write microcode CRAM
DECLARE_WRITE32_MEMBER( cram_w );
//! write microcode CRAM, depending on m_ucode_ram_base (ignore writes to CROM)
DECLARE_WRITE32_MEMBER( crom_cram_w );
//! read constants PROM
DECLARE_READ16_MEMBER ( const_r );
@ -568,7 +564,7 @@ private:
UINT16 m_next; //!< current micro instruction's next
UINT16 m_next2; //!< next micro instruction's next
UINT16 m_r[ALTO2_REGS]; //!< R register file
UINT16 m_s[ALTO2_SREG_BANKS][ALTO2_REGS]; //!< S register file(s)
UINT16 m_s[8][ALTO2_REGS]; //!< S register file(s) (1 or 8 are used)
UINT16 m_bus; //!< wired-AND bus
UINT16 m_t; //!< T register
UINT16 m_alu; //!< the current ALU

View File

@ -344,7 +344,7 @@ offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8
break;
case 7: // put the constant from PROM (RSELECT,BS) on the bus
pa = (rsel << 3) | bs;
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o", const_prom[pa]);
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-%05o ", const_prom[pa]);
break;
default:
dst += snprintf(dst, len - (size_t)(dst - buffer), "F1_%02o ", f1);
@ -386,6 +386,8 @@ offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8
dst += snprintf(dst, len - (size_t)(dst - buffer), "BUS<-F2_%02o ", f2);
break;
}
if (dst > buffer && dst[-1] == ' ')
*--dst = '\0';
return result;
}

View File

@ -162,6 +162,11 @@ static INPUT_PORTS_START( alto2 )
PORT_CONFNAME( 0x01, 0x01, "Memory switch")
PORT_CONFSETTING( 0x00, "on")
PORT_CONFSETTING( 0x01, "off")
PORT_CONFNAME( 0x06, 0x02, "CROM/CRAM configuration")
PORT_CONFSETTING( 0x00, "Invalid (no CROM/CRAM)")
PORT_CONFSETTING( 0x02, "1K CROM, 1K CRAM")
PORT_CONFSETTING( 0x04, "2K CROM, 1K CRAM")
PORT_CONFSETTING( 0x06, "1K CROM, 3K CRAM")
PORT_CONFNAME( 0x70, 0x00, "Ethernet breath-of-life")
PORT_CONFSETTING( 0x00, "off")
PORT_CONFSETTING( 0x10, "5 seconds")
@ -252,7 +257,7 @@ ROM_END
//**************************************************************************
ADDRESS_MAP_START( alto2_ucode_map, AS_0, 32, alto2_state )
AM_RANGE(0, ALTO2_UCODE_SIZE-1) AM_DEVICE32( "maincpu", alto2_cpu_device, ucode_map, 0xffffffffUL )
AM_RANGE(0, 4*ALTO2_UCODE_PAGE_SIZE-1) AM_DEVICE32( "maincpu", alto2_cpu_device, ucode_map, 0xffffffffUL )
ADDRESS_MAP_END
ADDRESS_MAP_START( alto2_const_map, AS_1, 16, alto2_state )
@ -275,12 +280,14 @@ static MACHINE_CONFIG_START( alto2, alto2_state )
/* video hardware */
MCFG_SCREEN_ADD_MONOCHROME("screen", RASTER, rgb_t::white)
MCFG_SCREEN_RAW_PARAMS(XTAL_20_16MHz,
ALTO2_DISPLAY_TOTAL_WIDTH, 0, ALTO2_DISPLAY_WIDTH,
ALTO2_DISPLAY_TOTAL_HEIGHT, 0, ALTO2_DISPLAY_HEIGHT)
MCFG_SCREEN_REFRESH_RATE(30) // two interlaced fields
MCFG_SCREEN_VBLANK_TIME(ALTO2_DISPLAY_VBLANK_TIME)
ALTO2_DISPLAY_TOTAL_WIDTH,
0,
ALTO2_DISPLAY_WIDTH,
ALTO2_DISPLAY_TOTAL_HEIGHT,
16, // some scalines of vblank period before
16+ALTO2_DISPLAY_HEIGHT+8) // and after the usual range
MCFG_SCREEN_REFRESH_RATE(30) // two interlaced fields at 60Hz
MCFG_SCREEN_UPDATE_DEVICE("maincpu", alto2_cpu_device, screen_update)
MCFG_SCREEN_VBLANK_DEVICE("maincpu", alto2_cpu_device, screen_eof)
MCFG_SCREEN_PALETTE("palette")
MCFG_DEFAULT_LAYOUT( layout_vertical )