// Videx Videoterm Card Emulator // by Augusto Baffa feb 2024 // // Based on Apple II Simulator // by Peter Koch, May 6, 1993 int videx_slot = 3; bool card_videx = true; bool card_videx_mem_on = false; bool card_videx_80col = false; class VidexCard { /* //notes: // To turn on/off 80 columns mode: // Write at 0xC058 or 0xC059 // card_videx_80col = (addr == 0xc059); // // To Control the card: // // IOSEL (0xC300-C3FFF - slot 3) // Read // r = videxcard.getRomIoSel(addr & 0x1FF); // card_videx_mem_on = true; // Write // card_videx_mem_on = true; // // DEVSEL (0xC0B0-C0BF - slot 3) // Read // r = videxcard.getC0SLOTX(addr); // // Write // videxcard.putC0SLOTX(addr, val); // // IOSTB (0xC800-CFFF) // Read // if (((addr >> 9) & 0b11) == 0b11) card_videx_mem_on = false; // // if (card_videx_mem_on && addr >= 0xC800 && addr <= 0xCDFF) // r = videxcard.getSLOTC8XX(addr & 0x7ff); // // Write // if (((addr >> 9) & 0b11) == 0b11) card_videx_mem_on = false; // // if (card_videx_mem_on && addr >= 0xC800 && addr <= 0xCDFF) // videxcard.putSLOTC8XX(addr - 0xC800, val); // // To Render: // // //for (int y = 0; y < 25; y++) { // for (int x = 0; x < 80; x++) { // // int vkeycode = videxcard.getCSLOTXX(x, y); // get ascii code from memory // bool vinverse = videxcard.isCursorPosition(x, y); // check cursor position to inverse // // for (int i = 0; i < 9; i++) { // // int video_bits = videxcard.getVideoBits(vkeycode, i); // get bits for the current char/scanline // // if (vinverse) // display_bit_80col(renderer, x, y, ~video_bits, i); // render char/scanline // else // display_bit_80col(renderer, x, y, video_bits, i); // render char/scanline // // } // } //} */ private: uint8_t videx_rom[0x400]; // 0x0400 at C800-CBFF uint8_t videx_chars[0xfff]; // 0x0-0x7ff rom 1 | 0x800-0xfff rom2 character rom (12x8) Matrix) uint8_t videx_vram[2048]; // 0x0800 at CC00-CDFF in 4 banks of 0x1FF // internal variables int videx_bankSLOT, videx_regvalSLOT; // active memory bank, selected register unsigned char videx_regSLOT[17];// registers of the CRT-controller //int videx_oldcursorSLOT; // old cursor position //int videx_upperSLOT, videx_lowerSLOT; // cursor size //******************************************************* // Registers // register r/w normal value Name // 00: w 7B Horiz. total // 01: w 50 Horiz. displayed // 02: w 62 Horiz. sync pos // 03: w 29 Horiz. sync width // 04: w 1B Vert. total // 05: w 08 Vert. adjust // 06: w 18 Vert. displayed // 07: w 19 Vert. sync pos // 08: w 00 Interlaced // 09: w 08 Max. scan line // 10:0A w C0 Cursor upper // 11:0B w 08 Cursor lower // 12:0C w 00 Startpos Hi // 13:0D w 00 Startpos Lo // 14:0E r/w 00 Cursor Hi // 15:0F r/w 00 Cursor Lo // 16:10 r 00 Lightpen Hi // 17:11 r 00 Lightpen Lo // // The registers are addressed as follows: // To write To read // LDA #$ LDA #$ // STA $C0B0 STA $C0B0 // LDA #$ LDA $C0B1 // STA $C0B1 //******************************************************* public: int getC0SLOTX(int adr)// 0x0400 at C800-CBFF { int value = 0x00; //define current memory bank videx_bankSLOT = (adr & 0x000c) >> 2; if (adr & 0x0001) // get current register value value = videx_regSLOT[videx_regvalSLOT]; else // define current register videx_regvalSLOT = value; return value; } void putC0SLOTX(int adr, int value)// 0x0400 at C800-CBFF { //define current memory bank videx_bankSLOT = (adr & 0x000c) >> 2; if (adr & 0x0001) { // set current register value videx_regSLOT[videx_regvalSLOT] = value; /* //10:0A Cursor upper //11:0B Cursor lower if ((videx_regvalSLOT == 10) || (videx_regvalSLOT == 11)) modifySLOT(); //14:0E Cursor Hi //15:0F Cursor Lo if ((videx_regvalSLOT == 14) || (videx_regvalSLOT == 15)) cursorSLOT(); //13:0D Startpos Lo if (videx_regvalSLOT == 13) redrawSLOT(); //12:0C Startpos Hi */ } else // define current register videx_regvalSLOT = value; } // IOSEL READS ROM // when reading using iosel, adds bit at A9 uint8_t getRomIoSel(int addr) { addr |= 0b1000000000; if (addr < 0x0400) return videx_rom[addr & 0x03ff]; return 0; } // Read Video Memory using position x, y int8_t getCSLOTXX(int col, int row) { int vstart = ((videx_regSLOT[12] << 8) | videx_regSLOT[13]); int vcursor = ((videx_regSLOT[14] << 8) | videx_regSLOT[15]); int vaddr = (((row * 80) + col) + vstart) % 0x800; return videx_vram[vaddr]; } // Read Character Rom (Char/scanline) int8_t getVideoBits(int8_t keycode, int line) { return videx_chars[keycode * 16 + line]; } // Is cursor at defined x, y? bool isCursorPosition(int col, int row) { int vstart = ((videx_regSLOT[12] << 8) | videx_regSLOT[13]); int vcursor = ((videx_regSLOT[14] << 8) | videx_regSLOT[15]); return vcursor == (((row * 80) + col) + vstart); } // IOSTB - Get Rom or VRam int getSLOTC8XX(int adr) { if (adr < 0x0400) // Rom is at 0x0-0x3ff return(videx_rom[adr & 0x03ff]); else // VRAM is at 0x600-0x7FF // VRAM has 0x0800 at CC00-CDFF divided in 4 banks of 0x1FF if (adr < 0x0600) return(videx_vram[(adr & 0x01ff) + videx_bankSLOT * 0x0200]); else //600 (or CE00-CF00) return(0); } // IOSTB - set VRam void putSLOTC8XX(int adr, int value) { // VRAM is at 0x600-0x7FF // VRAM has 0x0800 at CC00-CDFF divided in 4 banks of 0x1FF if ((adr >= 0x0400) && (adr < 0x0600)) { int vadr; vadr = (adr & 0x01ff) + videx_bankSLOT * 0x0200; videx_vram[vadr] = value; //drawSLOT(vadr, value); // ignored } } void card_videx_init() { FILE *g; int i; int value, bits, crow, ccol; // Read videx rom printf("Loading rom: videx_firmware.rom\n"); g = fopen("videx_firmware.rom", "r"); if (g == 0) { fprintf(stderr, "can't find 'videx_firmware.rom'.\n"); exit(1); } fread(videx_rom, 1, 0x0400, g); fclose(g); // Read videx character rom printf("Loading rom: videx_chars.rom\n"); g = fopen("videx_chars.rom", "r"); if (g == 0) { fprintf(stderr, "can't find 'videx_chars.rom'.\n"); exit(1); } fread(videx_chars, 1, 0x1000, g); fclose(g); // initializing registers videx_bankSLOT = 0; videx_regvalSLOT = 0; videx_regSLOT[0] = 0x7b; videx_regSLOT[1] = 0x50; videx_regSLOT[2] = 0x62; videx_regSLOT[3] = 0x29; videx_regSLOT[4] = 0x1b; videx_regSLOT[5] = 0x08; videx_regSLOT[6] = 0x18; videx_regSLOT[7] = 0x19; videx_regSLOT[8] = 0x0; videx_regSLOT[9] = 0x8; videx_regSLOT[10] = 0xc0; videx_regSLOT[11] = 0x8; videx_regSLOT[12] = 0x0; videx_regSLOT[13] = 0x0; videx_regSLOT[14] = 0x0; videx_regSLOT[15] = 0x0; videx_regSLOT[16] = 0x0; videx_regSLOT[17] = 0x0; //videx_upperSLOT = 0; //videx_lowerSLOT = 8; //videx_oldcursorSLOT = 0; for (i = 0; i < 2048; i++) videx_vram[i] = i & 0xff; } /* void drawSLOT(int adr, int value) { int sadr, crow, ccol; // update memory pixmap //XCopyArea(display, charsetSLOT, memorySLOT, gc, 8 * value, 0, 8, 12, adr * 8, 0); // update screen sadr = (0x800 + adr - 256 * videx_regSLOT[12] - videx_regSLOT[13]) & 0x7ff; crow = sadr / 80; ccol = sadr % 80; //printf("FRAMEBUFFER [W] %d x %d = %02X {%02x}\n", ccol, crow, value, ((crow * 80) + ccol) * 8 ); //XCopyArea(display, charsetSLOT, wSLOT, gc, 8 * value, 0, 8, 12, ccol * 8, crow * 12); } void cursorSLOT() { int sadr, newcursor, crow, ccol; // remove old cursor drawSLOT(videx_oldcursorSLOT, videx_vram[videx_oldcursorSLOT]); // update cursor newcursor = (256 * videx_regSLOT[14] + videx_regSLOT[15]) & 0x7ff; sadr = (0x800 + newcursor - (256 * videx_regSLOT[12] + videx_regSLOT[13])) & 0x7ff; crow = sadr / 80; ccol = sadr % 80; //XFillRectangle(display, wSLOT, xgcSLOT, ccol * 8, crow * 12 + upperSLOT, 7, lowerSLOT - upperSLOT); //XFlush(display); // remember old cursor videx_oldcursorSLOT = newcursor; } void redrawSLOT() { int sadr, crow, ccol; sadr = (256 * videx_regSLOT[12] + videx_regSLOT[13]) & 0x7ff; for (crow = 0; crow < 24; crow++) { ccol = sadr + 80; if (ccol > 0x800) { ccol &= 0x7ff; //printf("%d x %d\n", ccol, crow); //XCopyArea(display, memorySLOT, wSLOT, gc, 8 * sadr, 0, 8 * (80 - ccol), 12, 0, crow * 12); //XCopyArea(display, memorySLOT, wSLOT, gc, 0, 0, 8 * ccol, 12, 8 * (80 - ccol), crow * 12); } else { //XCopyArea(display, memorySLOT, wSLOT, gc, 8 * sadr, 0, 8 * 80, 12, 0, crow * 12); } sadr = ccol; } cursorSLOT(); } void modifySLOT() { int val; // set upper cursor bound videx_upperSLOT = 0; val = videx_regSLOT[10] & 0x7f; // remove blinking-flag if (val) while ((val & 0x40) == 0) { videx_upperSLOT++; val = val << 1; } // set lower cursor bound videx_lowerSLOT = 12; val = videx_regSLOT[11]; if (val) while ((val & 0x01) == 0) { videx_lowerSLOT--; val = val >> 1; } // if the setting is ridiculous if (videx_upperSLOT >= videx_lowerSLOT) { videx_upperSLOT = 0; videx_lowerSLOT = 12; } // draw new cursor cursorSLOT(); } */ };
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.