text: /*
   *  slot_rom.cpp - Slot declaration ROM
   *
   *  Basilisk II (C) Christian Bauer
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  /*
   *  SEE ALSO
   *    Inside Macintosh: Devices, chapter 2 "Slot Manager"
   *    Designing Cards and Drivers for the Macintosh Family, Second Edition
   */
  
  #include <stdio.h>
  #include <string.h>
  
  #include "sysdeps.h"
  #include "cpu_emulation.h"
  #include "main.h"
  #include "video.h"
  #include "emul_op.h"
  #include "version.h"
  #include "slot_rom.h"
  
  
  // Temporary buffer for slot ROM
  static uint8 srom[4096];
  
  // Index in srom
  static uint32 p;
  
  // Length of slot ROM
  static int slot_rom_size = 0;
  
  
  /*
   *  Construct slot declaration ROM and copy it into the Mac ROM (must be called after VideoInit())
   */
  
  static void Offs(uint8 type, uint32 ptr)
  {
  	uint32 offs = ptr - p;
  	srom[p++] = type;
  	srom[p++] = offs >> 16;
  	srom[p++] = offs >> 8;
  	srom[p++] = offs;
  }
  
  static void Rsrc(uint8 type, uint32 data)
  {
  	srom[p++] = type;
  	srom[p++] = data >> 16;
  	srom[p++] = data >> 8;
  	srom[p++] = data;
  }
  
  static void EndOfList(void)
  {
  	srom[p++] = 0xff;
  	srom[p++] = 0;
  	srom[p++] = 0;
  	srom[p++] = 0;
  }
  
  static void Long(uint32 data)
  {
  	srom[p++] = data >> 24;
  	srom[p++] = data >> 16;
  	srom[p++] = data >> 8;
  	srom[p++] = data;
  }
  
  static void Word(uint16 data)
  {
  	srom[p++] = data >> 8;
  	srom[p++] = uint8(data);
  }
  
  static void String(const char *str)
  {
  	while ((srom[p++] = *str++) != 0) ;
  	if (p & 1)
  		srom[p++] = 0;
  }
  
  static void PString(const char *str)
  {
  	srom[p++] = uint8(strlen(str));
  	while ((srom[p++] = *str++) != 0) ;
  	p--;
  	if (p & 1)
  		srom[p++] = 0;
  }
  
  static uint32 VModeParms(const monitor_desc &m, video_depth depth)
  {
  	const video_mode &mode = m.get_current_mode();
  
  	uint32 ret = p;
  	Long(50);					// Length
  	Long(0);					// Base offset
  	Word(m.get_bytes_per_row(depth, mode.resolution_id));
  	Word(0);					// Bounds
  	Word(0);
  	Word(mode.y);
  	Word(mode.x);
  	Word(0);					// Version
  	Word(0);					// Pack type
  	Long(0);					// Pack size
  	Long(0x00480000);			// HRes
  	Long(0x00480000);			// VRes
  	switch (depth) {
  		case VDEPTH_1BIT:
  			Word(0);			// Pixel type (indirect)
  			Word(1);			// Pixel size
  			Word(1);			// CmpCount
  			Word(1);			// CmpSize
  			break;
  		case VDEPTH_2BIT:
  			Word(0);			// Pixel type (indirect)
  			Word(2);			// Pixel size
  			Word(1);			// CmpCount
  			Word(2);			// CmpSize
  			break;
  		case VDEPTH_4BIT:
  			Word(0);			// Pixel type (indirect)
  			Word(4);			// Pixel size
  			Word(1);			// CmpCount
  			Word(4);			// CmpSize
  			break;
  		case VDEPTH_8BIT:
  			Word(0);			// Pixel type (indirect)
  			Word(8);			// Pixel size
  			Word(1);			// CmpCount
  			Word(8);			// CmpSize
  			break;
  		case VDEPTH_16BIT:
  			Word(16);			// Pixel type (direct)
  			Word(16);			// Pixel size
  			Word(3);			// CmpCount
  			Word(5);			// CmpSize
  			break;
  		case VDEPTH_32BIT:
  			Word(16);			// Pixel type (direct)
  			Word(32);			// Pixel size
  			Word(3);			// CmpCount
  			Word(8);			// CmpSize
  			break;
  	}
  	Long(0);					// Plane size
  	Long(0);					// Reserved
  	return ret;
  }
  
  static uint32 VModeDesc(uint32 params, bool direct)
  {
  	uint32 ret = p;
  	Offs(0x01, params);			// Video parameters
  	Rsrc(0x03, 1);				// Page count
  	Rsrc(0x04, direct ? 2 : 0);	// Device type
  	EndOfList();
  	return ret;
  }
  
  static uint32 VMonitor(const monitor_desc &m, uint32 videoType, uint32 videoName, uint32 vidDrvrDir, uint32 gammaDir)
  {
  	uint32 minorBase, minorLength;
  	uint32 vidModeParms1, vidModeParms2, vidModeParms4, vidModeParms8, vidModeParms16, vidModeParms32;
  	uint32 vidMode1, vidMode2, vidMode4, vidMode8, vidMode16, vidMode32;
  	uint32 ret;
  
  	minorBase = p;
  	Long(m.get_mac_frame_base());	// Frame buffer base
  	minorLength = p;
  	Long(0);					// Frame buffer size (unspecified)
  
  	vidModeParms1 = VModeParms(m, VDEPTH_1BIT);
  	vidModeParms2 = VModeParms(m, VDEPTH_2BIT);
  	vidModeParms4 = VModeParms(m, VDEPTH_4BIT);
  	vidModeParms8 = VModeParms(m, VDEPTH_8BIT);
  	vidModeParms16 = VModeParms(m, VDEPTH_16BIT);
  	vidModeParms32 = VModeParms(m, VDEPTH_32BIT);
  
  	vidMode1 = VModeDesc(vidModeParms1, false);
  	vidMode2 = VModeDesc(vidModeParms2, false);
  	vidMode4 = VModeDesc(vidModeParms4, false);
  	vidMode8 = VModeDesc(vidModeParms8, false);
  	vidMode16 = VModeDesc(vidModeParms16, true);
  	vidMode32 = VModeDesc(vidModeParms32, true);
  
  	ret = p;
  	Offs(0x01, videoType);				// Video type descriptor
  	Offs(0x02, videoName);				// Driver name
  	Offs(0x04, vidDrvrDir);				// Driver directory
  	Rsrc(0x08, 0x4232);					// Hardware device ID ('B2')
  	Offs(0x0a, minorBase);				// Frame buffer base
  	Offs(0x0b, minorLength);			// Frame buffer length
  	Offs(0x40, gammaDir);				// Gamma directory
  	Rsrc(0x7d, 6);						// Video attributes: Default to color, built-in
  	if (m.has_depth(VDEPTH_1BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_1BIT)), vidMode1);	// Video mode parameters for 1 bit
  	if (m.has_depth(VDEPTH_2BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_2BIT)), vidMode2);	// Video mode parameters for 2 bit
  	if (m.has_depth(VDEPTH_4BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_4BIT)), vidMode4);	// Video mode parameters for 4 bit
  	if (m.has_depth(VDEPTH_8BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_8BIT)), vidMode8);	// Video mode parameters for 8 bit
  	if (m.has_depth(VDEPTH_16BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_16BIT)), vidMode16);	// Video mode parameters for 16 bit
  	if (m.has_depth(VDEPTH_32BIT))
  		Offs(uint8(m.depth_to_apple_mode(VDEPTH_32BIT)), vidMode32);	// Video mode parameters for 32 bit
  	EndOfList();
  	return ret;
  }
  
  bool InstallSlotROM(void)
  {
  	uint32 boardType, boardName, vendorID, revLevel, partNum, date;
  	uint32 vendorInfo, sRsrcBoard;
  
  	uint32 videoType, videoName, videoDrvr, vidDrvrDir;
  	uint32 defaultGamma, gammaDir;
  
  	uint32 cpuType, cpuName, cpuMajor, cpuMinor, sRsrcCPU;
  
  	uint32 etherType, etherName, etherDrvr, etherDrvrDir, sRsrcEther;
  
  	uint32 sRsrcDir;
  
  	vector<monitor_desc *>::const_iterator m, mend = VideoMonitors.end();
  	vector<uint32> sRsrcVideo;
  
  	char str[256];
  	int i;
  	p = 0;
  
  	// Board sResource
  	boardType = p;						// Literals
  	Word(1); Word(0); Word(0); Word(0);	// Board sResource
  	boardName = p;
  	String("Basilisk II Slot ROM");
  	vendorID = p;
  	String("Christian Bauer");
  	revLevel = p;
  	sprintf(str, "V%d.%d", VERSION_MAJOR, VERSION_MINOR);
  	String(str);
  	partNum = p;
  	String("BasiliskII");
  	date = p;
  	String(__DATE__);
  
  	vendorInfo = p;						// Vendor Info
  	Offs(0x01, vendorID);				// Vendor ID
  	Offs(0x03, revLevel);				// Revision level
  	Offs(0x04, partNum);				// Part number
  	Offs(0x05, date);					// ROM build date
  	EndOfList();
  
  	sRsrcBoard = p;
  	Offs(0x01, boardType);				// Board descriptor
  	Offs(0x02, boardName);				// Board name
  	Rsrc(0x20, 0x4232);					// Board ID ('B2')
  	Offs(0x24, vendorInfo);				// Vendor Info
  	EndOfList();
  
  	videoType = p;
  	Word(3); Word(1); Word(1); Word(0x4232);	// Display Video Apple 'B2'
  	videoName = p;
  	String("Display_Video_Apple_Basilisk");
  
  	videoDrvr = p;						// Video driver
  	Long(0x72);							// Length
  	Word(0x4c00); Word(0); Word(0); Word(0);
  	Word(0x32);							// Open offset
  	Word(0x36);							// Prime offset
  	Word(0x3a);							// Control offset
  	Word(0x46);							// Status offset
  	Word(0x6c);							// Close offset
  	PString(".Display_Video_Apple_Basilisk");
  	Word(1);							// Driver version
  	Word(M68K_EMUL_OP_VIDEO_OPEN);		// Open()
  	Word(0x4e75);
  	Word(0x70ff);						// Prime()
  	Word(0x600e);
  	Word(M68K_EMUL_OP_VIDEO_CONTROL);	// Control()
  	Word(0x0c68); Word(0x0001); Word(0x001a);
  	Word(0x6604);
  	Word(0x4e75);
  	Word(M68K_EMUL_OP_VIDEO_STATUS);	// Status()
  	Word(0x3228); Word(0x0006);			// IOReturn
  	Word(0x0801); Word(0x0009);
  	Word(0x670c);
  	Word(0x4a40);
  	Word(0x6f02);
  	Word(0x4240);
  	Word(0x3140); Word(0x0010);
  	Word(0x4e75);
  	Word(0x4a40);
  	Word(0x6f04);
  	Word(0x4240);
  	Word(0x4e75);
  	Word(0x2f38); Word(0x08fc);
  	Word(0x4e75);
  	Word(0x70e8);						// Close()
  	Word(0x4e75);
  
  	vidDrvrDir = p;						// Driver directory
  	Offs(0x02, videoDrvr);				// sMacOS68020
  	EndOfList();
  
  	defaultGamma = p;					// Gamma table
  	Long(38 + 0x100);					// Length
  	Word(0x2000);						// Resource ID
  	String("Mac HiRes Std Gamma");
  	Word(0);							// Version
  	Word(0);							// Type
  	Word(0);							// FormulaSize
  	Word(1);							// ChanCnt
  	Word(0x0100);						// DataCnt
  	Word(8);							// ChanWidth
  	Long(0x0005090B); Long(0x0E101315); Long(0x17191B1D); Long(0x1E202224);
  	Long(0x2527282A); Long(0x2C2D2F30); Long(0x31333436); Long(0x37383A3B);
  	Long(0x3C3E3F40); Long(0x42434445); Long(0x4748494A); Long(0x4B4D4E4F);
  	Long(0x50515254); Long(0x55565758); Long(0x595A5B5C); Long(0x5E5F6061);
  	Long(0x62636465); Long(0x66676869); Long(0x6A6B6C6D); Long(0x6E6F7071);
  	Long(0x72737475); Long(0x76777879); Long(0x7A7B7C7D); Long(0x7E7F8081);
  	Long(0x81828384); Long(0x85868788); Long(0x898A8B8C); Long(0x8C8D8E8F);
  	Long(0x90919293); Long(0x94959596); Long(0x9798999A); Long(0x9B9B9C9D);
  	Long(0x9E9FA0A1); Long(0xA1A2A3A4); Long(0xA5A6A6A7); Long(0xA8A9AAAB);
  	Long(0xABACADAE); Long(0xAFB0B0B1); Long(0xB2B3B4B4); Long(0xB5B6B7B8);
  	Long(0xB8B9BABB); Long(0xBCBCBDBE); Long(0xBFC0C0C1); Long(0xC2C3C3C4);
  	Long(0xC5C6C7C7); Long(0xC8C9CACA); Long(0xCBCCCDCD); Long(0xCECFD0D0);
  	Long(0xD1D2D3D3); Long(0xD4D5D6D6); Long(0xD7D8D9D9); Long(0xDADBDCDC);
  	Long(0xDDDEDFDF); Long(0xE0E1E1E2); Long(0xE3E4E4E5); Long(0xE6E7E7E8);
  	Long(0xE9E9EAEB); Long(0xECECEDEE); Long(0xEEEFF0F1); Long(0xF1F2F3F3);
  	Long(0xF4F5F5F6); Long(0xF7F8F8F9); Long(0xFAFAFBFC); Long(0xFCFDFEFF);
  
  	gammaDir = p;						// Gamma directory
  	Offs(0x80, defaultGamma);
  	EndOfList();
  
  	for (m = VideoMonitors.begin(); m != mend; ++m)
  		sRsrcVideo.push_back(VMonitor(**m, videoType, videoName, vidDrvrDir, gammaDir));
  
  	// CPU sResource
  	cpuType = p;						// Literals
  	Word(10); Word(3); Word(0); Word(24);	// CPU 68020
  	cpuName = p;
  	String("CPU_68020");
  	cpuMajor = p;
  	Long(0); Long(0x7fffffff);
  	cpuMinor = p;
  	Long(0xf0800000); Long(0xf0ffffff);
  
  	sRsrcCPU = p;
  	Offs(0x01, cpuType);				// Type descriptor
  	Offs(0x02, cpuName);				// CPU name
  	Offs(0x81, cpuMajor);				// Major RAM space
  	Offs(0x82, cpuMinor);				// Minor RAM space
  	EndOfList();
  
  	// Ethernet sResource
  	etherType = p;						// Literals
  	Word(4); Word(1); Word(1); Word(0x4232);	// Network Ethernet Apple 'B2'
  	etherName = p;
  	String("Network_Ethernet_Apple_BasiliskII");
  
  	etherDrvr = p;						// Video driver
  	Long(0x88);							// Length
  	Word(0x4400); Word(0); Word(0); Word(0);
  	Word(0x4a);							// Open offset
  	Word(0x4e);							// Prime offset
  	Word(0x52);							// Control offset
  	Word(0x4e);							// Status offset
  	Word(0x82);							// Close offset
  	PString(".ENET");
  	Word(0x0111); Word(0x8000);			// Driver version
  	Word(0);
  	PString("1.1.1  ");
  	PString("Basilisk II Ethernet Network Driver");
  	Word(M68K_EMUL_OP_ETHER_OPEN);		// Open()
  	Word(0x4e75);
  	Word(0x70ef);						// Prime()/Status()
  	Word(0x600c);
  	Word(M68K_EMUL_OP_ETHER_CONTROL);	// Control()
  	Word(0x0c68); Word(0x0001); Word(0x001a);
  	Word(0x6602);
  	Word(0x4e75);
  	Word(0x3228); Word(0x0006);			// IOReturn
  	Word(0x0801); Word(0x0009);
  	Word(0x670c);
  	Word(0x4a40);
  	Word(0x6f02);
  	Word(0x4240);
  	Word(0x3140); Word(0x0010);
  	Word(0x4e75);
  	Word(0x4a40);
  	Word(0x6f04);
  	Word(0x4240);
  	Word(0x4e75);
  	Word(0x2f38); Word(0x08fc);
  	Word(0x4e75);
  	Word(0x70e8);						// Close()
  	Word(0x4e75);
  
  	etherDrvrDir = p;					// Driver directory
  	Offs(0x02, etherDrvr);				// sMacOS68020
  	EndOfList();
  
  	sRsrcEther = p;
  	Offs(0x01, etherType);				// Type descriptor
  	Offs(0x02, etherName);				// Driver name
  	Offs(0x04, etherDrvrDir);			// Driver directory
  	Rsrc(0x07, 2);						// Flags: OpenAtStart
  	Rsrc(0x08, 0x4232);					// Hardware device ID ('B2')
  	EndOfList();
  
  	// sResource directory
  	sRsrcDir = p;
  	Offs(0x01, sRsrcBoard);
  	for (m = VideoMonitors.begin(), i = 0; m != mend; ++m, ++i)
  		Offs((*m)->get_slot_id(), sRsrcVideo[i]);
  	Offs(0xf0, sRsrcCPU);
  	Offs(0xf1, sRsrcEther);
  	EndOfList();
  
  	// Format/header block
  	Offs(0, sRsrcDir);					// sResource directory
  	Long(p + 16);						// Length of declaration data
  	Long(0);							// CRC (calculated later)
  	Word(0x0101);						// Rev. level, format
  	Long(0x5a932bc7);					// Test pattern
  	Word(0x000f);						// Byte lanes
  
  	// Copy slot ROM to Mac ROM
  	slot_rom_size = p;
  	memcpy(ROMBaseHost + ROMSize - slot_rom_size, srom, slot_rom_size);
  
  	// Calculate checksum
  	ChecksumSlotROM();
  	return true;
  }
  
  /*
   *  Calculate slot ROM checksum (in-place)
   */
  
  void ChecksumSlotROM(void)
  {
  	// Calculate CRC
  	uint8 *p = ROMBaseHost + ROMSize - slot_rom_size;
  	p[slot_rom_size - 12] = 0;
  	p[slot_rom_size - 11] = 0;
  	p[slot_rom_size - 10] = 0;
  	p[slot_rom_size - 9] = 0;
  	uint32 crc = 0;
  	for (int i=0; i<slot_rom_size; i++) {
  		crc = (crc << 1) | (crc >> 31);
  		crc += p[i];
  	}
  	p[slot_rom_size - 12] = crc >> 24;
  	p[slot_rom_size - 11] = crc >> 16;
  	p[slot_rom_size - 10] = crc >> 8;
  	p[slot_rom_size - 9] = crc;
  }
  