'******************************************************************************
'* 
'* PC/486 ISA MOTHERBOARD v.1.0 (MOTHERBOARD DEVICE)
'*
'* Supported platform/bus: X86
'*
'* Adapters: VGA
'* 
'* Version history:
'*  - v.1.0 by WadiM (initial emulation)
'*
'****************************************************************************** 

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

//parent PC/AT chipset implementation
public use object CHIPSET_PCAT

//motherboard name
DeviceName="PC/486 Motherboard"
DebugName="PC486_MB"

//variables
dim i as integer

'--------------------------------- Adapters -----------------------------------

//VGA video adapter
public use object VID_VGA as VGA : AddDevice(VGA)
for i=0x3C0 to 0x3CF : pc.WritePort(i)=VGA.PORTS : pc.ReadPort(i)=VGA.PORTS : next
for i=0x3D0 to 0x3DF : pc.WritePort(i)=VGA.PORTS : pc.ReadPort(i)=VGA.PORTS : next
pc.WritePort(0x3B4)=VGA.PORTS : pc.ReadPort(0x3B4)=VGA.PORTS
pc.WritePort(0x3B5)=VGA.PORTS : pc.ReadPort(0x3B5)=VGA.PORTS
pc.WritePort(0x3BA)=VGA.PORTS : pc.ReadPort(0x3BA)=VGA.PORTS
for i=0xA0000/1024 to (0xBFFFF/1024)-1 //VGA video memory
 mem.KBReader(i)=VGA.ReadMemory : mem.KBWriter(i)=VGA.WriteMemory 
next

//Extended CMOS checksum calculation (cells [34h..3Dh]) and writing to [3E..3F])
protected procedure UpdateCMOSChecksumExt
 dim w as word=0 : for i=0x34 to 0x3D : w=w+CMOS.Cell(i) : next 
 CMOS.Cell(0x3E)=shr(w,8) : CMOS.Cell(0x3F)=w
end

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

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

 //Writing HDD Params directly to CMOS (as User Type 47) - AMI BIOS Only!!!
 dim Disk as object=emuDrives.HDD(0) //first HDD
 CMOS.Cell(0x20)=0 'control byte
 if not(Disk.Detected) then DetectHardDisk(Disk)
 if not(Disk.Usable) then 'not available
    CMOS.Cell(0x12)=CMOS.Cell(0x12) and (not 0xF0)
 else 'available
   CMOS.Cell(0x12)=CMOS.Cell(0x12) or 0xF0
   CMOS.Cell(0x1B)=disk.CylinderCount
   CMOS.Cell(0x1C)=shr(disk.CylinderCount,8)
   CMOS.Cell(0x1D)=disk.HeadCount
   if disk.HeadCount>=8 then : CMOS.Cell(0x20)=CMOS.Cell(0x20) or 8 
      else : CMOS.Cell(0x20)=CMOS.Cell(0x20) and not(8) : end
   CMOS.Cell(0x23)=disk.SectorCount
 end
 Disk=emuDrives.HDD(1) //second HDD
 CMOS.Cell(0x29)=0 'control byte
 if not(Disk.Detected) then DetectHardDisk(Disk)
 if not(Disk.Usable) then 'not available
    CMOS.Cell(0x12)=CMOS.Cell(0x12) and (not 0xF)
 else 'available
   CMOS.Cell(0x12)=CMOS.Cell(0x12) or 0xF
   CMOS.Cell(0x24)=disk.CylinderCount
   CMOS.Cell(0x25)=shr(disk.CylinderCount,8)
   CMOS.Cell(0x26)=disk.HeadCount
   if disk.HeadCount>=8 then : CMOS.Cell(0x29)=CMOS.Cell(0x29) or 8 
      else : CMOS.Cell(0x29)=CMOS.Cell(0x29) and not(8) : end
   CMOS.Cell(0x2C)=disk.SectorCount
 end
 CMOS.Cell(0x19)=47 : CMOS.Cell(0x1A)=47 
 CMOS.Cell(0x2D)=CMOS.Cell(0x2D) or 0x20 //Boot order: A,C
 UpdateCMOSChecksum

 //Calculation of extended checksum (AMI BIOS-only!!!)
 if CMOS.Cell(0x3D)=0 then 'some of cells 34h..3Dh need to be nonzero  
    CMOS.Cell(0x3D)=0xFF : end
 UpdateCMOSChecksumExt

 'load ROM BIOS files
 s="bin\at486.bin" : mem.Bytes(0x100000-FileSize(s))=ArrayFile(s) 'main BIOS
 //s="bin\trident.bin" : mem.Bytes(0xC0000)=ArrayFile(s)  'VGA BIOS
 s="bin\et4000.bin" : mem.Bytes(0xC0000)=ArrayFile(s) 'VGA BIOS

 'mark non-conventional memory area as read-only 
 for i=0xA0000/1024 to 0xFFFFF/1024 : mem.KBAccess(i)=memReadOnly : next
 'mark VGA memory as read-write 
 for i=0xA0000/1024 to 0xBFFFF/1024 : mem.KBAccess(i)=memReadWrite : next

 'success 
 result=true
end
