'******************************************************************************
'* 
'* SEGA GENESIS/MEGRADRIVE MOTHERBOARD (MOTHERBOARD DEVICE)
'*
'* Version history:
'*  2009 - initial emulation (by WadiM)
'*
'****************************************************************************** 

//DEBUG.ON 'uncomment to enable debug messages (can be slow for hi-freq events)

//parent DEVSET implementation
public use object DEVSET

//motherboard name
DeviceName="Sega Genesis Motherboard"
DebugName="MBOARD"

//variables
dim i as integer

'------------------------------ Video adapter ---------------------------------

public use object VID_SEGAMD as VDP : AddDevice(VDP)

//Memory writer
function MemVDPWriter(Addr as dword, Value as byte) as boolean //ROM areas
 select case Addr 
 case 0xC00000 : VDP.DATA_PORT(0)=Value
 case 0xC00001 : VDP.DATA_PORT(1)=Value
 case 0xC00002 : VDP.DATA_PORT(0)=Value
 case 0xC00003 : VDP.DATA_PORT(1)=Value
 case 0xC00004 : VDP.CTRL_PORT(0)=Value
 case 0xC00005 : VDP.CTRL_PORT(1)=Value
 case 0xC00006 : VDP.CTRL_PORT(0)=Value
 case 0xC00007 : VDP.CTRL_PORT(1)=Value
 case else //other VDP-area registers
    ?? DebugPrefix;">VDPReg[$";Hex(Addr,8);"]:=$";Hex(Value,2)
 end select
 result=true 
end

//Memory reader
function MemVDPReader(Addr as dword, byref Value as byte) as boolean
 select case Addr 
 case 0xC00000 : Value=VDP.DATA_PORT(0)
 case 0xC00001 : Value=VDP.DATA_PORT(1)
 case 0xC00002 : Value=VDP.DATA_PORT(0)
 case 0xC00003 : Value=VDP.DATA_PORT(1)
 case 0xC00004 : Value=VDP.STATE_PORT(0)
 case 0xC00005 : Value=VDP.STATE_PORT(1)
 case 0xC00006 : Value=VDP.STATE_PORT(0)
 case 0xC00007 : Value=VDP.STATE_PORT(1)
 case 0xC00008 : Value=VDP.HV_PORT(0)
 case 0xC00009 : Value=VDP.HV_PORT(1)
 case else : Value=0 
    ?? DebugPrefix;"<VDPReg[$";Hex(Addr,8);"]=$";Hex(Value,2)
 end select
 result=true 
end

'------------------- Handling of I/O registers at A10000h..A1001Fh -------------

//I/O values to reuse 
dim io_vals(0 to 0x1F) as byte

//Memory writer
function MemIOWriter(Addr as dword, Value as byte) as boolean //ROM areas
 select case Addr 
 case else //other I/O registers
    ?? DebugPrefix;">IOReg[$";Hex(Addr,8);"]:=$";Hex(Value,2)
 end select
 result=true 
end

//Memory reader
function MemIOReader(Addr as dword, byref Value as byte) as boolean
 select case Addr 
 case 0xA10001 //Configuration Register
    Value=0x81 'International, NTSC, no FDD
    ?? DebugPrefix;"<CfgReg=[$";Hex(Addr,4);"]=$";Hex(Value,2)
 case else : Value=0 
    ?? DebugPrefix;"<IOReg[$";Hex(Addr,8);"]=$";Hex(Value,2)
 end select
 result=true 
end

'---------------------------- DEVICE Interface --------------------------------

//Device initialization
protected function DEV_INIT(stream as object,byref EventFreq as integer) as boolean
 dim i as integer
  
 'parent call
 if not DEV_INIT(stream,EventFreq) then exit(false)
 if EventFreq<100 then EventFreq=100

 'mark all memory area as read-write (RAM)
 for i=0 to (mem.Size-1)/1024 : mem.KBAccess(i)=memReadWrite : next
 'mark ROM memory area as read-only
 for i=0x000000/1024 to 0x3FFFFF/1024 : mem.KBAccess(i)=memReadOnly : next
 'I/O register handlers 
 for i=0xA00000/1024 to 0xAFFFFF/1024 : mem.KBReader(i)=MemIOReader 
   mem.KBWriter(i)=MemIOWriter : next
 'VDP register handlers 
 for i=0xC00000/1024 to 0xDFFFFF/1024 : mem.KBReader(i)=MemVDPReader 
   mem.KBWriter(i)=MemVDPWriter : next

 'load CPU init data from ROM
 mem.Pos=0
 cpu.SP=shl(mem.Byte,24) or shl(mem.Byte,16) or shl(mem.Byte,8) or mem.Byte
 cpu.PC=shl(mem.Byte,24) or shl(mem.Byte,16) or shl(mem.Byte,8) or mem.Byte

 'success 
 result=true
end

