'******************************************************************************
'* 
'* BK-0010 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 chipset implementation
public use object CHIPSET_BK

//motherboard name
DeviceName="BK-0010 Motherboard"
DebugName="MBOARD"

//variables
dim i as integer
dim binstart as word=0x200-0xA004 'start address of program file (to autoload)

//objects
use object FILE_STREAM as file

//ROM memory writer to raise incorrect address error
protected function MemROMWriter(Addr as dword, Value as byte) as boolean
 pc.SetIRQ(1,true) : result=true 
end

//Memory reader of beginning of extra ROM to autoload binary file
protected function MemBinLoadReader(Addr as dword, byref Value as byte) as boolean
 result=false : if dbg.ReadingMemory then exit
 select case Addr 
  case 0xA000 'loading binary file
    binstart=0x200-0xA004
    dim bin as object=emuDrives.PROGRAM(0)
    dim offs as word=bin.Word(0) 'address
    dim len as word=bin.Word(2)  'size
    if (offs+len)>0x8000 then len=0x8000-offs
    mem.pos=offs : bin.pos=4 : mem.Copy(bin.Object,len) 'load BIN to memory
    if offs<0x200 then binstart=mem.Word(0x200-4)-0xA004 'process autostart
    //write resulting addr and size to some memory places also (need by "Apple" etc)
    mem.Word(0xB4)=offs : mem.Word(0xE6)=offs
    mem.Word(0xB6)=len : mem.Word(0xE8)=len
   //dbg.break - !!!! uncomment it to break to debugger on program start
  case 0xA002 : value=binstart : result=true
  case 0xA003 : value=shr(binstart,8) : result=true
 end select
end

//Capture EMT services to emulate loading from tape
public function CallEMT(Tag as dword) as boolean
 ?? DebugPrefix;"EMT ";Oct(Tag,6);
 result=false
 if Tag=0x1E then 'EMT 36 - tape service
    result=true : mem.Byte(cpu.R(1)+1)=1 'processed, default - file name error
    ?? " [R1]=[";Oct(cpu.R1,6);"]=";mem.Byte(cpu.R1);",";
    ?? Oct(mem.Word(cpu.R1+2),6);",";Oct(mem.Word,6);",";
    ?? Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);
    ?? Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);
    ?? Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);
    ?? Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte);Chr(mem.Byte)
    select case mem.Byte(cpu.R(1))
    case 0, 1 'start and stop tape
      mem.Byte(cpu.R1+1)=0 'no error
    case 3 'read file from tape
      dim i as integer, offs as word, len as word=0, fname as string, b as byte
      mem.Pos=cpu.R1+2 : offs=mem.Word : len=mem.Word
      for i=0 to 15 : b=mem.Byte : if b=0 then exit for 
          if (i>0) or (Chr(b)<>".") then fname=fname+Chr(b) : next
      fname=Trim(fname)
      if not file.OpenPath(emuDrives.PROGRAM(0).Path(false)+fname) then 
      if not file.OpenPath(emuDrives.PROGRAM(0).Path(false)+fname+".bin") then 
      if not file.OpenPath(emuDrives.PROGRAM(0).Path(false)+fname+".ovl") then exit
      end if : end if
      if offs=0 then offs=file.Word(0)
      if len=0 then len=file.Word(2)
      if len=0 then len=file.size
      if (offs+len)>0x8000 then len=0x8000-offs
      mem.pos=offs : file.pos=4 :
      mem.Copy(file.Object,len)  'load BIN to memory
      if offs<0x200 then cpu.PC=mem.Word(0x200-4) //process autostart frame
      mem.Byte(cpu.R1+1)=0 'no error
      //write resulting addr and size to some memory places also (need by "Apple" etc)
      mem.Word(cpu.R1+0x12)=offs : mem.Word(0xB4)=offs : mem.Word(0xE6)=offs
      mem.Word(cpu.R1+0x14)=len : mem.Word(0xB6)=len : mem.Word(0xE8)=len
      ? "[TAPE] Loaded file ";file.filename;" offset=";Oct(offs,6);
      ? " length=";Oct(len,6)
    end
 else : ?? : end
end

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

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

 'load ROM BIOS files
 select case pc.ModelNumber
 case 0 //BK-0010
   s="bin\monit10.rom" : mem.Bytes(0x8000)=ArrayFile(s) 
   s="bin\Focal.rom"   : mem.Bytes(0xA000)=ArrayFile(s) 
   s="bin\Tests.rom"   : mem.Bytes(0xE000)=ArrayFile(s) 
 case 1 //BK-0010.01
   s="bin\monit10.rom"       : mem.Bytes(0x8000)=ArrayFile(s) 
   s="bin\Basic10first.rom"  : mem.Bytes(0xA000)=ArrayFile(s) 
   s="bin\Basic10second.rom" : mem.Bytes(0xC000)=ArrayFile(s) 
   s="bin\Basic10third.rom"  : mem.Bytes(0xE000)=ArrayFile(s) 
 case else : ErrorMsg("Unknown model number.") : end select

 'bin files loading bin from drive if possible
 dim bin as object=emuDrives.PROGRAM(0)
 bin.Detected=(bin.Ready) and (bin.Latched) and (bin.Size<=0x8000)
 if bin.Detected then : pc.CallInt(6)=CallEMT
   mem.Pos=0xA000 : mem.Word=0x77 : mem.Word=0x200-0xA004 'jmp to bin start
   mem.KBReader(0xA000/1024)=MemBinLoadReader 'to load bin to memory after jump
 end if

 'mark first 32K of memory area as read-write (RAM)
 for i=1 to 31 : mem.KBAccess(i)=memReadWrite : next
 'mark next 32K of memory area as read-write (ROM, write handler raise error)
 for i=32 to 63 : mem.KBAccess(i)=memReadWrite
   mem.KBWriter(i)=MemROMWriter : next
 'mark hardware registers area of memory as read-write and attach handlers
 for i=0xFF80/1024 to 0xFFFF/1024 : mem.KBAccess(i)=memReadWrite 
   mem.KBReader(i)=MemIOReader : mem.KBWriter(i)=MemIOWriter : next

 'success 
 result=true
end

