#include "rendition.h"
#include "v1krisc.h"
#include "vos.h"
#define RISC_FLAG 37
#define RISC_SP 252
#define RISC_IRA 253
#define RISC_RA 254
#define RISC_FP 255
#define NOP_INSTR 0x00000000
#define ADDI_OP 0x00
#define SPRI_OP 0x4f
#define ADD_OP 0x10
#define ANDN_OP 0x12
#define OR_OP 0x15
#define ADDIFI_OP 0x40
#define ADDSL8_OP 0x4b
#define LB_OP 0x70
#define LH_OP 0x71
#define LW_OP 0x72
#define LI_OP 0x76
#define LUI_OP 0x77
#define SB_OP 0x78
#define SH_OP 0x79
#define SW_OP 0x7a
#define JMP_OP 0x6c
#define INT_INSTR(op, d, s2, s1) \
(((vu32)(op)<<24) | ((vu32)(d)<<16) | ((vu32)(s2)<<8) | ((vu32)(s1)&0xff))
#define STR_INSTR(op, off8, s2, s1) \
(((vu32)(op)<<24) | (((vu32)(off8)&0xff)<<16) | ((vu32)(s2)<<8) | ((vu32)(s1)))
#define LD_INSTR(op, d, off8, s1) \
(((vu32)(op)<<24) | ((vu32)(d)<<16) | (((vu32)(off8)&0xff)<<8) | ((vu32)(s1)))
#define LI_INSTR(op, d, immed16) \
(((vu32)(op)<<24) | ((vu32)(d)<<16) | ((vu32)(immed16)&0xffff))
#define BR_INSTR(op, off16, s1) \
(((vu32)(op)<<24) | (((vu32)(off16)&0xffff)<<8) | ((vu32)(s1)))
#define JMP_INSTR(op, addr24) \
(((vu32)(op)<<24) | ((vu32)(addr24)))
#define TYPEINSTR 0xf0000000
#define TYPEBRANCH 0x60000000
#define HALTBIT 0x00000008
#define VBIOS_DTNR 0x2000
#define READ_BYTE 0
#define READ_SHORT 1
#define READ_WORD 2
#define WRITE_BYTE 0
#define WRITE_SHORT 1
#define WRITE_WORD 2
#define VERITE_MAX_POLLS 100
static void verite_iopoll(IOADDRESS port, vu32 data, vu32 mask);
static void verite_iopoll8(IOADDRESS port, vu8 data, vu8 mask);
static vu32 readRF(IOADDRESS io_base, vu8 index);
static void writeRF(IOADDRESS io_base, vu8 index, vu32 data);
static vu32 risc_readmem(IOADDRESS io_base, vu32 addr, vu8 read_type);
static void risc_writemem(IOADDRESS io_base, vu32 addr, vu32 data, vu8 write_type);
#if 0
static void risc_step(IOADDRESS io_base, vu32 count);
#endif
static void risc_forcestep(IOADDRESS io_base, vu32 instruction);
static void risc_continue(IOADDRESS io_base);
void
v1k_start(ScrnInfoPtr pScreenInfo, vu32 pc)
{
renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
IOADDRESS io_base=pRendition->board.io_base;
v1k_stop(pScreenInfo);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, JMP_INSTR(JMP_OP, pc>>2));
risc_forcestep(io_base, NOP_INSTR);
v1k_continue(pScreenInfo);
}
void
v1k_continue(ScrnInfoPtr pScreenInfo)
{
renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
risc_continue(pRendition->board.io_base);
}
void
v1k_stop(ScrnInfoPtr pScreenInfo)
{
renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
vu8 debugreg, statusreg;
IOADDRESS io_base=pRendition->board.io_base;
vu16 STATUS = 0x4A;
int c;
debugreg=verite_in8(io_base+DEBUGREG);
if (pRendition->board.chip == V2000_DEVICE){
c=0;
do {
statusreg = verite_in8(io_base+STATUS);
if ((statusreg & 0x8C) == 0x8C)
break;
} while (c++<0xfffff);
if (c >= 0xfffff)
xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
("Status timeout (1)\n"));
verite_out8(io_base+DEBUGREG, debugreg|HOLDRISC);
if (pRendition->board.chip == V2000_DEVICE){
c=0;
do {
statusreg = verite_in8(io_base+STATUS);
if (statusreg & HOLDRISC) break;
} while (c++<0xfffff);
if (c >= 0xfffff)
xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR,
("Status timeout (2)\n"));
}
}
else {
verite_out8(io_base+DEBUGREG, debugreg|HOLDRISC);
verite_iopoll(io_base+STATEDATA, 0, 0);
verite_iopoll(io_base+STATEDATA, 0, 0);
verite_iopoll(io_base+STATEDATA, 0, 0);
}
}
void
v1k_flushicache(ScrnInfoPtr pScreenInfo)
{
renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
vu32 c, p1, p2;
IOADDRESS io_base=pRendition->board.io_base;
p1=risc_readmem(io_base, 0, READ_WORD);
p2=risc_readmem(io_base, 8, READ_WORD);
risc_writemem(io_base, 0, p1, WRITE_WORD);
risc_writemem(io_base, 8, p2, WRITE_WORD);
(void)risc_readmem(io_base, 0, READ_WORD);
(void)risc_readmem(io_base, 8, READ_WORD);
risc_forcestep(io_base, INT_INSTR(SPRI_OP, 0, 0, 31));
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
writeRF(io_base, RISC_RA, ICACHE_ONOFF_MASK);
risc_forcestep(io_base, INT_INSTR(OR_OP, RISC_FLAG, RISC_FLAG, RISC_RA));
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
for (c=0; c<ICACHESIZE*2; c+=ICACHELINESIZE)
risc_forcestep(io_base, JMP_INSTR(JMP_OP, c>>2));
writeRF(io_base, RISC_RA, ICACHE_ONOFF_MASK);
risc_forcestep(io_base, INT_INSTR(ANDN_OP, RISC_FLAG, RISC_FLAG, RISC_RA));
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, JMP_INSTR(JMP_OP, 0));
risc_forcestep(io_base, NOP_INSTR);
}
void
v1k_softreset(ScrnInfoPtr pScreenInfo)
{
renditionPtr pRendition = RENDITIONPTR(pScreenInfo);
IOADDRESS io_base=pRendition->board.io_base;
verite_out8(io_base+DEBUGREG, SOFTRESET|HOLDRISC);
verite_out8(io_base+STATEINDEX, STATEINDEX_PC);
verite_iopoll(io_base+STATEDATA, 0, 0xffffffff);
verite_iopoll(io_base+STATEDATA, 0, 0xffffffff);
verite_iopoll(io_base+STATEDATA, 0, 0xffffffff);
verite_out8(io_base+DEBUGREG, HOLDRISC);
verite_iopoll(io_base+STATEDATA, 0, 0);
verite_iopoll(io_base+STATEDATA, 0, 0);
verite_iopoll(io_base+STATEDATA, 0, 0);
risc_forcestep(io_base, LI_INSTR(LI_OP, RISC_RA, ICACHE_ONOFF_MASK&0xffff));
risc_forcestep(io_base, INT_INSTR(ADDIFI_OP, RISC_FLAG, RISC_RA,
ICACHE_ONOFF_MASK>>16));
verite_out8(io_base+INTR, 0xff);
verite_out8(io_base+MEMENDIAN, MEMENDIAN_NO);
}
static void
verite_iopoll(IOADDRESS port, vu32 data, vu32 mask)
{
vu32 c;
c=0;
do {
c++;
if ((verite_in32(port)&mask) == (data&mask))
break;
} while (c <= VERITE_MAX_POLLS);
}
static void
verite_iopoll8(IOADDRESS port, vu8 data, vu8 mask)
{
vu32 c;
c=0;
do {
c++;
if ((verite_in8(port)&mask) == (data&mask))
break;
} while (c <= VERITE_MAX_POLLS);
}
static vu32
readRF(IOADDRESS io_base, vu8 index)
{
vu32 data, instr;
vu8 debug, stateindex;
debug=verite_in8(io_base+DEBUGREG);
stateindex=verite_in8(io_base+STATEINDEX);
verite_out8(io_base+DEBUGREG, debug|HOLDRISC);
instr=INT_INSTR(ADD_OP, 0, 0, index);
verite_out32(io_base+STATEDATA, instr);
verite_out8(io_base+STATEINDEX, STATEINDEX_IR);
verite_iopoll(io_base+STATEDATA, instr, 0xffffffff);
verite_out8(io_base+STATEINDEX, STATEINDEX_S1);
verite_iopoll(io_base+STATEINDEX, 0, 0);
data=verite_in32(io_base+STATEDATA);
verite_out8(io_base+STATEINDEX, stateindex);
verite_out8(io_base+DEBUGREG, debug);
return data;
}
static void
writeRF(IOADDRESS io_base, vu8 index, vu32 data)
{
vu8 special=0;
if (index < 64) {
special=index;
index=RISC_SP;
}
if (!(data & 0xff000000)) {
risc_forcestep(io_base, LI_INSTR(LI_OP,index,data&0xffff));
if (data & 0x00ff0000)
risc_forcestep(io_base, INT_INSTR(ADDIFI_OP,index,index,data>>16) );
}
else {
risc_forcestep(io_base, LI_INSTR(LUI_OP, index, data>>16));
risc_forcestep(io_base, INT_INSTR(ADDSL8_OP, index, index, (data>>8)&0xff));
risc_forcestep(io_base, INT_INSTR(ADDI_OP, index, index, data&0xff));
}
if (special) {
risc_forcestep(io_base, INT_INSTR(ADD_OP, special, 0, RISC_SP));
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
}
}
static vu32
risc_readmem(IOADDRESS io_base, vu32 addr, vu8 read_type)
{
vu32 data;
writeRF(io_base, RISC_RA, addr);
if (READ_BYTE == read_type)
risc_forcestep(io_base, LD_INSTR(LB_OP, RISC_SP, 0, RISC_RA));
else
if (READ_SHORT == read_type)
risc_forcestep(io_base, LD_INSTR(LH_OP, RISC_SP, 0, RISC_RA));
else
risc_forcestep(io_base, LD_INSTR(LW_OP, RISC_SP, 0, RISC_RA));
risc_forcestep(io_base, NOP_INSTR);
risc_forcestep(io_base, NOP_INSTR);
data=readRF(io_base, RISC_SP);
return data;
}
static void
risc_writemem(IOADDRESS io_base, vu32 addr, vu32 data, vu8 write_type)
{
writeRF(io_base, RISC_RA, addr);
writeRF(io_base, RISC_FP, data);
if (WRITE_BYTE == write_type)
risc_forcestep(io_base, STR_INSTR(SB_OP, 0, RISC_FP, RISC_RA));
else
if (WRITE_SHORT == write_type)
risc_forcestep(io_base, STR_INSTR(SH_OP, 0, RISC_FP, RISC_RA));
else
risc_forcestep(io_base, STR_INSTR(SW_OP, 0, RISC_FP, RISC_RA));
}
#if 0
static void
risc_step(IOADDRESS io_base, vu32 count)
{
vu32 c, d;
vu8 debugreg;
for (c=0; c<count; c++) {
debugreg=verite_in8(io_base+DEBUGREG);
verite_out8(io_base+DEBUGREG, debugreg|STEPRISC);
for (d=0; d<1000; d++)
if(0 == (verite_in8(io_base+DEBUGREG)&STEPRISC))
break;
if (1000 == d)
return;
}
}
#endif
static void
risc_forcestep(IOADDRESS io_base, vu32 instruction)
{
vu32 c;
vu8 debugreg, stateindex;
debugreg=verite_in8(io_base+DEBUGREG);
stateindex=verite_in8(io_base+STATEINDEX);
verite_out8(io_base+STATEINDEX, STATEINDEX_IR);
verite_iopoll8(io_base+STATEINDEX, STATEINDEX_IR, 0xff);
verite_out32(io_base+STATEDATA, instruction);
verite_iopoll(io_base+STATEDATA, instruction, 0xffffffff);
verite_out8(io_base+DEBUGREG, debugreg|HOLDRISC|STEPRISC);
verite_iopoll(io_base+STATEDATA, 0, 0);
for (c=0; c<VERITE_MAX_POLLS; c++)
if (HOLDRISC == (verite_in8(io_base+DEBUGREG) & (HOLDRISC|STEPRISC)))
break;
verite_out8(io_base+STATEINDEX, stateindex);
}
static void
risc_continue(IOADDRESS io_base)
{
vu8 debugreg;
debugreg=verite_in8(io_base+DEBUGREG);
verite_out8(io_base+DEBUGREG, debugreg&(~HOLDRISC));
verite_iopoll(io_base+STATEDATA, 0, 0);
}