/*
RM 380Z video code
*/
#include "includes/rm380z.h"
void rm380z_state::put_point(int charnum,int x,int y,int col)
{
int mx=3;
if (y==6) mx=4;
for (int r=y;r<(y+mx);r++)
{
for (int c=x;c<(x+3);c++)
{
m_graphic_chars[charnum][c+(r*(RM380Z_CHDIMX+1))]=col;
}
}
}
void rm380z_state::init_graphic_chars()
{
for (int c=0;c<0x3f;c++)
{
if (c&0x01) put_point(c,0,0,1);
else put_point(c,0,0,0);
if (c&0x02) put_point(c,3,0,1);
else put_point(c,3,0,0);
if (c&0x04) put_point(c,0,3,1);
else put_point(c,0,3,0);
if (c&0x08) put_point(c,3,3,1);
else put_point(c,3,3,0);
if (c&0x10) put_point(c,0,6,1);
else put_point(c,0,6,0);
if (c&0x20) put_point(c,3,6,1);
else put_point(c,3,6,0);
}
}
void rm380z_state::config_videomode()
{
if (m_port0&0x20)
{
// 80 cols
m_videomode=RM380Z_VIDEOMODE_80COL;
}
else
{
// 40 cols
m_videomode=RM380Z_VIDEOMODE_40COL;
}
if (m_old_videomode!=m_videomode)
{
m_old_videomode=m_videomode;
}
}
// char attribute bits in COS 4.0
// 0=alternate charset
// 1=underline
// 2=dim
// 3=reverse
void rm380z_state::decode_videoram_char(int pos,UINT8& chr,UINT8& attrib)
{
UINT8 ch1=m_vramchars[pos];
UINT8 ch2=m_vramattribs[pos];
// "special" (unknown) cases first
if ((ch1==0x80)&&(ch2==0x04))
{
// blank out
chr=0x20;
attrib=0;
return;
}
else if ((ch1==0)&&(ch2==8))
{
// cursor
chr=0x20;
attrib=8;
return;
}
else if ((ch1==0)&&(ch2==0))
{
// delete char (?)
chr=0x20;
attrib=0;
return;
}
else if ((ch1==4)&&(ch2==4))
{
// reversed cursor?
chr=0x20;
attrib=0;
return;
}
else if ((ch1==4)&&(ch2==8))
{
// normal cursor
chr=0x20;
attrib=8;
return;
}
else
{
chr=ch1;
attrib=ch2;
//printf("unhandled character combination [%x][%x]\n",ch1,ch2);
}
}
void rm380z_state::scroll_videoram()
{
rm380z_state *state = machine().driver_data<rm380z_state>();
int lineWidth=0x80;
if (m_videomode==RM380Z_VIDEOMODE_40COL)
{
lineWidth=0x40;
}
// scroll up one row of videoram
for (int row=1;row<RM380Z_SCREENROWS;row++)
{
for (int c=0;c<lineWidth;c++)
{
int sourceaddr=(row*lineWidth)+c;
int destaddr=((row-1)*lineWidth)+c;
state->m_vram[destaddr]=state->m_vram[sourceaddr];
state->m_vramchars[destaddr]=state->m_vramchars[sourceaddr];
state->m_vramattribs[destaddr]=state->m_vramattribs[sourceaddr];
}
}
// the last line is filled with spaces
for (int c=0;c<lineWidth;c++)
{
state->m_vram[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x20;
state->m_vramchars[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x20;
state->m_vramattribs[((RM380Z_SCREENROWS-1)*lineWidth)+c]=0x00;
}
}
void rm380z_state::check_scroll_register()
{
UINT8 r[3];
r[0]=m_old_old_fbfd;
r[1]=m_old_fbfd;
r[2]=m_fbfd;
if ( ((r[1]&0x20)==0) && ((r[2]&0x20)==0) )
{
// it's a scroll command
if (r[2]>r[1])
{
scroll_videoram();
}
else if ((r[2]==0x00)&&(r[1]==0x17))
{
// wrap-scroll
scroll_videoram();
}
}
}
// after ctrl-L (clear screen?): routine at EBBD is executed
// EB30??? next line?
// memory at FF02 seems to hold the line counter (same as FBFD)
//
// basics:
// 20e2: prints "Ready:"
// 0195: prints "\n"
WRITE8_MEMBER( rm380z_state::videoram_write )
{
rm380z_state *state = machine().driver_data<rm380z_state>();
//printf("vramw [%2.2x][%2.2x] port0 [%2.2x] fbfd [%2.2x] fbfe [%2.2x] PC [%4.4x]\n",offset,data,state->m_port0,m_fbfd,m_fbfe,m_maincpu->safe_pc());
int lineWidth=0x80;
if (m_videomode==RM380Z_VIDEOMODE_40COL)
{
lineWidth=0x40;
}
int rowadder=(m_fbfe&0x0f)*2;
if (m_videomode==RM380Z_VIDEOMODE_40COL) rowadder=0; // FBFE register is not used in VDU-40
int lineAdder=rowadder*lineWidth;
int realA=(offset+lineAdder);
// we suppose videoram is being written as character/attribute couple
// fbfc 6th bit set=attribute, unset=char
if (!(state->m_port0&0x40))
{
m_vramchars[realA%RM380Z_SCREENSIZE]=data;
}
else
{
m_vramattribs[realA%RM380Z_SCREENSIZE]=data;
}
//
state->m_mainVideoram[offset]=data;
}
READ8_MEMBER( rm380z_state::videoram_read )
{
rm380z_state *state = machine().driver_data<rm380z_state>();
return state->m_mainVideoram[offset];
}
void rm380z_state::putChar(int charnum,int attribs,int x,int y,bitmap_ind16 &bitmap,unsigned char* chsb,int vmode)
{
//bool attrDim=false;
bool attrRev=false;
bool attrUnder=false;
if (attribs&0x02) attrUnder=true;
//if (attribs&0x04) attrDim=true;
if (attribs&0x08) attrRev=true;
if ((charnum>0)&&(charnum<=0x7f))
{
// normal chars (base set)
if (vmode==RM380Z_VIDEOMODE_80COL)
{
int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
for (int r=0;r<RM380Z_CHDIMY;r++)
{
for (int c=0;c<RM380Z_CHDIMX;c++)
{
UINT8 chval=(chsb[((basey+r)*(RM380Z_CHDIMX*RM380Z_NCX))+(basex+c)])==0xff?0:1;
if (attrRev)
{
if (chval==0) chval=1;
else chval=0;
}
if (attrUnder)
{
if (r==(RM380Z_CHDIMY-1))
{
if (attrRev) chval=0;
else chval=1;
}
}
UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c);
*dest=chval;
}
}
// last pixel of underline
if (attrUnder&&(!attrRev))
{
UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+(RM380Z_CHDIMY-1),(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX);
*dest=attrRev?0:1;
}
// if reversed, print another column of pixels on the right
if (attrRev)
{
for (int r=0;r<RM380Z_CHDIMY;r++)
{
UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+RM380Z_CHDIMX);
*dest=1;
}
}
}
else if (vmode==RM380Z_VIDEOMODE_40COL)
{
int basex=RM380Z_CHDIMX*(charnum/RM380Z_NCY);
int basey=RM380Z_CHDIMY*(charnum%RM380Z_NCY);
for (int r=0;r<RM380Z_CHDIMY;r++)
{
for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
{
UINT8 chval=(chsb[((basey+r)*(RM380Z_CHDIMX*RM380Z_NCX))+(basex+(c/2))])==0xff?0:1;
if (attrRev)
{
if (chval==0) chval=1;
else chval=0;
}
if (attrUnder)
{
if (r==(RM380Z_CHDIMY-1))
{
if (attrRev) chval=0;
else chval=1;
}
}
UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c);
UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1);
*dest=chval;
*dest2=chval;
}
}
// last 2 pixels of underline
if (attrUnder)
{
UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2));
UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+RM380Z_CHDIMY-1 , ((x*(RM380Z_CHDIMX+1))*2)+(RM380Z_CHDIMX*2)+1);
*dest=attrRev?0:1;
*dest2=attrRev?0:1;
}
// if reversed, print another 2 columns of pixels on the right
if (attrRev)
{
for (int r=0;r<RM380Z_CHDIMY;r++)
{
UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2));
UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+((RM380Z_CHDIMX)*2)+1);
*dest=1;
*dest2=1;
}
}
}
}
else
{
// graphic chars: 0x80-0xbf is "dimmed", 0xc0-0xff is full bright
if (vmode==RM380Z_VIDEOMODE_80COL)
{
for (int r=0;r<(RM380Z_CHDIMY+1);r++)
{
for (int c=0;c<RM380Z_CHDIMX;c++)
{
UINT16 *dest=&bitmap.pix16((y*(RM380Z_CHDIMY+1))+r,(x*(RM380Z_CHDIMX+1))+c);
*dest=m_graphic_chars[charnum&0x3f][c+(r*(RM380Z_CHDIMX+1))];
}
}
}
else
{
for (int r=0;r<RM380Z_CHDIMY;r++)
{
for (int c=0;c<(RM380Z_CHDIMX*2);c+=2)
{
UINT16 *dest=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c);
UINT16 *dest2=&bitmap.pix16( (y*(RM380Z_CHDIMY+1))+r,((x*(RM380Z_CHDIMX+1))*2)+c+1);
*dest=m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
*dest2=m_graphic_chars[charnum&0x3f][(c/2)+(r*(RM380Z_CHDIMX+1))];
}
}
}
}
}
void rm380z_state::update_screen(bitmap_ind16 &bitmap)
{
unsigned char* pChar=memregion("chargen")->base();
int lineWidth=0x80;
int ncols=80;
if (m_videomode==RM380Z_VIDEOMODE_40COL)
{
lineWidth=0x40;
ncols=40;
}
// blank screen
bitmap.fill(0);
for (int row=0;row<RM380Z_SCREENROWS;row++)
{
for (int col=0;col<ncols;col++)
{
UINT8 curch,attribs;
decode_videoram_char((row*lineWidth)+col,curch,attribs);
putChar(curch,attribs,col,row,bitmap,pChar,m_videomode);
//putChar(0x44,0x00,10,10,bitmap,pChar,m_videomode);
}
}
}