Old ISA video cards and AVR

About ten years ago I was given ISA graphics cards from 286 ... 486 cars. Video cards have been tested and since then gathering dust in a box. A couple of years ago, I had an idea, but would it be possible to connect such a video card to a microcontroller? That's what I will tell in the article.



To connect an old ISA-video card is enough 8-bit data bus and 20-bit address bus. Microcontrollers I love the AVR families for their simplicity, so I took Atmega16. But you can take any convenient for you - in this case, the same stm32 legs will be exactly enough without external strapping. But Atmega16 legs on all these tires is not enough, so the address bus was collected on three more Soviet parallel registers (I have a large supply of them) K588IR1. The microcontroller in turn sets part of the address in these three registers. More and is not required.





On the ISA-connector, the outputs of this circuit must be connected as follows:



+5,

+12,

GND,

REFRESH (drawn to + 5V through a resistor),

A0-A19,

D0-D7,

RESET,

MEMW,

MEMR,

Iow

IOR,

ALE,

Rdy,

AEN (connects to GND).









In the picture in red, I marked the required ISA connector pins.



For some video cards, you need to connect -5 V and -12 V (you will have to get them from somewhere - for example, from TracoPower sources) and the OSC signal (14.318 MHz) - it can be generated with a simple K155LN1 generator. Other video cards do not require these lines. Then how lucky. In general, if on the video card the corresponding leg on the ISA is hanging in the air, you just can not connect it. Keep in mind that the video card's consumption on the + 5V line is quite substantial - if you use something like the LM7805 to power, be sure to put it on the radiator (preferably with a fan).



Personally, my assembled construction looks like this:



image



It remains the case for small - somehow initialize the video card and start working with it. There are similar projects on the Internet - I found one ( link ), from where I took the Trident 9000i video card initialization code. In the same program from the Internet there is also an initialization code for the Trident9000C, but in the comments it is indicated that it does not work. I checked. It really does not work - the garbage on the screen and the video card does not respond to writing data to RAM.



Video of work (the picture was transmitted via SPI to Atmega16 (as you can see, these lines are left free on the diagram) via the computer's LPT port):





(I made a reservation in the video - 320x200 mode, not 320x240)



Combining this module with an optical mouse ( an article about using a mouse sensor ), I got this:







If you want to run any available ISA video card, then for this you should find the BIOS of the required video card (say, here ) on the Internet and use the IDA to disassemble it. There is the usual X86 code. It only begins with a non-zero address - there is a signature (2 bytes) and a checksum (1 byte). So, start with the 3rd byte. And successively find out which ports need to be recorded for the card to work. Frankly, I did not have enough patience to understand what is wrong with the Trident9000C.



A module was written to work with the ISA bus:



Module for working with the ISA bus
//**************************************************************************************************** //       ISA //**************************************************************************************************** //**************************************************************************************************** // //**************************************************************************************************** //  #define ADDR_BUS_PORT PORTA #define ADDR_BUS_DDR DDRA //  A0-A7 #define ADDR_BUS_0_7_SELECT_PORT PORTC #define ADDR_BUS_0_7_SELECT_DDR DDRC #define ADDR_BUS_0_7_SELECT 7 //  A8-A15 #define ADDR_BUS_8_15_SELECT_PORT PORTC #define ADDR_BUS_8_15_SELECT_DDR DDRC #define ADDR_BUS_8_15_SELECT 6 //  A16-A19 #define ADDR_BUS_16_19_SELECT_PORT PORTC #define ADDR_BUS_16_19_SELECT_DDR DDRC #define ADDR_BUS_16_19_SELECT 5 //  #define DATA_BUS_PORT PORTB #define DATA_BUS_DDR DDRB #define DATA_BUS_PIN PINB //RESET #define RESET_DDR DDRD #define RESET_PORT PORTD #define RESET 0 //MEMW #define MEMW_DDR DDRD #define MEMW_PORT PORTD #define MEMW 1 //MEMR #define MEMR_DDR DDRD #define MEMR_PORT PORTD #define MEMR 2 //IOW #define IOW_DDR DDRD #define IOW_PORT PORTD #define IOW 3 //IOR #define IOR_DDR DDRD #define IOR_PORT PORTD #define IOR 4 //ALE #define ALE_DDR DDRD #define ALE_PORT PORTD #define ALE 5 //RDY #define RDY_DDR DDRD #define RDY_PORT PORTD #define RDY_PIN PIND #define RDY 6 //**************************************************************************************************** //  //**************************************************************************************************** void System_Init(void);//  void System_SetAddr(unsigned long addr);//    void System_RESET_HI(void);// RESET  1 void System_RESET_LO(void);// RESET  0 void System_MEMW_HI(void);// MEMW  1 void System_MEMW_LO(void);// MEMW  0 void System_MEMR_HI(void);// MEMR  1 void System_MEMR_LO(void);// MEMR  0 void System_IOW_HI(void);// IOW  1 void System_IOW_LO(void);// IOW  0 void System_IOR_HI(void);// IOR  1 void System_IOR_LO(void);// IOR  0 void System_ALE_HI(void);// ALE  1 void System_ALE_LO(void);// ALE  0 void System_WaitReady(void);//   void System_Out8(unsigned short port,unsigned char value);//    UInt8 void System_Out16(unsigned short port,unsigned short value);//    UInt16 unsigned char System_In8(unsigned short port);//    UInt8 unsigned short System_In16(unsigned short port);//    UInt16 void System_Poke8(unsigned long addr,unsigned char value);//    UInt8 void System_Poke16(unsigned long addr,unsigned short value);//    UInt16 unsigned char System_Peek8(unsigned long addr);//    UInt8 unsigned short System_Peek16(unsigned long addr);//    UInt16 //**************************************************************************************************** //  //**************************************************************************************************** //---------------------------------------------------------------------------------------------------- //  //---------------------------------------------------------------------------------------------------- void System_Init(void) { //  DDRA=0; DDRB=0; DDRD=0; DDRC=0; ADDR_BUS_DDR=0xff; DATA_BUS_DDR=0; ADDR_BUS_0_7_SELECT_DDR|=(1<<ADDR_BUS_0_7_SELECT); ADDR_BUS_8_15_SELECT_DDR|=(1<<ADDR_BUS_8_15_SELECT); ADDR_BUS_16_19_SELECT_DDR|=(1<<ADDR_BUS_16_19_SELECT); RESET_DDR|=(1<<RESET); MEMW_DDR|=(1<<MEMW); MEMR_DDR|=(1<<MEMR); IOW_DDR|=(1<<IOW); IOR_DDR|=(1<<IOR); ALE_DDR|=(1<<ALE); RDY_DDR&=0xff^(1<<RDY); RDY_PORT|=1<<RDY; //   asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_0_7_SELECT_PORT)),[bit]"M"(ADDR_BUS_0_7_SELECT)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_8_15_SELECT_PORT)),[bit]"M"(ADDR_BUS_8_15_SELECT)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_16_19_SELECT_PORT)),[bit]"M"(ADDR_BUS_16_19_SELECT)); asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(RESET_PORT)),[bit]"M"(RESET)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOW_PORT)),[bit]"M"(IOW)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOR_PORT)),[bit]"M"(IOR)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMW_PORT)),[bit]"M"(MEMW)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMR_PORT)),[bit]"M"(MEMR)); asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ALE_PORT)),[bit]"M"(ALE)); } //---------------------------------------------------------------------------------------------------- //    //---------------------------------------------------------------------------------------------------- void System_SetAddr(unsigned long addr) { unsigned char al=addr&0xff; unsigned char am=(addr>>8)&0xff; unsigned char ah=(addr>>16)&0xff; System_ALE_LO();//  ALE //     ADDR_BUS_PORT=ah; asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_16_19_SELECT_PORT)),[bit]"M"(ADDR_BUS_16_19_SELECT)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_16_19_SELECT_PORT)),[bit]"M"(ADDR_BUS_16_19_SELECT)); ADDR_BUS_PORT=am; asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_8_15_SELECT_PORT)),[bit]"M"(ADDR_BUS_8_15_SELECT)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_8_15_SELECT_PORT)),[bit]"M"(ADDR_BUS_8_15_SELECT)); ADDR_BUS_PORT=al; asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_0_7_SELECT_PORT)),[bit]"M"(ADDR_BUS_0_7_SELECT)); asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ADDR_BUS_0_7_SELECT_PORT)),[bit]"M"(ADDR_BUS_0_7_SELECT)); System_ALE_HI();//  ALE } //---------------------------------------------------------------------------------------------------- // RESET  1 //---------------------------------------------------------------------------------------------------- inline void System_RESET_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(RESET_PORT)),[bit]"M"(RESET)); } //---------------------------------------------------------------------------------------------------- // RESET  0 //---------------------------------------------------------------------------------------------------- inline void System_RESET_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(RESET_PORT)),[bit]"M"(RESET)); } //---------------------------------------------------------------------------------------------------- // MEMW  1 //---------------------------------------------------------------------------------------------------- inline void System_MEMW_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMW_PORT)),[bit]"M"(MEMW)); } //---------------------------------------------------------------------------------------------------- // MEMW  0 //---------------------------------------------------------------------------------------------------- inline void System_MEMW_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMW_PORT)),[bit]"M"(MEMW)); } //---------------------------------------------------------------------------------------------------- // MEMR  1 //---------------------------------------------------------------------------------------------------- inline void System_MEMR_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMR_PORT)),[bit]"M"(MEMR)); } //---------------------------------------------------------------------------------------------------- // MEMR  0 //---------------------------------------------------------------------------------------------------- inline void System_MEMR_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(MEMR_PORT)),[bit]"M"(MEMR)); } //---------------------------------------------------------------------------------------------------- // IOW  1 //---------------------------------------------------------------------------------------------------- inline void System_IOW_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOW_PORT)),[bit]"M"(IOW)); } //---------------------------------------------------------------------------------------------------- // IOW  0 //---------------------------------------------------------------------------------------------------- inline void System_IOW_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOW_PORT)),[bit]"M"(IOW)); } //---------------------------------------------------------------------------------------------------- // IOR  1 //---------------------------------------------------------------------------------------------------- inline void System_IOR_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOR_PORT)),[bit]"M"(IOR)); } //---------------------------------------------------------------------------------------------------- // IOR  0 //---------------------------------------------------------------------------------------------------- inline void System_IOR_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(IOR_PORT)),[bit]"M"(IOR)); } //---------------------------------------------------------------------------------------------------- // ALE  1 //---------------------------------------------------------------------------------------------------- inline void System_ALE_HI(void) { asm volatile ("sbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ALE_PORT)),[bit]"M"(ALE)); } //---------------------------------------------------------------------------------------------------- // ALE  0 //---------------------------------------------------------------------------------------------------- inline void System_ALE_LO(void) { asm volatile ("cbi %[port],%[bit]"::[port]"I"(_SFR_IO_ADDR(ALE_PORT)),[bit]"M"(ALE)); } //---------------------------------------------------------------------------------------------------- //   //---------------------------------------------------------------------------------------------------- void System_WaitReady(void) { asm volatile ("nop"::); asm volatile ("nop"::); while(1) { if (RDY_PIN&(1<<RDY)) break; } } //---------------------------------------------------------------------------------------------------- //    UInt8 //---------------------------------------------------------------------------------------------------- void System_Out8(unsigned short port,unsigned char value) { //     DATA_BUS_DDR=0xff; DATA_BUS_PORT=value; System_SetAddr(port); //   System_IOW_LO(); System_WaitReady();//  System_IOW_HI(); DATA_BUS_DDR=0; } //---------------------------------------------------------------------------------------------------- //    UInt16 //---------------------------------------------------------------------------------------------------- void System_Out16(unsigned short port,unsigned short value) { System_Out8(port,value&0xff); System_Out8(port+1,(value>>8)&0xff); } //---------------------------------------------------------------------------------------------------- //    UInt8 //---------------------------------------------------------------------------------------------------- unsigned char System_In8(unsigned short port) { unsigned char byte; System_SetAddr(port); DATA_BUS_DDR=0; //   System_IOR_LO(); System_WaitReady();//  byte=DATA_BUS_PIN; System_IOR_HI(); return(byte); } //---------------------------------------------------------------------------------------------------- //    UInt16 //---------------------------------------------------------------------------------------------------- unsigned short System_In16(unsigned short port) { unsigned short ret=System_In8(port+1); ret<<=8; ret|=System_In8(port); return(ret); } //---------------------------------------------------------------------------------------------------- //    UInt8 //---------------------------------------------------------------------------------------------------- void System_Poke8(unsigned long addr,unsigned char value) { //     DATA_BUS_DDR=0xff; DATA_BUS_PORT=value; System_SetAddr(addr); //   System_MEMW_LO(); System_WaitReady();//  System_MEMW_HI(); DATA_BUS_DDR=0; } //---------------------------------------------------------------------------------------------------- //    UInt16 //---------------------------------------------------------------------------------------------------- void System_Poke16(unsigned long addr,unsigned short value) { System_Poke8(addr,value&0xff); System_Poke8(addr+1,(value>>8)&0xff); } //---------------------------------------------------------------------------------------------------- //    UInt8 //---------------------------------------------------------------------------------------------------- unsigned char System_Peek8(unsigned long addr) { unsigned char byte; System_SetAddr(addr); DATA_BUS_DDR=0; //   System_MEMR_LO(); System_WaitReady();//  byte=DATA_BUS_PIN; System_MEMR_HI(); return(byte); } //---------------------------------------------------------------------------------------------------- //    UInt16 //---------------------------------------------------------------------------------------------------- unsigned short System_Peek16(unsigned long addr) { unsigned short ret=System_Peek8(addr+1); ret<<=8; ret|=System_Peek8(addr); return(ret); }
      
      







Trident 9000i video card is initialized like this:



Trident 9000i video card initialization
 //**************************************************************************************************** //     trident //**************************************************************************************************** //**************************************************************************************************** // //**************************************************************************************************** //**************************************************************************************************** //  //**************************************************************************************************** CHIP_TYPE TRIDENT_Init(void);//   Trident unsigned char TRIDENT_TestInx2(unsigned short rg,unsigned char ix,unsigned char msk);// true,   MSK  PT   RG  1 void TRIDENT_TR9000i_Init(void);//  Trident9000i void TRIDENT_TR8900D_Init(void);//  Trident8900D bool TRIDENT_Unit_594(void);// 594 void TRIDENT_Unit_5A6(void);// 5A6 bool TRIDENT_Unit_4D9(void);// 4D9 void TRIDENT_Unit_51A(void);// 51A unsigned char TRIDENT_Unit_26A(void);// 26A void TRIDENT_Unit_179(void);// 179 void TRIDENT_Unit_2EA(void);// 2EA unsigned char TRIDENT_Unit_292(void);// 292 //**************************************************************************************************** //  //**************************************************************************************************** //---------------------------------------------------------------------------------------------------- //   Trident //---------------------------------------------------------------------------------------------------- CHIP_TYPE TRIDENT_Init(void) { VGA_Reset();//   CHIP_TYPE chiptype=UNKNOWN;//     //Trident VGA (  8800BR)    2 : // ,   128k,      A000h - BFFFh //     64k,     A000h - AFFFh. System_Out8(VGAENABLE_ADDR,0x00); System_Out8(0x46E8,0x16);//    (D3=0) System_Out8(0x46E9,0x00); System_Out8(0x0102,0x01); System_Out8(0x0103,0x00); System_Out8(0x46E8,0x0E);//    (D3=1) System_Out8(0x46E9,0x00); System_Out8(0x4AE8,0x00); System_Out8(0x4AE9,0x00); VGA_OutReg8(SEQ_ADDR,0x0B,0x00);//  ID    unsigned char chip=System_In8(0x3C5);//    unsigned char old=VGA_InReg8(SEQ_ADDR,0x0E); System_Out8(0x3C5,0x00); unsigned char value=System_In8(0x3C5)&0x0F; System_Out8(0x3C5,old); //   if (value==2) { System_Out8(0x3C5,old^2); switch(chip) { case 0x01: chiptype=TR8800BR; break; case 0x02: chiptype=TR8800CS; break; case 0x03: chiptype=TR8900; break; case 0x04: chiptype=TR8900C; TRIDENT_TR8900D_Init(); break; case 0x13: chiptype=TR8900C; TRIDENT_TR8900D_Init(); break; case 0x23: chiptype=TR9000; TRIDENT_TR9000i_Init(); break; case 0x33: chiptype=TR8900CLD; TRIDENT_TR8900D_Init(); break; case 0x43: chiptype=TR9000i; TRIDENT_TR9000i_Init(); break; case 0x53: chiptype=TR8900CXr; break; case 0x63: chiptype=LCD9100B; break; case 0x83: chiptype=LX8200; break; case 0x93: chiptype=TVGA9400CXi; break; case 0xA3: chiptype=LCD9320; break; case 0x73: chiptype=GUI9420; break; case 0xF3: chiptype=GUI9420; break; } } else { if ((chip==1)&TRIDENT_TestInx2(SEQ_ADDR,0x0E,6)) chiptype=TVGA8800BR; } return(chiptype); } //---------------------------------------------------------------------------------------------------- // true,   MSK  PT   RG  1 //---------------------------------------------------------------------------------------------------- unsigned char TRIDENT_TestInx2(unsigned short rg,unsigned char ix,unsigned char msk) { unsigned char old,nw1,nw2; old=VGA_InReg8(rg,ix); VGA_OutReg8(rg,ix,old&(~msk)); nw1=VGA_InReg8(rg,ix)&msk; VGA_OutReg8(rg,ix,old|msk); nw2=VGA_InReg8(rg,ix)&msk; VGA_OutReg8(rg,ix,old); return((nw1==0)&(nw2==msk)); } //---------------------------------------------------------------------------------------------------- //  Trident9000i //---------------------------------------------------------------------------------------------------- void TRIDENT_TR9000i_Init(void) { unsigned short i=0; System_Out8(VGAENABLE_ADDR,0x00); if (TRIDENT_Unit_4D9()==false) return;// do { System_Out8(0x3C9,0x00); i++; } while (i<768); System_Out8(MISC_ADDR,0x23); TRIDENT_Unit_51A(); } //---------------------------------------------------------------------------------------------------- //  Trident8900D //---------------------------------------------------------------------------------------------------- void TRIDENT_TR8900D_Init(void) { if (TRIDENT_Unit_594()==true) { //  256  System_Out8(0x3C8,0x00); for(unsigned short n=0;n<256;n++) { System_Out8(0x3C9,n);//R System_Out8(0x3C9,0);//G System_Out8(0x3C9,0);//B } System_Out8(MISC_ADDR,0x23); TRIDENT_Unit_5A6(); } if (TRIDENT_Unit_594()==false) { System_In8(STATUS_ADDR); System_Out8(ATTRCON_ADDR,0x20); System_In8(STATUS_ADDR); VGA_OutReg8(CRTC_ADDR,0x020,VGA_InReg8(CRTC_ADDR,0x20)&0xDF); } System_Out8(0x3D8,0x00); VGA_OutReg8(CRTC_ADDR,0x23,0x10); System_Out8(0x3C6,0xff); } //---------------------------------------------------------------------------------------------------- // 594 //---------------------------------------------------------------------------------------------------- bool TRIDENT_Unit_594(void) { VGA_OutReg8(SEQ_ADDR,0x0B,0x00);//   if ((VGA_InReg8(SEQ_ADDR,0x0D)&0x0E)!=0x0C) return(true); if ((System_In8(0x3CC)&0x67)!=0x67) return(true); return(false); } //---------------------------------------------------------------------------------------------------- // 5A6 //---------------------------------------------------------------------------------------------------- void TRIDENT_Unit_5A6(void) { unsigned char al,bh; VGA_InReg8(SEQ_ADDR,0x0B);//   VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)|0x80)^2); bh=(VGA_InReg8(SEQ_ADDR,0x0C)&0xFE)|0x80; if (VGA_InReg8(SEQ_ADDR,0x0B)==0x53)//   { VGA_InReg8(CRTC_ADDR,0x29); VGA_OutReg8(CRTC_ADDR,0x29,0x44); VGA_OutReg8(CRTC_ADDR,0x2B,0x03); VGA_OutReg8(CRTC_ADDR,0x2C,0x3D); VGA_OutReg8(CRTC_ADDR,0x25,0x27); } if (!(!VGA_InReg8(CRTC_ADDR,0x28)&1)) { bh&=0xCE; bh|=0x80; VGA_OutReg8(MISC_ADDR,0x01,0x00);//  0x3D2 (  0x01) al=(VGA_InReg8(CRTC_ADDR,0x28))&0x0C; if (al==0) { al|=0x04; VGA_OutReg8(CRTC_ADDR,0x28,al); } VGA_OutReg8(SEQ_ADDR,0x0F,VGA_InReg8(SEQ_ADDR,0x0F)&0x7F); VGA_InReg8(SEQ_ADDR,0x0C); VGA_OutReg8(SEQ_ADDR,0x0C,bh); VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)&0x7F)^2); if (VGA_InReg8(SEQ_ADDR,0x0F)&0x08) { VGA_InReg8(SEQ_ADDR,0x0B);//   VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)|0x80)^2); al=(VGA_InReg8(SEQ_ADDR,0x0C)&0xFE)|0x80; al&=0xFE; VGA_OutReg8(SEQ_ADDR,0x0C,al); VGA_OutReg8(GRACON_ADDR,0x0F,0x00); al=VGA_InReg8(SEQ_ADDR,0x0C);//  VGA_OutReg8(SEQ_ADDR,0x0F,VGA_InReg8(SEQ_ADDR,0x0F)|0x80); VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)&0x7F)^0x02); } } VGA_OutReg8(SEQ_ADDR,0x0B,0x00);//  VGA_OutReg8(SEQ_ADDR,0x0D,0x20); VGA_OutReg8(SEQ_ADDR,0x0E,0xA0); VGA_InReg8(SEQ_ADDR,0x0B);//   VGA_OutReg8(SEQ_ADDR,0x0E,0x02); al=VGA_InReg8(GRACON_ADDR,0x06);//atvizsglni if (al==0) { al&=0xF3; al|=0x04; VGA_OutReg8(GRACON_ADDR,0x06,al); } VGA_OutReg8(SEQ_ADDR,0x0D,0x00); VGA_InReg8(CRTC_ADDR,0x1E); VGA_OutReg8(CRTC_ADDR,0x1E,0x00); if (VGA_InReg8(SEQ_ADDR,0x0B)==0x53) VGA_OutReg8(CRTC_ADDR,0x20,0x1D);//   else VGA_OutReg8(CRTC_ADDR,0x20,0x1C); VGA_OutReg8(CRTC_ADDR,0x29,0x44); } //---------------------------------------------------------------------------------------------------- // 4D9 //---------------------------------------------------------------------------------------------------- bool TRIDENT_Unit_4D9(void) { unsigned char al; al=TRIDENT_Unit_292()&0x0E; if (al!=0x0C) return(true); al=System_In8(0x3CC)&0x67; if (al!=0x67) return(true); return(false); } //---------------------------------------------------------------------------------------------------- // 51A //---------------------------------------------------------------------------------------------------- void TRIDENT_Unit_51A(void) { unsigned char al,bh; bh=(TRIDENT_Unit_26A()|0x80)&0xFE; VGA_OutReg8(SEQ_ADDR,0x07,0x24); System_Out8(MISC_ADDR,0x01); if (!((al=VGA_InReg8(CRTC_ADDR,0x28))&0x0C)) { al|=0x04; VGA_OutReg8(CRTC_ADDR,0x28,al); } VGA_OutReg8(SEQ_ADDR,0x0F,VGA_InReg8(SEQ_ADDR,0x0F)&0x7F); VGA_OutReg8(SEQ_ADDR,0x0C,bh); VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)&0x7F)^2); if (VGA_InReg8(SEQ_ADDR,0x0F)&0x08) TRIDENT_Unit_179(); TRIDENT_Unit_2EA();//  VGA_OutReg8(SEQ_ADDR,0x0D,0x20); VGA_OutReg8(SEQ_ADDR,0x0E,0xA0); VGA_InReg8(SEQ_ADDR,0x0B);//  VGA_OutReg8(SEQ_ADDR,0x0E,0x02); if (!((al=VGA_InReg8(GRACON_ADDR,0x06))&0x0C)) VGA_OutReg8(GRACON_ADDR,0x06,(al&0xF3)|0x04); VGA_OutReg8(SEQ_ADDR,0x0D,0x00); al=VGA_InReg8(CRTC_ADDR,0x1E); VGA_OutReg8(CRTC_ADDR,0x1E,0x00); } //---------------------------------------------------------------------------------------------------- // 26A //---------------------------------------------------------------------------------------------------- unsigned char TRIDENT_Unit_26A(void) { VGA_InReg8(SEQ_ADDR,0x0B);//   VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)|0x80)^2); return(VGA_InReg8(SEQ_ADDR,0x0C)); } //---------------------------------------------------------------------------------------------------- // 179 //---------------------------------------------------------------------------------------------------- void TRIDENT_Unit_179(void) { // SP  BP VGA_OutReg8(SEQ_ADDR,0x0C,(TRIDENT_Unit_26A()|0x42)&0xFE); VGA_OutReg8(SEQ_ADDR,0x0F,VGA_InReg8(SEQ_ADDR,0x0F)|0x80); VGA_OutReg8(SEQ_ADDR,0x0E,(VGA_InReg8(SEQ_ADDR,0x0E)&0x7F)^2); } //---------------------------------------------------------------------------------------------------- // 2EA //---------------------------------------------------------------------------------------------------- void TRIDENT_Unit_2EA(void) { VGA_OutReg8(SEQ_ADDR,0x0B,0x00);//   } //---------------------------------------------------------------------------------------------------- // 292 //---------------------------------------------------------------------------------------------------- unsigned char TRIDENT_Unit_292(void) { TRIDENT_Unit_2EA();//   return(VGA_InReg8(SEQ_ADDR,0x0D));// ,  SEQ_ADDR 0x0D }
      
      







I also ran the OAK OTI077 video card (until I accidentally filed a 12 V on it and it did not burn):



Initializing video card OAK OTI077
 //**************************************************************************************************** //     oak //**************************************************************************************************** //**************************************************************************************************** // //**************************************************************************************************** //**************************************************************************************************** //  //**************************************************************************************************** unsigned char OAK_InitData[77] PROGMEM= { 0x01,0x29,0x04,0x10,0x07,0x00,0x01,0x3E, 0x00,0x00,0x80,0x70,0xFF,0x01,0xFF,0xFF, 0x7F,0x00,0xFF,0xC8,0x00,0x00,0xFF,0x00, 0x01,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x01,0x00,0x08,0x00,0x00,0x00,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x00,0x00,0x00,0x00,0x00,0xD8,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00, 0x00,0x00,0x00,0x00,0x10 }; //**************************************************************************************************** //  //**************************************************************************************************** CHIP_TYPE OAK_Init(void);//   Trident unsigned char OAK_TestInx2(unsigned short rg,unsigned char ix,unsigned char msk);// true,   MSK  PT   RG  1 void OAK_OTI077_Init(void);// OAK077 void OAK_OTI087_Init(void);// OAK087 void OAK_Unit218C(void);// 218C void OAK_Unit201B(void);// 201B void OAK_Unit50F(void);// 50F void OAK_Unit58F(unsigned char ah,unsigned char al);// 58F void OAK_Unit552(void);// 552 unsigned char OAK_Unit53D(void);// 53D void OAK_Unit21A8(void);// 21A8 void OAK_Fill3DE(void);// Fill3DE bool OAK_Unit21C9(void);// 21C9 void OAK_Unit2167(unsigned short addr,unsigned char v);// 2167 void OAK_Unit2148(unsigned char v);// 2148 void OAK_Unit2A0F(void);// 2A0F void OAK_Unit28E2(unsigned char al,unsigned char ah);// 28E2 void OAK_Unit28AC(unsigned char al,unsigned char ah);// 28AC void OAK_Unit29E0(void);// 29E0 unsigned char OAK_Unit1CED(void);// 1CED void OAK_Unit1E12(void);// 1E12 void OAK_Unit292D(unsigned char al,unsigned char bl,unsigned char bh);// 292D //**************************************************************************************************** //  //**************************************************************************************************** //---------------------------------------------------------------------------------------------------- //   Trident //---------------------------------------------------------------------------------------------------- CHIP_TYPE OAK_Init(void) { CHIP_TYPE chiptype=UNKNOWN; VGA_Reset(); System_Out8(0x46E8,0x17); System_Out8(0x0102,System_In8(0x0102)|1); System_Out8(0x46E8,0x0F); if (OAK_TestInx2(0x3DE,0x0D,0x38)) { if (OAK_TestInx2(0x3DE,0x23,0x1F)) { if((VGA_InReg8(0x3DE,0x00)&0x02)==0) { chiptype=OAK_087; OAK_OTI087_Init(); } else chiptype=OAK_083; } else { switch(System_In8(0x3DE)/32) { case 0: chiptype=OAK_037C; break; case 2: chiptype=OAK_067; break; case 5: chiptype=OAK_077; OAK_OTI077_Init(); break; case 7: chiptype=OAK_057; break; } } } return(chiptype); } //---------------------------------------------------------------------------------------------------- // true,   MSK  PT   RG  1 //---------------------------------------------------------------------------------------------------- unsigned char OAK_TestInx2(unsigned short rg,unsigned char ix,unsigned char msk) { unsigned char old,nw1,nw2; old=VGA_InReg8(rg,ix); VGA_OutReg8(rg,ix,old&(~msk)); nw1=VGA_InReg8(rg,ix)&msk; VGA_OutReg8(rg,ix,old|msk); nw2=VGA_InReg8(rg,ix)&msk; VGA_OutReg8(rg,ix,old<<8); return((nw1==0)&(nw2==msk)); } //---------------------------------------------------------------------------------------------------- // OAK087 //---------------------------------------------------------------------------------------------------- void OAK_OTI087_Init(void) { System_Out8(0x320,1); System_In8(0x320); OAK_Unit218C(); VGA_OutReg8(0x3DE,0x13,VGA_InReg8(0x3DE,0x13)&0xBF); VGA_OutReg8(0x3DE,0x0B,((VGA_InReg8(0x3DE,0x0B)&0x0F)|(VGA_InReg8(0x3DE,0x10)))&0xF0); OAK_Unit201B(); OAK_Unit50F(); OAK_Unit552(); System_Out8(0x320,2); OAK_Fill3DE(); OAK_Unit21A8(); OAK_Unit218C(); System_Out8(0x320,0x0c); System_Out8(0x46E8,0x17); System_Out8(0x0102,System_In8(0x0102)|1); System_Out8(0x46E8,0x0F); OAK_Fill3DE(); } //---------------------------------------------------------------------------------------------------- // OAK077 //---------------------------------------------------------------------------------------------------- void OAK_OTI077_Init(void) { OAK_Unit2A0F(); VGA_OutReg8(0x3DE,0x0E,VGA_InReg8(0x3DE,0x0E)&0xDE); OAK_Unit1E12(); System_Out8(0x46E8,0x17); System_Out8(0x0102,System_In8(0x0102)|1); System_Out8(0x46E8,0x0F); } //---------------------------------------------------------------------------------------------------- // 218C //---------------------------------------------------------------------------------------------------- void OAK_Unit218C(void) { OAK_Unit2148(0x0F); if (OAK_Unit21C9()==false) return; OAK_Unit2167(0x0094,0x01); if (OAK_Unit21C9()==false) return; OAK_Unit2167(0x0394,0x01); return; } //---------------------------------------------------------------------------------------------------- // 201B //---------------------------------------------------------------------------------------------------- void OAK_Unit201B(void) { unsigned char ah; System_In8(0x3C8); ah=System_In8(0x3C6); System_In8(0x3C8); System_In8(0x3C6); System_In8(0x3C6); System_In8(0x3C6); System_In8(0x3C6); System_Out8(0x3C6,0); System_In8(0x3C8); System_Out8(0x3C6,ah); System_In8(0x3C8); } //---------------------------------------------------------------------------------------------------- // 50F //---------------------------------------------------------------------------------------------------- void OAK_Unit50F(void) { if ((VGA_InReg8(0x3DE,0x07)&0x04)) return; OAK_Unit58F(0xFF,0x05); } //---------------------------------------------------------------------------------------------------- // 58F //---------------------------------------------------------------------------------------------------- void OAK_Unit58F(unsigned char ah,unsigned char al) { System_Out8(0x1E,al); System_Out8(0x1F,ah); } //---------------------------------------------------------------------------------------------------- // 552 //---------------------------------------------------------------------------------------------------- void OAK_Unit552(void) { if (OAK_Unit53D()) return; OAK_Unit58F(0x07,0x04); OAK_Unit58F(0xFF,0x05); OAK_Unit58F((VGA_InReg8(0x1E,0xFE)|0x40),0xFE); } //---------------------------------------------------------------------------------------------------- // 53D //---------------------------------------------------------------------------------------------------- unsigned char OAK_Unit53D(void) { if (VGA_InReg8(0x3DE,0x07)&0x04) return(1); return(VGA_InReg8(0x3DE,0x08)&0x03); } //---------------------------------------------------------------------------------------------------- // 21A8 //---------------------------------------------------------------------------------------------------- void OAK_Unit21A8(void) { if (VGA_InReg8(0x3DE,0x07)&0x04) OAK_Unit2148(0x00); else { OAK_Unit2167(0x0094,0x00); OAK_Unit2167(0x0394,0x00); } } //---------------------------------------------------------------------------------------------------- // Fill3DE //---------------------------------------------------------------------------------------------------- void OAK_Fill3DE(void) { unsigned char i; for(i=0;i<77;i++) { unsigned short byte=pgm_read_byte(&(OAK_InitData[i])); VGA_OutReg8(0x3DE,i,byte); } } //---------------------------------------------------------------------------------------------------- // 21C9 //---------------------------------------------------------------------------------------------------- bool OAK_Unit21C9(void) { unsigned char al=0x55,ah=al; while(1) { System_Out8(0x3DE,al); if (al==ah) return(true); al^=0xFF; ah^=0xFF; if (al==0x55 && ah==0x55) return(false); } } //---------------------------------------------------------------------------------------------------- // 2167 //---------------------------------------------------------------------------------------------------- void OAK_Unit2167(unsigned short addr,unsigned char v) { unsigned char ah; ah=System_In8(addr); System_Out8(addr,0x80); System_Out8(0x102,0x01); System_Out8(addr,ah); System_Out8(0x3C3,v); } //---------------------------------------------------------------------------------------------------- // 2148 //---------------------------------------------------------------------------------------------------- void OAK_Unit2148(unsigned char v) { System_Out8(0x46E8,0x17); System_Out8(0x0102,System_In8(0x0102)|1); System_Out8(0x46E8,v); } //---------------------------------------------------------------------------------------------------- // 2A0F //---------------------------------------------------------------------------------------------------- void OAK_Unit2A0F(void) { OAK_Unit28E2(0,8); OAK_Unit28AC(0,0xBE); OAK_Unit29E0(); OAK_Unit292D(0,0x11,0x06); OAK_Unit292D(1,0x11,0x07); OAK_Unit292D(2,0x06,0x1F); OAK_Unit292D(3,0x06,0x15); } //---------------------------------------------------------------------------------------------------- // 28E2 //---------------------------------------------------------------------------------------------------- void OAK_Unit28E2(unsigned char al,unsigned char ah) { unsigned char bl=al,bh=ah; VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)|0x20); System_Out8(0x3C7,0x0E); al=System_In8(0x3C9)&bh; ah^=0xFF; bl&=ah; bl|=al; System_Out8(0x3C8,0x0E); System_Out8(0x3C9,bl); VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)&0xDF); } //---------------------------------------------------------------------------------------------------- // 28AC //---------------------------------------------------------------------------------------------------- void OAK_Unit28AC(unsigned char al,unsigned char ah) { unsigned char bl=al; VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)|0x20); al=System_In8(0x3C6)&ah; ah^=0xFF; bl&=ah; al|=bl; System_Out8(0x3C6,al); VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)&0xDF); } //---------------------------------------------------------------------------------------------------- // 29E0 //---------------------------------------------------------------------------------------------------- void OAK_Unit29E0(void) { if ((System_In8(0x3DE)&0xE0)==0xA0) { if (!(OAK_Unit1CED()&0x20)) OAK_Unit292D(0x0A,0x02,0x0C); else OAK_Unit292D(0x0A,0x03,0x0D); } else OAK_Unit292D(0x0A,0x03,0x0D); } //---------------------------------------------------------------------------------------------------- // 1CED //---------------------------------------------------------------------------------------------------- unsigned char OAK_Unit1CED(void) { return((VGA_InReg8(0x3DE,0x10)&0x4F)|(VGA_InReg8(0x3DE,0x0B)&0xB0)); } //---------------------------------------------------------------------------------------------------- // 1E12 //---------------------------------------------------------------------------------------------------- void OAK_Unit1E12(void) { System_Out8(0x46E8,0x17); System_Out8(0x0102,System_In8(0x0102)|1); System_Out8(0x46E8,0x00); } //---------------------------------------------------------------------------------------------------- // 292D //---------------------------------------------------------------------------------------------------- void OAK_Unit292D(unsigned char al,unsigned char bl,unsigned char bh) { VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)|0x20); System_Out8(0x3C8,al); System_Out8(0x3C9,bh); System_Out8(0x3C9,bl); VGA_OutReg8(0x3DE,0x0D,VGA_InReg8(0x3DE,0x0D)&0xDF); }
      
      







By the way, are there any VGA adapter register specialists? I see strange things in the video mode change code when initializing a video card:



 //   #define ATTRCON_ADDR 0x03C0 System_In8(0x03DA); System_Out8(ATTRCON_ADDR,0x20);
      
      





Here, in general, there is nothing special. Writing to the registers of the attribute controller is done in 2 steps: first write the register number, and then the data. To always start by writing down the number, read ISR1 (from 0x03DA) - so it’s done.



But here's what's strange. Attribute controller has no register 0x20! He has the last register 0x14. And even if such a register would have been, why is there no record of the value? There must be two entries in the port. And here she is alone. I searched the Internet and found that for some reason (I didn’t find it in the books) you can write, say, in the 0x10 register the value 0x20 at a time simply by combining the bits: System_Out8 (ATTRCON_ADDR, 0x10 | 0x20); Then the specified entry writes 0x20 to register 0x00? But why does this work? And is that so? This is interesting to me, that's why - the thing is, sometimes the color falls off after initialization. The palette is simply not set. It can be seen that it is changing, but the colors are not what they should be. If the initialization is done again, then everything is restored. At what stage it happens is not clear. Experimentally, I found out that with high probability, this is just the installation of the video mode. But that's what's wrong there, I do not understand.



β†’ Link to PCB archive

β†’ Link to archive with firmware



All Articles