'******************************************************************************
'* 
'* COLECOVISION MOTHERBOARD (MOTHERBOARD DEVICE)
'*
'* Supported platform/bus: ColecoVision
'*
'* Version history:
'*  2009 - initial emulation (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="ColecoVision Motherboard"
DebugName="MBOARD"

//variables
dim i as integer

'-------------------------- Video adapter (TMS9918) ---------------------------

//TMS9918 video adapter
public use object VID_TMS9918 as VDP : AddDevice(VDP)
for i=0xA0 to 0xBE step 2 
 pc.WritePort(i)=VDP.MEM_PORT   : pc.ReadPort(i)=VDP.MEM_PORT
 pc.WritePort(i+1)=VDP.REG_PORT : pc.ReadPort(i+1)=VDP.STATE_PORT
next i

'-------------------------------- Controllers ---------------------------------

//Variables
dim vkey_state(256) as boolean 'virtual key states (pressed/released)
dim joy_usage as boolean=false 'controllers mode (keypad or joystick)
dim key1_state as byte=0x7F, joy1_state as byte=0x7F 'state of controller 1

//Keypads mode port
property PORT_KEYMODE(Value as byte) 
 joy_usage=false : ?? DebugPrefix;">KeyMode=true"
end

//Joysticks mode port
property PORT_JOYMODE(Value as byte) 
 joy_usage=true : ?? DebugPrefix;">JoyMode=true"
end

//Controller 1 state
function PORT_CTRL1 as byte 
 if joy_usage then result=joy1_state else result=key1_state or 0x70  
 ?? DebugPrefix;"<Ctrl1Data=";Hex(result)
end

//Controller 2 state
function PORT_CTRL2 as byte
 result=0x7F 'nothing
end

//Update controllers state after virtual key state change
procedure GenerateControllerStates
 key1_state=0x7F : joy1_state=0x7F
 //keypad
 if vkey_state(VK_0) then key1_state=key1_state and 0xA '0
 if vkey_state(VK_1) then key1_state=key1_state and 0xD '1
 if vkey_state(VK_2) then key1_state=key1_state and 0x7 '2
 if vkey_state(VK_3) then key1_state=key1_state and 0xC '3
 if vkey_state(VK_4) then key1_state=key1_state and 0x2 '4
 if vkey_state(VK_5) then key1_state=key1_state and 0x3 '5
 if vkey_state(VK_6) then key1_state=key1_state and 0xE '6
 if vkey_state(VK_7) then key1_state=key1_state and 0x5 '7
 if vkey_state(VK_8) then key1_state=key1_state and 0x1 '8
 if vkey_state(VK_9) then key1_state=key1_state and 0xB '9
 if vkey_state(VK_LCTRL) or vkey_state(VK_RCTRL) or vkey_state(VK_MULTIPLY) or vkey_state(VK_X) then '*
    key1_state=key1_state and 0x9 : end if
 if vkey_state(VK_RETURN) or vkey_state(VK_EXTRETURN) or vkey_state(VK_Z) then '#
    key1_state=key1_state and 0x6 : end if
 if vkey_state(VK_SPACE) or vkey_state(VK_A) then 'Fire1
    key1_state=key1_state and 0x4 : end if
 if vkey_state(VK_LALT) or vkey_state(VK_RALT) or vkey_state(VK_S) then 'Fire2
    key1_state=key1_state and 0x8 : end if
 //joystick
 if vkey_state(VK_UP) then joy1_state=joy1_state and not(1) 'Up
 if vkey_state(VK_RIGHT) then joy1_state=joy1_state and not(2) 'Right
 if vkey_state(VK_DOWN) then joy1_state=joy1_state and not(4) 'Down
 if vkey_state(VK_LEFT) then joy1_state=joy1_state and not(8) 'Left
 if vkey_state(VK_LSHIFT) or vkey_state(VK_RSHIFT) then 'JoyBtn
    joy1_state=joy1_state and not(0x10) : end if
end

//Handle key from emulator
public procedure HandleKey(vkey as byte, pressed as boolean)
 ?? DebugPrefix;">VKey=";Hex(vkey,2);"h (";iif(pressed,"DOWN","UP");")"
 vkey_state(vkey)=pressed 
  GenerateControllerStates
end
pc.HandleKey=HandleKey

//Attach port handlers
for i=0x80 to 0x9E step 2 : pc.WritePort(i)=PORT_KEYMODE : next i
for i=0xC0 to 0xDE step 2 : pc.WritePort(i)=PORT_JOYMODE : next i
for i=0xE0 to 0xFF 
 if (i and 2)=0 then pc.ReadPort(i)=PORT_CTRL1 else pc.ReadPort(i)=PORT_CTRL2
next i

'------------------------------ IRQ Emulation ---------------------------------

//Set IRQ
public function SetIRQ(Index as integer, State as boolean) as boolean
 //?? DebugPrefix;"SetIRQ=NMI"
 pc.SetNMI(true) : result=true
end

//Configure IRQs
pc.SetIRQ=SetIRQ

'---------------------------- 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)

 'load ROM BIOS file 
 mem.Bytes(0)=ArrayFile("bin\coleco.rom")  'main BIOS

 'mark all memory area as read-only (ROM)
 for i=0 to 63 : mem.KBAccess(i)=memReadOnly : next
 'mark RAM area (0x6000...0x7FFF) as read-write and mirroring (1kb x 8)
 for i=0x6000/1024 to 0x7FFF/1024 
   mem.KBAccess(i)=memReadWrite 
   mem.KBIndex(i)=0x6000/1024
 next

 'mask port indexes to use only low byte
 pc.PortIndexMask=0xFF

 'success 
 result=true
end

