From 8e1acfa3b1be3bb60b8a23baf6f14f98595fac7a Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 31 Jan 2026 06:17:25 +0100 Subject: [PATCH 01/49] Mouse Systems mice: The last two bytes of the report are now correctly the mouse movement delta between when we've initially prepared the report for sending and when we've reached the 3rd byte. --- src/device/mouse_serial.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 45750ef09..340d3d144 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -143,8 +143,24 @@ sermouse_transmit_byte(mouse_t *dev, int do_next) if (dev->buf_pos == 0) dev->acc_time = 0.0; - if (dev->serial) + if (dev->serial) { + if ((dev->state == STATE_TRANSMIT_REPORT) && (dev->format == FORMAT_PB_5BYTE) && + (dev->buf_pos == 3)) { + /* + The last two bytes are the delta between now and when we originally + prepared the report for sending. + */ + int delta_x = 0; + int delta_y = 0; + + mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0); + + dev->buf[3] = delta_x; /* same as byte 1 */ + dev->buf[4] = delta_y; /* same as byte 2 */ + } + serial_write_fifo(dev->serial, dev->buf[dev->buf_pos]); + } if (do_next) { /* If we have a buffer length of 0, pretend the state is STATE_SKIP_PACKET. */ From e7fee34332c61b9209468a4e8335d05cc02f32f6 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 14:41:04 +0100 Subject: [PATCH 02/49] ESC/P 2: 4 versions, filtering by version, selectable paper. The four versions are: - EX-1000 and 7 other early printers (including FX-80, the only Epson available OOTB for Windows 1.03), have ESC i and ESC j. - 9-pin ESC/P, a superset of EX-1000 besides ESC i and ESC j. - 24-pin ESC/P in 360 DPI instead of 240. - ESC/P 2 with raster graphics. As for paper, four sizes: Letter, A4, Legal, B4. The former ones are mainly for EX-800, the latter two are sideways and meant for EX-1000. I did some other minor changes, like converting a bunch of defines to enum. --- src/include/86box/prt_papersizes.h | 4 + src/printer/prt_escp.c | 580 ++++++++++++++++++----------- 2 files changed, 373 insertions(+), 211 deletions(-) diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index c45c74568..e468abb35 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -47,4 +47,8 @@ #define A4_PAGE_WIDTH 8.25 #define A4_PAGE_HEIGHT 11.75 +/* Standard B4 */ +#define B4_PAGE_WIDTH 9.875 +#define B4_PAGE_HEIGHT 13.875 + #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 2a50ae54f..e87fa88db 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -72,31 +72,38 @@ #include <86box/prt_devs.h> #include <86box/prt_papersizes.h> +enum { + LANG_EX1000 = 0, // last printer with ESC i and j + LANG_9PIN, + LANG_ESCP, // also known as 24/48-pin + LANG_ESCP2 +}; + +enum { + PAPER_LETTER = 0, + PAPER_A4, + PAPER_LEGAL_SIDE, + PAPER_B4_SIDE +}; + /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_WIDTH LETTER_PAGE_WIDTH -#define PAGE_HEIGHT LETTER_PAGE_HEIGHT -#if 0 -#define PAGE_LMARGIN 0.0 -#define PAGE_RMARGIN PAGE_WIDTH -#define PAGE_TMARGIN 0.0 -#define PAGE_BMARGIN PAGE_HEIGHT -#endif -#define PAGE_DPI 360 -#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_CPI 10.0 /* standard310 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ /* FreeType library handles - global so they can be shared. */ FT_Library ft_lib = NULL; /* The fonts. */ -#define FONT_DEFAULT 0 -#define FONT_ROMAN 1 -#define FONT_SANSSERIF 2 -#define FONT_COURIER 3 -#define FONT_SCRIPT 4 -#define FONT_OCRA 5 -#define FONT_OCRB 6 +enum { + FONT_DEFAULT = 0, + FONT_ROMAN, + FONT_SANSSERIF, + FONT_COURIER, + FONT_SCRIPT, + FONT_OCRA, + FONT_OCRB +}; /* Font styles. */ #define STYLE_PROP 0x0001 @@ -125,20 +132,22 @@ FT_Library ft_lib = NULL; #define QUALITY_LQ 0x02 /* Typefaces. */ -#define TYPEFACE_ROMAN 0 -#define TYPEFACE_SANSSERIF 1 -#define TYPEFACE_COURIER 2 -#define TYPEFACE_PRESTIGE 3 -#define TYPEFACE_SCRIPT 4 -#define TYPEFACE_OCRB 5 -#define TYPEFACE_OCRA 6 -#define TYPEFACE_ORATOR 7 -#define TYPEFACE_ORATORS 8 -#define TYPEFACE_SCRIPTC 9 -#define TYPEFACE_ROMANT 10 -#define TYPEFACE_SANSSERIFH 11 -#define TYPEFACE_SVBUSABA 30 -#define TYPEFACE_SVJITTRA 31 +enum { + TYPEFACE_ROMAN = 0, + TYPEFACE_SANSSERIF, + TYPEFACE_COURIER, + TYPEFACE_PRESTIGE, + TYPEFACE_SCRIPT, + TYPEFACE_OCRB, + TYPEFACE_OCRA, + TYPEFACE_ORATOR, + TYPEFACE_ORATORS, + TYPEFACE_SCRIPTC, + TYPEFACE_ROMANT, + TYPEFACE_SANSSERIFH, + TYPEFACE_SVBUSABA = 30, + TYPEFACE_SVJITTRA +}; /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x + 1] * 256 + dev->esc_parms[x]) @@ -164,6 +173,9 @@ typedef struct escp_t { pc_timer_t pulse_timer; pc_timer_t timeout_timer; + int lang; + int paper_size; + char page_fn[260]; uint8_t color; @@ -423,6 +435,23 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, static void reset_printer(escp_t *dev) { + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + dev->bottom_margin = dev->page_height; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; dev->curr_x = dev->curr_y = 0.0; @@ -430,23 +459,20 @@ reset_printer(escp_t *dev) dev->fss_seen = 0; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width = PAGE_WIDTH; - dev->bottom_margin = dev->page_height = PAGE_HEIGHT; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = QUALITY_DRAFT; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ dev->defined_unit = -1.0; dev->multipoint_mode = 0; @@ -633,73 +659,55 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page case 0x0e: // Select double-width printing (one line) (ESC SO) case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x31: // Select 7/60-inch line spacing - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x38: // Disable paper-out detector - case 0x39: // Enable paper-out detector - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - + case '#': // Cancel MSB control + case '0': // Select 1/8-inch line spacing + case '1': // Select 7/60-inch line spacing + case '2': // Select 1/6-inch line spacing + case '4': // Select italic font + case '5': // Cancel italic font + case '6': // Enable printing of upper control codes + case '7': // Enable upper control codes + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + case '<': // Unidirectional mode (one line) + case '=': // Set MSB to 0 + case '>': // Set MSB to 1 + case '@': // Initialize printer + case 'E': // Select bold font + case 'F': // Cancel bold font + case 'G': // Select double-strike printing + case 'H': // Cancel double-strike printing + case 'M': // Select 10.5-point, 12-cpi + case 'O': // Cancel bottom margin + case 'P': // Select 10.5-point, 10-cpi + case 'T': // Cancel superscript/subscript printing + case '^': // Enable printing of all character codes on next character + dev->esc_parms_req = 0; + break; + case 'g': // Select 10.5-point, 15-cpi + dev->esc_parms_req = 0; + if (dev->lang == LANG_EX1000) { + dev->esc_pending = 0; + return 1; + } + break; + case 0x0a: // Reverse line feed (IBM's ESC LF) + case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) case 0x835: // Cancel italic font (FS 5) (= ESC 5) case 0x846: // Select forward feed mode (FS F) case 0x852: // Select reverse feed mode (FS R) dev->esc_parms_req = 0; + if (dev->lang < LANG_ESCP2) { + dev->esc_pending = 0; + return 1; + } break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x49: // Select character type and print pitch - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x66: // Absolute horizontal tab in columns [conflict] - case 0x68: // Select double or quadruple size - case 0x69: // Immediate print - case 0x6a: // Reverse paper feed - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x73: // Select low-speed mode (ESC s) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) + case 'h': // Select double or quadruple size (IBM's) + case '~': // Select/Deselect slash zero (IBM's?) case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) @@ -708,53 +716,142 @@ process_char(escp_t *dev, uint8_t ch) case 0x849: // Select character table (FS I) (= ESC t) case 0x853: // Select High Speed/High Density elite pitch (FS S) case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '+': // Set n/360-inch line spacing + if (dev->lang < LANG_ESCP) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 'w': // Turn double-height printing on/off + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 0x19: // Control paper loading/ejecting (ESC EM) + case ' ': // Set intercharacter space + case '!': // Master select + case '-': // Turn underline on/off + case '/': // Select vertical tab channel + case '3': // Set n/180-inch line spacing + case 'A': // Set n/60-inch line spacing + case 'C': // Set page length in lines + case 'I': // Select character type and print pitch + case 'J': // Advance print position vertically + case 'N': // Set bottom margin + case 'Q': // Set right margin + case 'R': // Select an international character set + case 'S': // Select superscript/subscript printing + case 'U': // Turn unidirectional mode on/off + case 'W': // Turn double-width printing on/off + case 'a': // Select justification + case 'k': // Select typeface + case 'l': // Set left margin + case 'p': // Turn proportional mode on/off + case 'r': // Select printing color + case 's': // Select low-speed mode + case 't': // Select character table + case 'x': // Select LQ or draft + dev->esc_parms_req = 1; + break; + case 'f': // Absolute horizontal tab in columns + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 1; + break; + case 'i': // Immediate print + case 'j': // Reverse paper feed + if (dev->lang != LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 1; break; - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) + case 'c': // Set horizontal motion index (HMI) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '$': // Set absolute horizontal print position + case '?': // Reassign bit-image mode + case 'K': // Select 60-dpi graphics + case 'L': // Select 120-dpi graphics + case 'Y': // Select 120-dpi, double-speed graphics + case 'Z': // Select 240-dpi graphics + case '\\': // Set relative horizontal print position case 0x85a: // Print 24-bit hex-density graphics (FS Z) dev->esc_parms_req = 2; break; + case 'e': // Set vertical tab stops every n lines + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 2; + break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) + case 'X': // Select font by pitch and point + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '*': // Select bit image dev->esc_parms_req = 3; break; - case 0x5b: // Select character height, width, line spacing + case '[': // Select character height, width, line spacing (IBM's) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 7; break; - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) + case 'b': // Set vertical tabs in VFU channels + case 'B': // Set vertical tabs dev->num_vertical_tabs = 0; return 1; - case 0x44: // Set horizontal tabs (ESC D) + case 'D': // Set horizontal tabs dev->num_horizontal_tabs = 0; return 1; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) + case '%': // Select user-defined set + case '&': // Define user-defined characters + case ':': // Copy ROM to RAM escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); return 1; - case 0x28: // Two bytes sequence + case '(': // Two bytes sequence + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + } /* return and wait for second ESC byte */ return 1; - case 0x2e: - fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); - exit(-1); + case '.': + if (dev->lang >= LANG_ESCP2) { + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + } + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; default: escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", @@ -776,50 +873,67 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Two-byte command pending=%03x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) case 0x025e: // Print data as characters (ESC (^) + if (dev->lang < LANG_ESCP2) + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_pending = 0x101; /* dummy value to be checked later */ + case 0x0242: // Bar code setup and print (ESC (B) dev->esc_parms_req = 2; break; case 0x0255: // Set unit (ESC (U) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 3; break; case 0x0243: // Set page length in defined unit (ESC (C) case 0x0256: // Set absolute vertical print position (ESC (V) case 0x0276: // Set relative vertical print position (ESC (v) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 4; break; - case 0x0228: // Assign character table (ESC (t) case 0x022d: // Select line/score (ESC (-) + if (dev->lang == LANG_9PIN) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } + case 0x0228: // Assign character table (ESC (t) dev->esc_parms_req = 5; break; case 0x0263: // Set page format (ESC (c) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 6; break; - - default: - /* ESC ( commands are always followed by a "number of parameters" word parameter */ - dev->esc_parms_req = 2; - dev->esc_pending = 0x101; /* dummy value to be checked later */ - return 1; } - /* If we need parameters, return and wait for them to appear. */ - if (dev->esc_parms_req > 0) - return 1; + // Wait for more parameters. + return 1; } /* Ignore VFU channel setting. */ - if (dev->esc_pending == 0x62) { - dev->esc_pending = 0x42; + if (dev->esc_pending == 'b') { + dev->esc_pending = 'B'; return 1; } /* Collect vertical tabs. */ - if (dev->esc_pending == 0x42) { + if (dev->esc_pending == 'B') { /* check if we're done */ if ((ch == 0) || (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double) ch * dev->linespacing)) { dev->esc_pending = 0; @@ -830,7 +944,7 @@ process_char(escp_t *dev, uint8_t ch) } /* Collect horizontal tabs. */ - if (dev->esc_pending == 0x44) { + if (dev->esc_pending == 'D') { /* check if we're done... */ if ((ch == 0) || (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double) ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; @@ -887,7 +1001,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x21: /* master select (ESC !) */ + case '!': /* master select */ dev->cpi = (dev->esc_parms[0]) & 0x01 ? 12.0 : 10.0; /* Reset first seven bits. */ @@ -914,11 +1028,11 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x23: /* cancel MSB control (ESC #) */ + case '#': /* cancel MSB control */ dev->msb = 255; break; - case 0x24: /* set abs horizontal print position (ESC $) */ + case '$': /* set abs horizontal print position */ unit_size = dev->defined_unit; if (unit_size < 0) unit_size = 60.0; @@ -932,12 +1046,12 @@ process_char(escp_t *dev, uint8_t ch) setup_bit_image(dev, 40, PARAM16(0)); break; - case 0x2a: /* select bit image (ESC *) */ + case '*': /* select bit image */ setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); break; - case 0x2b: /* set n/360-inch line spacing (ESC +) */ case 0x833: /* Set n/360-inch line spacing (FS 3) */ + case '+': /* set n/360-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 360.0; break; @@ -951,58 +1065,58 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x2f: /* select vertical tab channel (ESC /) */ + case '/': /* select vertical tab channel */ /* Ignore */ break; - case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + case '0': /* select 1/8-inch line spacing */ dev->linespacing = 1.0 / 8.0; break; - case 0x31: /* select 7/60-inch line spacing */ + case '1': /* select 7/60-inch line spacing */ dev->linespacing = 7.0 / 60.0; break; - case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + case '2': /* select 1/6-inch line spacing */ dev->linespacing = 1.0 / 6.0; break; - case 0x33: /* set n/180-inch line spacing (ESC 3) */ + case '3': /* set n/180-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 180.0; break; - case 0x34: /* select italic font (ESC 4) */ + case '4': /* select italic font */ dev->font_style |= STYLE_ITALICS; update_font(dev); break; - case 0x35: /* cancel italic font (ESC 5) */ + case '5': /* cancel italic font */ dev->font_style &= ~STYLE_ITALICS; update_font(dev); break; - case 0x36: /* enable printing of upper control codes (ESC 6) */ + case '6': /* enable printing of upper control codes */ dev->print_upper_control = 1; break; - case 0x37: /* enable upper control codes (ESC 7) */ + case '7': /* enable upper control codes */ dev->print_upper_control = 0; break; - case 0x3c: /* unidirectional mode (one line) (ESC <) */ + case '<': /* unidirectional mode (one line) */ /* We don't have a print head, so just * ignore this. */ break; - case 0x3d: /* set MSB to 0 (ESC =) */ + case '=': /* set MSB to 0 */ dev->msb = 0; break; - case 0x3e: /* set MSB to 1 (ESC >) */ + case '>': /* set MSB to 1 */ dev->msb = 1; break; - case 0x3f: /* reassign bit-image mode (ESC ?) */ + case '?': /* reassign bit-image mode */ if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1013,16 +1127,16 @@ process_char(escp_t *dev, uint8_t ch) dev->density_z = dev->esc_parms[1]; break; - case 0x40: /* initialize printer (ESC @) */ + case '@': /* initialize printer */ reset_printer(dev); break; - case 0x41: /* set n/60-inch line spacing */ - case 0x841: + case 'A': /* set n/60-inch line spacing */ + case 0x841: // FS A dev->linespacing = (double) dev->esc_parms[0] / 60.0; break; - case 0x43: /* set page length in lines (ESC C) */ + case 'C': /* set page length in lines */ if (dev->esc_parms[0] != 0) { dev->page_height = dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; } else { /* == 0 => Set page length in inches */ @@ -1033,69 +1147,69 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x45: /* select bold font (ESC E) */ + case 'E': /* select bold font */ dev->font_style |= STYLE_BOLD; update_font(dev); break; - case 0x46: /* cancel bold font (ESC F) */ + case 'F': /* cancel bold font */ dev->font_style &= ~STYLE_BOLD; update_font(dev); break; - case 0x47: /* select double-strike printing (ESC G) */ + case 'G': /* select double-strike printing */ dev->font_style |= STYLE_DOUBLESTRIKE; break; - case 0x48: /* cancel double-strike printing (ESC H) */ + case 'H': /* cancel double-strike printing */ dev->font_style &= ~STYLE_DOUBLESTRIKE; break; - case 0x4a: /* advance print pos vertically (ESC J n) */ + case 'J': /* advance print pos vertically */ dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; - case 0x4b: /* select 60-dpi graphics (ESC K) */ + case 'K': /* select 60-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; - case 0x4c: /* select 120-dpi graphics (ESC L) */ + case 'L': /* select 120-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; - case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + case 'M': /* select 10.5-point, 12-cpi */ dev->cpi = 12.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x4e: /* set bottom margin (ESC N) */ + case 'N': /* set bottom margin */ dev->top_margin = 0.0; dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; break; - case 0x4f: /* cancel bottom (and top) margin */ + case 'O': /* cancel bottom (and top) margin */ dev->top_margin = 0.0; dev->bottom_margin = dev->page_height; break; - case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + case 'P': /* select 10.5-point, 10-cpi */ dev->cpi = 10.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x51: /* set right margin */ + case 'Q': /* set right margin */ dev->right_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; break; - case 0x52: /* select an intl character set (ESC R) */ + case 'R': /* select an intl character set */ if ((dev->esc_parms[0] <= 13) || (dev->esc_parms[0] == 64)) { if (dev->esc_parms[0] == 64) dev->esc_parms[0] = 14; @@ -1115,7 +1229,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x53: /* select superscript/subscript printing (ESC S) */ + case 'S': /* select superscript/subscript printing */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style |= STYLE_SUBSCRIPT; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[1] == '1')) @@ -1123,16 +1237,16 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x54: /* cancel superscript/subscript printing (ESC T) */ + case 'T': /* cancel superscript/subscript printing */ dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; update_font(dev); break; - case 0x55: /* turn unidirectional mode on/off (ESC U) */ + case 'U': /* turn unidirectional mode on/off */ /* We don't have a print head, so just ignore this. */ break; - case 0x57: /* turn double-width printing on/off (ESC W) */ + case 'W': /* turn double-width printing on/off */ if (!dev->multipoint_mode) { dev->hmi = -1; if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) @@ -1143,7 +1257,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x58: /* select font by pitch and point (ESC X) */ + case 'X': /* select font by pitch and point */ dev->multipoint_mode = 1; /* Copy currently non-multipoint CPI if no value was set so far. */ if (dev->multipoint_cpi == 0.0) { @@ -1165,17 +1279,17 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + case 'Y': /* select 120-dpi, double-speed graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; - case 0x5a: /* select 240-dpi graphics (ESC Z) */ + case 'Z': /* select 240-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; - case 0x5c: /* set relative horizontal print pos (ESC \) */ + case '\\': /* set relative horizontal print pos */ rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) @@ -1183,16 +1297,16 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_x += ((double) rel_move / unit_size); break; - case 0x61: /* select justification (ESC a) */ + case 'a': /* select justification */ /* Ignore. */ break; - case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + case 'c': /* set horizontal motion index (HMI) */ dev->hmi = (double) PARAM16(0) / 360.0; dev->extra_intra_space = 0.0; break; - case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + case 'g': /* select 10.5-point, 15-cpi */ dev->cpi = 15; dev->hmi = -1; dev->multipoint_mode = 0; @@ -1204,7 +1318,7 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing *= -1; break; - case 0x6a: // Reverse paper feed (ESC j) + case 'j': // Reverse paper feed (ESC j) reverse = (double) PARAM16(0) / (double) 216.0; reverse = dev->curr_y - reverse; if (reverse < dev->left_margin) @@ -1213,20 +1327,20 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_y = reverse; break; - case 0x6b: /* select typeface (ESC k) */ + case 'k': /* select typeface */ if ((dev->esc_parms[0] <= 11) || (dev->esc_parms[0] == 30) || (dev->esc_parms[0] == 31)) dev->lq_typeface = dev->esc_parms[0]; update_font(dev); break; - case 0x6c: /* set left margin (ESC 1) */ + case 'l': /* set left margin */ dev->left_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; if (dev->curr_x < dev->left_margin) dev->curr_x = dev->left_margin; break; - case 0x70: /* Turn proportional mode on/off (ESC p) */ + case 'p': /* Turn proportional mode on/off */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_PROP; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[0] == '1')) { @@ -1238,18 +1352,18 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x72: /* select printing color (ESC r) */ + case 'r': /* select printing color */ if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) dev->color = COLOR_BLACK; else dev->color = dev->esc_parms[0] << 5; break; - case 0x73: /* select low-speed mode (ESC s) */ + case 's': /* select low-speed mode */ /* Ignore. */ break; - case 0x74: /* select character table (ESC t) */ + case 't': /* select character table */ case 0x849: /* Select character table (FS I) */ if (dev->esc_parms[0] < 4) { dev->curr_char_table = dev->esc_parms[0]; @@ -1260,7 +1374,7 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x77: /* turn double-height printing on/off (ESC w) */ + case 'w': /* turn double-height printing on/off */ if (!dev->multipoint_mode) { if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_DOUBLEHEIGHT; @@ -1270,7 +1384,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x78: /* select LQ or draft (ESC x) */ + case 'x': /* select LQ or draft */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) { dev->print_quality = QUALITY_DRAFT; dev->font_style |= STYLE_CONDENSED; @@ -1523,9 +1637,12 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_seen = 1; return 1; - case 0x1c: /* FS (IBM commands) */ - dev->fss_seen = 1; - return 1; + case 0x1c: /* FS (IBM Proprinter II) + TODO: Make an IBM printer. */ + if (dev->lang == LANG_ESCP2) { + dev->fss_seen = 1; + return 1; + } default: /* This is a printable character -> print it. */ @@ -1998,6 +2115,8 @@ escp_init(const device_t *info) dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, read_ctrl, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); /* Create a full pathname for the font files. */ @@ -2014,9 +2133,28 @@ escp_init(const device_t *info) plat_dir_create(dev->pagepath); path_slash(dev->pagepath); - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->dpi = PAGE_DPI; + dev->paper_size = device_get_config_int("paper_size"); + + switch (dev->paper_size) { + case PAPER_A4: + dev->page_width = A4_PAGE_WIDTH; + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + dev->page_width = LEGAL_PAGE_HEIGHT; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + dev->page_width = B4_PAGE_HEIGHT; + break; + case PAPER_LETTER: + default: + dev->page_width = LETTER_PAGE_WIDTH; + dev->page_height = LETTER_PAGE_HEIGHT; + } + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2090,6 +2228,29 @@ escp_close(void *priv) // clang-format off #if 0 static const device_config_t lpt_prt_escp_config[] = { + { .name = "", .description = "", .type = CONFIG_END } +}; +#endif +static const device_config_t lpt_prt_escp_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_ESCP2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "EX-1000", .value = LANG_EX1000 }, +#if 0 + { .description = "9-pin", .value = LANG_9PIN }, + { .description = "ESC/P", .value = LANG_ESCP }, +#endif + { .description = "ESC/P 2", .value = LANG_ESCP2 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "paper_size", .description = "Paper Size", @@ -2099,15 +2260,16 @@ static const device_config_t lpt_prt_escp_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Letter", .value = 0 }, - { .description = "A4", .value = 1 }, + { .description = "Letter", .value = PAPER_LETTER }, + { .description = "A4", .value = PAPER_A4 }, + { .description = "Legal (sideways)", .value = PAPER_LEGAL_SIDE }, + { .description = "B4 (sideways)", .value = PAPER_B4_SIDE }, { .description = "" } }, .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; -#endif // clang-format on const device_t lpt_prt_escp_device = { @@ -2121,9 +2283,5 @@ const device_t lpt_prt_escp_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, -#if 0 .config = lpt_prt_escp_config -#else - .config = NULL -#endif }; From c850beccc9cc9f2acd279599f59f41032bd13a2f Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 15:01:34 +0100 Subject: [PATCH 03/49] ESC/P 2: Implement ESC 3, A, M, P, \ for 9-pin ESC/P Also removed forward declarations. --- src/printer/prt_escp.c | 643 ++++++++++++++++++++--------------------- 1 file changed, 313 insertions(+), 330 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e87fa88db..b49589ee0 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -267,23 +267,6 @@ typedef struct escp_t { PALETTE palcol; } escp_t; -static void -update_font(escp_t *dev); -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add); -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken); -static void -init_codepage(escp_t *dev, uint16_t num); -static void -reset_printer(escp_t *dev); -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns); -static void -print_bit_graph(escp_t *dev, uint8_t ch); -static void -new_page(escp_t *dev, int8_t save, int8_t resetx); - /* Codepage table, needed for ESC t ( */ static const uint16_t codepages[15] = { 0, 437, 932, 850, 851, 853, 855, 860, @@ -432,93 +415,6 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, } } -static void -reset_printer(escp_t *dev) -{ - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width; - switch (dev->paper_size) { - case PAPER_A4: - dev->page_height = A4_PAGE_HEIGHT; - break; - case PAPER_LEGAL_SIDE: - dev->page_height = LEGAL_PAGE_WIDTH; - break; - case PAPER_B4_SIDE: - dev->page_height = B4_PAGE_WIDTH; - break; - case PAPER_LETTER: - default: - dev->page_height = LETTER_PAGE_HEIGHT; - } - dev->bottom_margin = dev->page_height; - /* TODO: these should be configurable. */ - dev->color = COLOR_BLACK; - dev->curr_x = dev->curr_y = 0.0; - dev->esc_seen = 0; - dev->fss_seen = 0; - dev->esc_pending = 0; - dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ - dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ - dev->defined_unit = -1.0; - dev->multipoint_mode = 0; - dev->multipoint_size = 0.0; - dev->multipoint_cpi = 0.0; - dev->hmi = -1; - dev->msb = 255; - dev->print_everything_count = 0; - dev->lq_typeface = TYPEFACE_COURIER; - - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - - update_font(dev); - - new_page(dev, 0, 1); - - for (uint8_t i = 0; i < 32; i++) - dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); - dev->num_horizontal_tabs = 32; - dev->num_vertical_tabs = -1; - - if (dev->page != NULL) - dev->page->dirty = 0; - - escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", - dev->page_width, dev->page_height, (int) dev->dpi, - (int) dev->cpi, (int) dev->lpi); -} - -static void -reset_printer_hard(escp_t *dev) -{ - dev->ack = 0; - timer_disable(&dev->pulse_timer); - timer_stop(&dev->timeout_timer); - reset_printer(dev); -} - -/* Select a ASCII->Unicode mapping by CP number */ -static void -init_codepage(escp_t *dev, uint16_t num) -{ - /* Get the codepage map for this number. */ - select_codepage(num, dev->curr_cpmap); -} - static void update_font(escp_t *dev) { @@ -633,6 +529,205 @@ update_font(escp_t *dev) } } +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) +{ + /* Get the codepage map for this number. */ + select_codepage(num, dev->curr_cpmap); +} + +static void +reset_printer(escp_t *dev) +{ + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + dev->bottom_margin = dev->page_height; + /* TODO: these should be configurable. */ + dev->color = COLOR_BLACK; + dev->curr_x = dev->curr_y = 0.0; + dev->esc_seen = 0; + dev->fss_seen = 0; + dev->esc_pending = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = QUALITY_DRAFT; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->defined_unit = -1.0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->hmi = -1; + dev->msb = 255; + dev->print_everything_count = 0; + dev->lq_typeface = TYPEFACE_COURIER; + + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + + update_font(dev); + + new_page(dev, 0, 1); + + for (uint8_t i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = 32; + dev->num_vertical_tabs = -1; + + if (dev->page != NULL) + dev->page->dirty = 0; + + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + dev->page_width, dev->page_height, (int) dev->dpi, + (int) dev->cpi, (int) dev->lpi); +} + +static void +reset_printer_hard(escp_t *dev) +{ + dev->ack = 0; + timer_disable(&dev->pulse_timer); + timer_stop(&dev->timeout_timer); + reset_printer(dev); +} + +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) +{ + escp_log("Density=%d\n", density); + switch (density) { + case 0: + dev->bg_h_density = 60; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 1: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 2: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 3: + dev->bg_h_density = 60; + dev->bg_v_density = 240; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 4: + dev->bg_h_density = 80; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 6: + dev->bg_h_density = 90; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 32: + dev->bg_h_density = 60; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 33: + dev->bg_h_density = 120; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 38: + dev->bg_h_density = 90; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 39: + dev->bg_h_density = 180; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 40: + dev->bg_h_density = 360; + dev->bg_v_density = 180; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 3; + break; + + case 71: + dev->bg_h_density = 180; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 72: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 6; + break; + + case 73: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + default: + escp_log("ESC/P: Unsupported bit image density %d.\n", density); + break; + } + + dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; + dev->bg_bytes_read = 0; +} + /* This is the actual ESC/P interpreter. */ static int process_char(escp_t *dev, uint8_t ch) @@ -1081,8 +1176,8 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing = 1.0 / 6.0; break; - case '3': /* set n/180-inch line spacing */ - dev->linespacing = (double) dev->esc_parms[0] / 180.0; + case '3': /* set n/180 or n/216-inch line spacing */ + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0); break; case '4': /* select italic font */ @@ -1131,9 +1226,9 @@ process_char(escp_t *dev, uint8_t ch) reset_printer(dev); break; - case 'A': /* set n/60-inch line spacing */ + case 'A': /* set n/60 or n/72-inch line spacing */ case 0x841: // FS A - dev->linespacing = (double) dev->esc_parms[0] / 60.0; + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 60.0 : 72.0); break; case 'C': /* set page length in lines */ @@ -1293,7 +1388,7 @@ process_char(escp_t *dev, uint8_t ch) rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) - unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + unit_size = (dev->print_quality == QUALITY_DRAFT || dev->lang < LANG_ESCP) ? 120.0 : 180.0; dev->curr_x += ((double) rel_move / unit_size); break; @@ -1650,6 +1745,115 @@ process_char(escp_t *dev, uint8_t ch) } } +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ +static void +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) +{ + const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + uint8_t src; + uint8_t *dst; + + /* check if freetype is available */ + if (ft_lib == NULL) + return; + + for (unsigned int y = 0; y < bitmap->rows; y++) { + for (unsigned int x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + x + y * bitmap->pitch); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { + dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } else + *dst = src | dev->color; + } + } + } +} + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) +{ + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + + for (unsigned int x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; + if (y < dev->page->h) + *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; + if (y + 1 < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; + } + } +} + +static void +print_bit_graph(escp_t *dev, uint8_t ch) +{ + uint8_t pixel_w; /* width of the "pixel" */ + uint8_t pixel_h; /* height of the "pixel" */ + double old_y; + + dev->bg_column[dev->bg_bytes_read++] = ch; + dev->bg_remaining_bytes--; + + /* Only print after reading a full column. */ + if (dev->bg_bytes_read < dev->bg_bytes_per_column) + return; + + old_y = dev->curr_y; + + pixel_w = 1; + pixel_h = 1; + + if (dev->bg_adjacent) { + /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ + pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; + pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; + } + + for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { + /* for each byte */ + for (uint8_t j = 128; j != 0; j >>= 1) { + /* for each bit */ + if (dev->bg_column[i] & j) { + /* draw a "pixel" */ + for (uint8_t xx = 0; xx < pixel_w; xx++) { + for (uint8_t yy = 0; yy < pixel_h; yy++) { + if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) + *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); + } + } + } + + dev->curr_y += 1.0 / (double) dev->bg_v_density; + } + } + + /* Mark page dirty. */ + dev->page->dirty = 1; + + /* Restore Y-position. */ + dev->curr_y = old_y; + + dev->bg_bytes_read = 0; + + /* Advance print head. */ + dev->curr_x += 1.0 / dev->bg_h_density; +} + static void handle_char(escp_t *dev, uint8_t ch) { @@ -1767,227 +1971,6 @@ handle_char(escp_t *dev, uint8_t ch) } } -/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) -{ - const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; - uint8_t src; - uint8_t *dst; - - /* check if freetype is available */ - if (ft_lib == NULL) - return; - - for (unsigned int y = 0; y < bitmap->rows; y++) { - for (unsigned int x = 0; x < bitmap->width; x++) { - src = *(bitmap->buffer + x + y * bitmap->pitch); - /* ignore background, and respect page size */ - if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { - dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; - src >>= 3; - - if (add) { - if (((*dst) & 0x1f) + src > 31) - *dst |= (dev->color | 0x1f); - else { - *dst += src; - *dst |= dev->color; - } - } else - *dst = src | dev->color; - } - } - } -} - -/* Draw anti-aliased line. */ -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) -{ - unsigned breakmod = dev->dpi / 15; - unsigned gapstart = (breakmod * 4) / 5; - - for (unsigned int x = from_x; x <= to_x; x++) { - /* Skip parts if broken line or going over the border. */ - if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { - if (y > 0 && (y - 1) < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; - if (y < dev->page->h) - *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; - if (y + 1 < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; - } - } -} - -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) -{ - escp_log("Density=%d\n", density); - switch (density) { - case 0: - dev->bg_h_density = 60; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 1: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 2: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 3: - dev->bg_h_density = 60; - dev->bg_v_density = 240; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 4: - dev->bg_h_density = 80; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 6: - dev->bg_h_density = 90; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 32: - dev->bg_h_density = 60; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 33: - dev->bg_h_density = 120; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 38: - dev->bg_h_density = 90; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 39: - dev->bg_h_density = 180; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 40: - dev->bg_h_density = 360; - dev->bg_v_density = 180; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 3; - break; - - case 71: - dev->bg_h_density = 180; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - case 72: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 6; - break; - - case 73: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - default: - escp_log("ESC/P: Unsupported bit image density %d.\n", density); - break; - } - - dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; - dev->bg_bytes_read = 0; -} - -static void -print_bit_graph(escp_t *dev, uint8_t ch) -{ - uint8_t pixel_w; /* width of the "pixel" */ - uint8_t pixel_h; /* height of the "pixel" */ - double old_y; - - dev->bg_column[dev->bg_bytes_read++] = ch; - dev->bg_remaining_bytes--; - - /* Only print after reading a full column. */ - if (dev->bg_bytes_read < dev->bg_bytes_per_column) - return; - - old_y = dev->curr_y; - - pixel_w = 1; - pixel_h = 1; - - if (dev->bg_adjacent) { - /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ - pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; - pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; - } - - for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { - /* for each byte */ - for (uint8_t j = 128; j != 0; j >>= 1) { - /* for each bit */ - if (dev->bg_column[i] & j) { - /* draw a "pixel" */ - for (uint8_t xx = 0; xx < pixel_w; xx++) { - for (uint8_t yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) - *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); - } - } - } - - dev->curr_y += 1.0 / (double) dev->bg_v_density; - } - } - - /* Mark page dirty. */ - dev->page->dirty = 1; - - /* Restore Y-position. */ - dev->curr_y = old_y; - - dev->bg_bytes_read = 0; - - /* Advance print head. */ - dev->curr_x += 1.0 / dev->bg_h_density; -} - static void write_data(uint8_t val, void *priv) { From 397120b28253a4041f52d4013be65d195db21cbd Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 16:26:06 +0100 Subject: [PATCH 04/49] ESC/P 2: 9-bit graphics mode (9-pin ESC/P) --- src/printer/prt_escp.c | 114 ++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index b49589ee0..6269573f9 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -623,47 +623,67 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) switch (density) { case 0: dev->bg_h_density = 60; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 1: dev->bg_h_density = 120; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 2: dev->bg_h_density = 120; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 0; dev->bg_bytes_per_column = 1; break; case 3: - dev->bg_h_density = 60; - dev->bg_v_density = 240; + dev->bg_h_density = 240; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 0; dev->bg_bytes_per_column = 1; break; case 4: dev->bg_h_density = 80; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 5: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 72; + dev->bg_v_density = 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 6: dev->bg_h_density = 90; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 7: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 144; + dev->bg_v_density = 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 32: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 60; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -671,6 +691,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 33: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 120; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -678,6 +700,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 38: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 90; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -685,6 +709,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 39: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 180; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -692,6 +718,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 40: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 360; dev->bg_v_density = 180; dev->bg_adjacent = 0; @@ -699,6 +727,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 71: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 180; dev->bg_v_density = 360; dev->bg_adjacent = 1; @@ -706,6 +736,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 72: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 360; dev->bg_v_density = 360; dev->bg_adjacent = 0; @@ -713,12 +745,32 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 73: + if (dev->lang < LANG_ESCP2) + break; dev->bg_h_density = 360; dev->bg_v_density = 360; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 6; break; + case 254: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 120; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + + case 255: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 60; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + default: escp_log("ESC/P: Unsupported bit image density %d.\n", density); break; @@ -758,14 +810,11 @@ process_char(escp_t *dev, uint8_t ch) case 0x0f: // Select condensed printing (ESC SI) case '#': // Cancel MSB control case '0': // Select 1/8-inch line spacing - case '1': // Select 7/60-inch line spacing case '2': // Select 1/6-inch line spacing case '4': // Select italic font case '5': // Cancel italic font case '6': // Enable printing of upper control codes case '7': // Enable upper control codes - case '8': // Disable paper-out detector - case '9': // Enable paper-out detector case '<': // Unidirectional mode (one line) case '=': // Set MSB to 0 case '>': // Set MSB to 1 @@ -778,7 +827,6 @@ process_char(escp_t *dev, uint8_t ch) case 'O': // Cancel bottom margin case 'P': // Select 10.5-point, 10-cpi case 'T': // Cancel superscript/subscript printing - case '^': // Enable printing of all character codes on next character dev->esc_parms_req = 0; break; case 'g': // Select 10.5-point, 15-cpi @@ -788,6 +836,15 @@ process_char(escp_t *dev, uint8_t ch) return 1; } break; + case '1': // Select 7/72-inch line spacing + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + dev->esc_parms_req = 0; + if (dev->lang >= LANG_ESCP) { + dev->esc_pending = 0; + return 1; + } + break; case 0x0a: // Reverse line feed (IBM's ESC LF) case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) @@ -903,6 +960,16 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_pending = 0; return 1; } + case '^': /* 9-pin ESC/P: Select 60/120-dpi, 9-bit graphics + IBM: Enable printing of all character codes on next character */ + if (dev->lang <= LANG_9PIN) + dev->esc_parms_req = 3; + else { + dev->esc_parms_req = 0; + if (dev->lang == LANG_ESCP) + dev->esc_pending = 0; + } + break; case '*': // Select bit image dev->esc_parms_req = 3; break; @@ -1168,8 +1235,8 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing = 1.0 / 8.0; break; - case '1': /* select 7/60-inch line spacing */ - dev->linespacing = 7.0 / 60.0; + case '1': /* select 7/72-inch line spacing */ + dev->linespacing = 7.0 / 72.0; break; case '2': /* select 1/6-inch line spacing */ @@ -1212,6 +1279,14 @@ process_char(escp_t *dev, uint8_t ch) break; case '?': /* reassign bit-image mode */ + if ((dev->esc_parms[1] == 3 || dev->esc_parms[1] == 5) && dev->lang >= LANG_ESCP) + break; + if (dev->esc_parms[1] > 7) { + if (dev->lang < LANG_ESCP) + break; + if (dev->esc_parms[1] > 40 && dev->lang < LANG_ESCP2) + break; + } if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1267,12 +1342,10 @@ process_char(escp_t *dev, uint8_t ch) break; case 'K': /* select 60-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; case 'L': /* select 120-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; @@ -1375,12 +1448,10 @@ process_char(escp_t *dev, uint8_t ch) break; case 'Y': /* select 120-dpi, double-speed graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; case 'Z': /* select 240-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; @@ -1392,6 +1463,10 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_x += ((double) rel_move / unit_size); break; + case '^': // Select 60/120-dpi, 9-pin graphics) + setup_bit_image(dev, 255 - dev->esc_parms[0], PARAM16(0)); + break; + case 'a': /* select justification */ /* Ignore. */ break; @@ -1414,8 +1489,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'j': // Reverse paper feed (ESC j) - reverse = (double) PARAM16(0) / (double) 216.0; - reverse = dev->curr_y - reverse; + reverse = dev->curr_y - (double) PARAM16(0) / (double) 216.0; if (reverse < dev->left_margin) dev->curr_y = dev->left_margin; else @@ -1827,6 +1901,8 @@ print_bit_graph(escp_t *dev, uint8_t ch) for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { /* for each byte */ for (uint8_t j = 128; j != 0; j >>= 1) { + if (dev->bg_v_density == 72 && i == 1 && j != 128) // 9-bit mode from ESC ^ + break; /* for each bit */ if (dev->bg_column[i] & j) { /* draw a "pixel" */ From 686936714192c9075f9f40d9bd7d3bc16a373297 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 21:24:29 +0100 Subject: [PATCH 05/49] ESC/P 2: Fix ESC J on 9-pin printers --- src/printer/prt_escp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 6269573f9..e8ccb74f9 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1336,7 +1336,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'J': /* advance print pos vertically */ - dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); + dev->curr_y += ((double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0)); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; @@ -1460,7 +1460,8 @@ process_char(escp_t *dev, uint8_t ch) unit_size = dev->defined_unit; if (unit_size < 0) unit_size = (dev->print_quality == QUALITY_DRAFT || dev->lang < LANG_ESCP) ? 120.0 : 180.0; - dev->curr_x += ((double) rel_move / unit_size); + if (dev->curr_x + ((double) rel_move / unit_size) < dev->right_margin) + dev->curr_x += ((double) rel_move / unit_size); break; case '^': // Select 60/120-dpi, 9-pin graphics) From 156f2aaa622841bc12e8a65855d876deb43f0d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sat, 31 Jan 2026 21:45:34 +0100 Subject: [PATCH 06/49] Update CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index e0aaf1410..0fec8df13 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -3,7 +3,7 @@ In order for everyone to enjoy their time contributing to 86Box or otherwise bei ## 1. No illegal activity or GitHub ToS violations - 1.1. Do not distribute malware for non-research purposes. Post samples in a clearly named encrypted archive. -- 1.2. Posting old software is allowed if at least 10 years old and out of support. +- 1.2. Disclosure of copyrighted materials is permitted only if they are demo/trial versions, shareware, freeware, or open-source software, or if they are disclosed by the copyright holder or on the copyright holder’s behalf. If such materials need to be disclosed for testing or bug-fixing purposes, any available private channels should be used. Developers undertake to remove any materials obtained for such purposes as soon as they are no longer needed. - 1.3. Do not post NSFW content (defined at the staff's discretion). - 1.4. Do not do anything forbidden by the law or the Discord or GitHub Terms of Service. From dbb44ebde31bd86968bcab771a381c60cea4ef38 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 04:59:26 +0100 Subject: [PATCH 07/49] Fixed session numbers in the raw TOC mode of READ TOC/PMA/ATIP and cancel sector caching on audio play if the sector to be played is not the one already cached, fixes CD Audio in Rayman for DOS. --- src/cdrom/cdrom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index e5f6ba259..8c781caf7 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -692,14 +692,14 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra int num = 0; int len = 4; - /* Bytes 2 and 3 = Number of first and last sessions */ - read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - cdrom_log(dev->log, "read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", (uintptr_t) dev, (uintptr_t) b, start_track); dev->ops->get_raw_track_info(dev->local, &num, rti); + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + if (num != 0) for (int i = 0; i < num; i++) if (t[i].session >= start_track) { memcpy(&(b[len]), &(t[i]), 11); @@ -1654,6 +1654,9 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int dev->cd_end = len2; dev->cd_status = CD_STATUS_PLAYING; dev->cd_buflen = 0; + + if (dev->cached_sector != dev->seek_pos) + dev->cached_sector = -1; } else { cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); cdrom_stop(dev); From 85a63dd1d64325ad19d8d410387c4ae777d4729c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 05:29:25 +0100 Subject: [PATCH 08/49] Always load HDD audio profiles at initialization. --- src/86box.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/86box.c b/src/86box.c index 24e8be26a..cf992df4c 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1494,6 +1494,7 @@ pc_init_modules(void) fdd_audio_init(); } + hdd_audio_load_profiles(); hdd_audio_init(); sound_init(); From a900405a81b5410ff775679d7ee19f5491e4ea65 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 05:51:16 +0100 Subject: [PATCH 09/49] Settings dialog: On Cancel button, remove the VM directory if it is empty, closes #6769. --- src/qt/qt_settings.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_settings.hpp b/src/qt/qt_settings.hpp index 8603c42b6..b64ea8e83 100644 --- a/src/qt/qt_settings.hpp +++ b/src/qt/qt_settings.hpp @@ -30,6 +30,7 @@ public: static Settings *settings; protected slots: void accept() override; + void reject() override; private: Ui::Settings *ui; From 378ade3d3a5a61d4cb6782031a100b9e999f0121 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 06:34:21 +0100 Subject: [PATCH 10/49] The forgotten qt/qt_settings.cpp. --- src/qt/qt_settings.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp index 312b48996..d1c25a014 100644 --- a/src/qt/qt_settings.cpp +++ b/src/qt/qt_settings.cpp @@ -44,6 +44,9 @@ extern "C" { #include #include +#include +#include + class SettingsModel : public QAbstractListModel { public: SettingsModel(QObject *parent) @@ -236,5 +239,36 @@ Settings::accept() return; } } + QDialog::accept(); } + +static int +plat_path_is_empty(char *path) +{ + int n = 0; + DIR *dir = opendir(path); + struct dirent *d; + + if (dir == NULL) + /* Not a directory or doesn't exist. */ + return 1; + + while ((d = readdir(dir)) != NULL) { + if (++n > 2) + break; + } + + closedir(dir); + + return (n <= 2); +} + +void +Settings::reject() +{ + if (plat_path_is_empty(usr_path)) + rmdir(usr_path); + + QDialog::reject(); +} From f66e2d5fd773ccb841bd393234f3648a972677f7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 07:08:53 +0100 Subject: [PATCH 11/49] Fix Ctrl+NumLock processing. --- src/qt/qt_main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 9d55ba7ca..8a12dd441 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -400,7 +400,8 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) ret = CallNextHookEx(NULL, nCode, wParam, lParam); if (lpKdhs->scanCode == 0x00000045) { - if ((lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000090)) { + if ((lpKdhs->flags & LLKHF_EXTENDED) && ((lpKdhs->vkCode == 0x00000090) || + (lpKdhs->vkCode == 0x00000013))) { /* NumLock. */ lpKdhs->flags &= ~LLKHF_EXTENDED; } else if (!(lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000013)) { From 37a4a99a3e3c6a9e6539a4bb3bbed690ede3167b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 09:14:39 +0100 Subject: [PATCH 12/49] Make the activity indicator orange instead of green to be more easily visible for color-blind people. --- src/qt/icons/active.ico | Bin 9622 -> 9622 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/icons/active.ico b/src/qt/icons/active.ico index 9569a3962ba1d76f735492b689bfd8fd1cd95839..ebd5bb4524a62656d27c8598b103f52f77c8db5c 100644 GIT binary patch literal 9622 zcmeHMJ5Iwu5S@q!geXXnB3;}dQE~%PaSkfP8K_cHA&!A4sG);9aDYhkh>`*^ys`Hs zo3GZ6<0xoG8jZcXGjI3Bo>^~1TGEzIM_@C#Zi`%qNVi+uKkth?p{>^|?r#r8u8u^q zthj%G-zUbN!Uva#P_)Cy0DfzV!k=0;l*-M^M2k3SG2nOiu6pt~(L7dajBWedD#ILX z9j0OaY3t{xY5v&i))}bGfPSdz8*~_{-CKKtSe`+;$@7inE0cTVsG5YiCbm^WPjb)n zdt|Z8$%1^s+*B$r5!K_3b9*KJjK{zs^DAwoJRAKkx&QR@!d|z|fHTk#1Nwcg`qft* z9nY(^TYm|$x`i#YoIzQ)F0q&1fW)!{d|b z#dg#D80rd){QD>M+imd*iq?R^T2C9EomHOceZa`$#WvmBM>+$}fHSbO45%Kc{_d&% zw6MpLd9`-yw{aE3_F)-x0OdYxXa|?g3HM~NZ34Z(i|Y!ntDmu^&U;+bxZjHHxZc%K zqi1J?HCmmH@s?eOI&M7GC)>m?flW?o<-qZipS^#{zr95zo`G7QJ-)%)#*a8ymWMX- z9l`a}f(QN<#G}o5xBez1%wvq%6mAo1a|~y|8E^)i0cXG&*l7lE0MW-EKsaO=;jrNq UhYqGg97xP6`)r(zH^24e4?=A9M*si- literal 9622 zcmeHMy-ve05Wb2Egc#`1p<6RD@&uPeF)|>`_t`ncazmBG zNh+1Q>f-q4?(8r2-N_Z1$W&%CL0QPdROD7f=JQa0Jr#LD+hP&wkLM!y7a~Ow>d%n- zz}PFu;1wD|I|^ArE|VPOmD{RvvWBd3(9=u@WJr*%e$>-c$D!r9%5n~VAzVwCf3x-L zD9R{no0Wz@1_Ex2&G-&pN6b3g8xZ{r+>Q4)^jD-O_^6&p&v;yRRb8DOJwxFPQg=Io z94Ycf)q5A6rY{dae!UXIbjx<~v$`AjEmPJ$D-8idU^E2W*Ntw;;wX zq|kB=*0^#!Uk1;y%yfFbZ75OD6yxt|l~z9-1B5VuoiJNr4V12GRP zz$>ukVQXGojz^j=#pM{*gT4CrqH`H)9#u@!d@C+>PJP7abOq2&+MD}nFXz$s91dx} zjqM>YF#FB--ZA3Ov)E=2VC+$yKdzrtV(^zA@|%P{Dy%=q^!=pnXdY_Q&#CO|+hnai zwH24O1Fg{zFa!(%L% Date: Sun, 1 Feb 2026 21:50:31 -0600 Subject: [PATCH 13/49] CS423x: Make bits 2-0 of control register C0 writable, fixes Win3.1 v2.02 driver invalid codec error and Win9x v2.86 driver code 10 --- src/sound/snd_cs423x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b9004454e..264171b1e 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -290,7 +290,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) ad1848_init(&dev->ad1848, dev->ad1848_type); ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2); } - val = 0x00; + val &= 0x07; break; case 1: /* Version / Chip ID */ From 2d777403f91236c757104bf07e7e72681a79b54f Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sun, 1 Feb 2026 22:11:30 -0600 Subject: [PATCH 14/49] AD1848: Remove old CS423xB/4235/4239 I18/I19 mixer hack as it's no longer needed --- src/sound/snd_ad1848.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 44e328842..181d2158e 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -411,19 +411,6 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) goto readonly_i; } - /* HACK: the Windows 9x driver's "Synth" control writes to this - register with no remapping, even if internal FM is enabled. */ - if (ad1848->index == 18) { - if (val & 0x80) - ad1848->fm_vol_l = 0; - else - ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } else { - if (val & 0x80) - ad1848->fm_vol_r = 0; - else - ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } } if ((ad1848->type >= AD1848_TYPE_CS4232) && (ad1848->type <= AD1848_TYPE_CS4236)) { if (ad1848->index == 18) { From be36624ed95c516bbe7d985a7ce153474ad009be Mon Sep 17 00:00:00 2001 From: Paradyx0392 Date: Mon, 2 Feb 2026 18:28:22 +0800 Subject: [PATCH 15/49] Update de-DE.po --- src/qt/languages/de-DE.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 5dccc6e54..8d0bf7fde 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -55,10 +55,10 @@ msgid "&Resizeable window" msgstr "G&rößenverstellbares Fenster" msgid "R&emember size && position" -msgstr "Größe && &Position merken" +msgstr "Größe und &Position merken" msgid "Remember size && position" -msgstr "Größe && Position merken" +msgstr "Größe und Position merken" msgid "Re&nderer" msgstr "Re&nderer" @@ -742,10 +742,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Die Videokarte \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." +msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." +msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." msgid "Machine" msgstr "System" @@ -2848,10 +2848,10 @@ msgid "Hostname:" msgstr "Hostname:" msgid "ISA RAM:" -msgstr "" +msgstr "ISA RAM:" msgid "ISA ROM:" -msgstr "" +msgstr "ISA ROM:" msgid "&Wipe NVRAM" msgstr "NVRAM leeren" @@ -2869,7 +2869,7 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin msgstr "Beim Leeren des NVRAMs der virtuellen Maschine ist ein Fehler aufgetreten \"%1\"" msgid "%1 VM Manager" -msgstr "" +msgstr "%1 VM-Manager" msgid "%n disk(s)" msgstr "%n Festplatte(n)" From 9d94482040960404f4409bac778ce8b58e706109 Mon Sep 17 00:00:00 2001 From: Paradyx0392 Date: Mon, 2 Feb 2026 18:33:10 +0800 Subject: [PATCH 16/49] Update de-DE.po --- src/qt/languages/de-DE.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 8d0bf7fde..d0e649bc2 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2869,7 +2869,7 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin msgstr "Beim Leeren des NVRAMs der virtuellen Maschine ist ein Fehler aufgetreten \"%1\"" msgid "%1 VM Manager" -msgstr "%1 VM-Manager" +msgstr "%1 VM Manager" msgid "%n disk(s)" msgstr "%n Festplatte(n)" From d7f011e85ffe9164ad775e711bd2a47d67e73639 Mon Sep 17 00:00:00 2001 From: Maxwell Scott Date: Mon, 2 Feb 2026 20:04:32 +0700 Subject: [PATCH 17/49] Added Olivetti OEM BIOS to TriGem Como The Olivetti OEM BIOS' date (06/05/99) is newer than the current one (01/18/99). Until the actual voltage and multiplier bus speeds are found, I adjusted them to match other i440LX/EX machines. Also added a note about onboard video. --- src/include/86box/machine.h | 3 ++ src/machine/m_at_slot1.c | 65 ++++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 13 ++++---- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index caf929c19..ea5d56257 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1210,6 +1210,9 @@ extern int machine_at_ma30d_init(const machine_t *); /* i440EX */ extern int machine_at_brio83xx_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t como_device; +#endif extern int machine_at_como_init(const machine_t *); /* i440BX */ diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index cbd0cdec5..efd5d5d6f 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -544,17 +544,72 @@ machine_at_brio83xx_init(const machine_t *model) return ret; } +static const device_config_t como_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "como", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "AMIBIOS 6 (071595) - Revision 1.08 (Olivetti OEM)", + .internal_name = "como_olivetti", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO_Olivetti_OEM.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 1.12", + .internal_name = "como", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO.ROM", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t como_device = { + .name = "TriGem Como", + .internal_name = "como_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = como_config +}; + int machine_at_como_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/como/COMO.ROM", - 0x000c0000, 262144, 0); - - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000c0000, 262144, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ca484969d..bf13025ff 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -18511,10 +18511,11 @@ const machine_t machines[] = { .block = CPU_BLOCK(CPU_CYRIX3S), .min_bus = 66666667, .max_bus = 83333333, - .min_voltage = 2050, - .max_voltage = 3100, - .min_multi = 3.5, - .max_multi = 5.0 + /* TODO: to find the actual voltage and multiplier bus speeds. */ + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, @@ -18531,11 +18532,11 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &como_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = NULL, /* Onboard video not yet emulated: ATi Rage IIc AGP */ .snd_device = &cs4235_onboard_device, .net_device = NULL }, From 6829fee32af5cabf8ecbfdb544a29affbd68dd9a Mon Sep 17 00:00:00 2001 From: Maxwell Scott Date: Mon, 2 Feb 2026 20:36:03 +0700 Subject: [PATCH 18/49] Added "eMachines OEM" name to revision 1.12 According to their 1.12 BIOS' first POST screen, it appears to be distributed by eMachines. --- src/machine/m_at_slot1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index efd5d5d6f..a40fac2dd 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -566,7 +566,7 @@ static const device_config_t como_config[] = { .files = { "roms/machines/como/COMO_Olivetti_OEM.ROM", "" } }, { - .name = "AMIBIOS 6 (071595) - Revision 1.12", + .name = "AMIBIOS 6 (071595) - Revision 1.12 (eMachines OEM)", .internal_name = "como", .bios_type = BIOS_NORMAL, .files_no = 1, From 7f69f00ed25bd0c34eb2d9e4dba4b2b032e703dc Mon Sep 17 00:00:00 2001 From: aubymori Date: Mon, 2 Feb 2026 19:15:31 -0600 Subject: [PATCH 19/49] Query UI font from system on Windows Previously, we determined the UI font from a predefined set of fonts each mapped to a language. This works well if the user doesn't change their Windows UI font, but if one does, they will get the default UI font associated with their language instead of the one the set. This commit replaces ProgSettings::getFontName with ProgSettings::getUIFont, which uses the SystemParametersInfo API to query the message font from the system, which will allow users to have a custom font. It will also not interfere with different languages, as the message font will be appropriately set by default there. --- src/qt/qt_main.cpp | 2 +- src/qt/qt_mainwindow.cpp | 2 +- src/qt/qt_progsettings.cpp | 56 ++++++++++++++++++++---------- src/qt/qt_progsettings.hpp | 2 +- src/qt/qt_vmmanager_details.cpp | 2 +- src/qt/qt_vmmanager_mainwindow.cpp | 2 +- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 8a12dd441..fd4bc5610 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -622,7 +622,7 @@ main(int argc, char *argv[]) fprintf(stderr, "Qt: version %s, platform \"%s\"\n", qVersion(), QApplication::platformName().toUtf8().data()); ProgSettings::loadTranslators(&app); #ifdef Q_OS_WINDOWS - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); SetCurrentProcessExplicitAppUserModelID(L"86Box.86Box"); #endif diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index f6195389c..1133b26c0 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2431,7 +2431,7 @@ MainWindow::changeEvent(QEvent *event) #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { auto size = this->centralWidget()->size(); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); QApplication::processEvents(); main_window->centralWidget()->setFixedSize(size); QApplication::processEvents(); diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 62b63bbcc..d3ebfa9e8 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -28,6 +28,8 @@ #ifdef Q_OS_WINDOWS # include # include +# define WIN32_LEAN_AND_MEAN +# include #endif extern "C" { @@ -158,26 +160,42 @@ ProgSettings::~ProgSettings() } #ifdef Q_OS_WINDOWS -/* Return the standard font name on Windows, which is overridden per-language - to prevent CJK fonts with embedded bitmaps being chosen as a fallback. */ -QString -ProgSettings::getFontName(int langId) +/* Returns the standard UI font for Windows, which by default varies for different + languages. It can also be changed via external tools, if the user wants that. + + We use the message font here since that is what most Windows components and + other third-party programs use. */ +QFont +ProgSettings::getUIFont() { - QString langCode = languageIdToCode(lang_id); - if (langCode == "ja-JP") { - /* Check for Windows 10 or later to choose the appropriate system font */ - if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) - return "Yu Gothic UI"; - else - return "Meiryo UI"; - } else if (langCode == "ko-KR") - return "Malgun Gothic"; - else if (langCode == "zh-CN") - return "Microsoft YaHei"; - else if (langCode == "zh-TW") - return "Microsoft JhengHei"; - else - return "Segoe UI"; + // Get the system (primary monitor) DPI. The font returned by + // SystemParametersInfo is scaled according to this and we need + // to get the font size in points to pass into QFont's constructor. + HDC hdc = GetDC(NULL); + int systemDpi = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + + // Get the font metrics. + NONCLIENTMETRICSW ncm = {}; + ncm.cbSize = sizeof(ncm); + // This should never happen, but just to be safe, return Segoe UI if + // SPI fails. + if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + return QFont("Segoe UI", 9); + } + + QString fontName = QString::fromWCharArray(ncm.lfMessageFont.lfFaceName); + // Windows' conversion from points to pixels goes as follows: + // + // -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72) + // + // (source: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfontw) + // + // Let's reverse that calculation to get the point size from the message font. + int fontSize = -MulDiv(ncm.lfMessageFont.lfHeight, 72, systemDpi); + + return QFont(fontName, fontSize); } #endif diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 2ada8c2bf..579c5abf7 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -15,7 +15,7 @@ public: explicit ProgSettings(QWidget *parent = nullptr); ~ProgSettings(); #ifdef Q_OS_WINDOWS - static QString getFontName(int langId); + static QFont getUIFont(); #endif static int languageCodeToId(QString langCode); static QString languageIdToCode(int id); diff --git a/src/qt/qt_vmmanager_details.cpp b/src/qt/qt_vmmanager_details.cpp index 40d0fb185..300e227e2 100644 --- a/src/qt/qt_vmmanager_details.cpp +++ b/src/qt/qt_vmmanager_details.cpp @@ -165,7 +165,7 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) connect(this, &VMManagerDetails::styleUpdated, portsSection, &VMManagerDetailSection::updateStyle); connect(this, &VMManagerDetails::styleUpdated, otherSection, &VMManagerDetailSection::updateStyle); - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(ProgSettings::getUIFont()); #endif sysconfig = new VMManagerSystem(); diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp index 17bd898bd..a52002653 100644 --- a/src/qt/qt_vmmanager_mainwindow.cpp +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -269,7 +269,7 @@ VMManagerMainWindow::changeEvent(QEvent *event) { #ifdef Q_OS_WINDOWS if (event->type() == QEvent::LanguageChange) { - QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); + QApplication::setFont(QFont(ProgSettings::getUIFont())); } #endif QWidget::changeEvent(event); From 657155ac9747f7e034a3193ea6a18f0109e61ebd Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 3 Feb 2026 03:29:38 +0100 Subject: [PATCH 20/49] Work around Windows' inappropriate, ugly default fonts when using an East Asian language when it is not also the system language. --- src/qt/qt_progsettings.cpp | 57 ++++++++++++++++++++++++++++++++++++++ src/qt/qt_progsettings.hpp | 1 + 2 files changed, 58 insertions(+) diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index d3ebfa9e8..9be40c1cb 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -159,6 +159,8 @@ ProgSettings::~ProgSettings() delete ui; } +static QString sys_lang; + #ifdef Q_OS_WINDOWS /* Returns the standard UI font for Windows, which by default varies for different languages. It can also be changed via external tools, if the user wants that. @@ -168,6 +170,28 @@ ProgSettings::~ProgSettings() QFont ProgSettings::getUIFont() { + QString langCode = languageIdToCode(lang_id); + + if ((langCode != sys_lang) && ((langCode == "ja-JP") || (langCode == "ko-KR") || + (langCode == "zh-CN") || (langCode == "zh-TW"))) { + /* + Work around Windows' inappropriate, ugly default fonts when using an East Asian + language when it is not also the system language. + */ + if (langCode == "ja-JP") { + /* Check for Windows 10 or later to choose the appropriate system font */ + if (QVersionNumber::fromString(QSysInfo::kernelVersion()).majorVersion() >= 10) + return QFont("Yu Gothic UI", 9); + else + return QFont("Meiryo UI", 9); + } else if (langCode == "ko-KR") + return QFont("Malgun Gothic", 9); + else if (langCode == "zh-CN") + return QFont("Microsoft YaHei", 9); + else if (langCode == "zh-TW") + return QFont("Microsoft JhengHei", 9); + } + // Get the system (primary monitor) DPI. The font returned by // SystemParametersInfo is scaled according to this and we need // to get the font size in points to pass into QFont's constructor. @@ -219,9 +243,42 @@ ProgSettings::languageIdToCode(int id) return languages[id].first; } +void +ProgSettings::getSysLang(QObject *parent) +{ + if (qtTranslator) { + QApplication::removeTranslator(qtTranslator); + qtTranslator = nullptr; + } + if (translator) { + QApplication::removeTranslator(translator); + translator = nullptr; + } + qtTranslator = new QTranslator(parent); + translator = new CustomTranslator(parent); + QString localetofilename = ""; + for (int i = 0; i < QLocale::system().uiLanguages().size(); i++) { + localetofilename = QLocale::system().uiLanguages()[i]; + if (translator->load(QLatin1String("86box_") + localetofilename, QLatin1String(":/"))) { + qDebug() << "Translations loaded."; + QCoreApplication::installTranslator(translator); + /* First try qtbase */ + if (!loadQtTranslations(QLatin1String("qtbase_") + localetofilename.replace('-', '_'))) + /* If that fails, try legacy qt_* translations */ + if (!loadQtTranslations(QLatin1String("qt_") + localetofilename.replace('-', '_'))) + qDebug() << "Failed to find Qt translations!"; + if (QCoreApplication::installTranslator(qtTranslator)) + qDebug() << "Qt translations loaded."; + sys_lang = localetofilename; + break; + } + } +} + void ProgSettings::loadTranslators(QObject *parent) { + getSysLang(parent); if (qtTranslator) { QApplication::removeTranslator(qtTranslator); qtTranslator = nullptr; diff --git a/src/qt/qt_progsettings.hpp b/src/qt/qt_progsettings.hpp index 579c5abf7..cebfa8177 100644 --- a/src/qt/qt_progsettings.hpp +++ b/src/qt/qt_progsettings.hpp @@ -19,6 +19,7 @@ public: #endif static int languageCodeToId(QString langCode); static QString languageIdToCode(int id); + static void getSysLang(QObject *parent = nullptr); static void loadTranslators(QObject *parent = nullptr); static void reloadStrings(); class CustomTranslator : public QTranslator { From 419a3acb85dbe58f59e86668f3dfd4d99d70d84b Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Feb 2026 00:21:50 +0100 Subject: [PATCH 21/49] MDS v2/MDX: Actually use nvr_path() when removing the temporary file, fixes the piling up them. --- src/cdrom/cdrom_image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index fdde47251..20977f48b 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -2965,7 +2965,7 @@ image_close(void *local) free(img); if (temp_file[0] != 0x00) { - remove(temp_file); + remove(nvr_path(temp_file)); temp_file[0] = 0x00; } } From a0e6566eb8e32994a06aa6ab6db1c28cc4a88017 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 4 Feb 2026 02:35:35 +0100 Subject: [PATCH 22/49] Add the ADD-X Normerel Xenon - original patch by Kotochi, plus my fixes. --- src/chipset/opti499.c | 4 +++ src/include/86box/machine.h | 3 +++ src/include/86box/mem.h | 1 + src/machine/m_at_socket3.c | 23 ++++++++++++++++ src/machine/machine_table.c | 53 +++++++++++++++++++++++++++++++++---- src/mem/mem.c | 11 ++++---- 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index ed7c269b0..132754ac7 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -28,6 +28,7 @@ #include <86box/device.h> #include <86box/mem.h> #include <86box/port_92.h> +#include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> #include <86box/chipset.h> @@ -176,6 +177,9 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) break; case 0x22: + mem_a20_chipset = (val & 0x02); + mem_a20_recalc(); + fallthrough; case 0x23: case 0x26: case 0x2d: diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index ea5d56257..824183673 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -749,6 +749,9 @@ extern int machine_at_4gpv5_init(const machine_t *); /* Contaq 82C597 */ extern int machine_at_greenb_init(const machine_t *); +/* OPTi 499 */ +extern int machine_at_xenon_init(const machine_t *); + /* OPTi 895 */ #ifdef EMU_DEVICE_H extern const device_t j403tg_device; diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 9051189a6..1fc95c047 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -307,6 +307,7 @@ extern int read_type; extern int mem_a20_state; extern int mem_a20_alt; +extern int mem_a20_chipset; extern int mem_a20_key; extern uint8_t read_mem_b(uint32_t addr); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index 008394505..bd044d65c 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -166,6 +166,29 @@ machine_at_greenb_init(const machine_t *model) return ret; } +/* OPTi 499 */ +int +machine_at_xenon_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/xenon/addx-bios-7-71-i28f001.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&opti499_device); + device_add(&ide_vlb_device); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C661 | FDC37C6XX_IDE_PRI)); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&intel_flash_bxt_device); + + return ret; +} + /* OPTi 895 */ static const device_config_t j403tg_config[] = { // clang-format off diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bf13025ff..c64e15af8 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -8761,6 +8761,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has AMIKey F KBC firmware. */ + { + .name = "[OPTi 499] ADD-X Normerel Xenon", + .internal_name = "xenon", + .type = MACHINE_TYPE_486_S3, + .chipset = MACHINE_CHIPSET_OPTI_499, + .init = machine_at_xenon_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE | MACHINE_APM, + .ram = { + .min = 1024, + .max = 65536, + .step = 1024 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_AMI | 0x00004600, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Version 1.0 has an AMIKEY-2, version 2.0 has a VIA VT82C42N KBC. */ { .name = "[OPTi 895] Jetway J-403TG", @@ -18511,11 +18555,10 @@ const machine_t machines[] = { .block = CPU_BLOCK(CPU_CYRIX3S), .min_bus = 66666667, .max_bus = 83333333, - /* TODO: to find the actual voltage and multiplier bus speeds. */ - .min_voltage = 1800, - .max_voltage = 3500, - .min_multi = 1.5, - .max_multi = 8.0 + .min_voltage = 2050, + .max_voltage = 3100, + .min_multi = 3.5, + .max_multi = 5.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, diff --git a/src/mem/mem.c b/src/mem/mem.c index 91fa277be..c456c840a 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -106,9 +106,10 @@ int cachesize = 256; uint32_t get_phys_virt; uint32_t get_phys_phys; -int mem_a20_key = 0; -int mem_a20_alt = 0; -int mem_a20_state = 0; +int mem_a20_key = 0; +int mem_a20_alt = 0; +int mem_a20_chipset = 0; +int mem_a20_state = 0; int mmuflush = 0; @@ -3109,12 +3110,12 @@ mem_a20_recalc(void) if (!is286) { rammask = 0xfffff; flushmmucache(); - mem_a20_key = mem_a20_alt = mem_a20_state = 0; + mem_a20_key = mem_a20_alt = mem_a20_state = mem_a20_chipset = 0; return; } - state = mem_a20_key | mem_a20_alt; + state = mem_a20_key | mem_a20_alt | mem_a20_chipset; if (state && !mem_a20_state) { rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; if (is6117) From 2d01fb45603a3515ede2385c16f2ed0a9db196e7 Mon Sep 17 00:00:00 2001 From: DimMan88 Date: Wed, 4 Feb 2026 12:06:59 +0000 Subject: [PATCH 23/49] Translated using Weblate (Greek) Currently translated at 100.0% (1005 of 1005 strings) Translation: 86Box/86Box Translate-URL: https://weblate.86box.net/projects/86box/86box/el/ --- src/qt/languages/el-GR.po | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 6933075a5..1442183df 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-26 17:57+0000\n" +"PO-Revision-Date: 2026-02-04 18:32+0000\n" "Last-Translator: DimMan88 \n" "Language-Team: Greek \n" "Language: el-GR\n" @@ -61,7 +61,7 @@ msgid "Remember size && position" msgstr "Απομνήμευση μεγέθους && θέσης" msgid "Re&nderer" -msgstr "Re&nderer" +msgstr "&Απεικονιστής" msgid "&Qt (Software)" msgstr "&Qt (Software)" @@ -397,7 +397,7 @@ msgid "Enabled (UTC)" msgstr "Ενεργό (UTC)" msgid "Dynamic Recompiler" -msgstr "Dynamic Recompiler" +msgstr "Δυναμικός Αναμεταγλωττιστής" msgid "CPU frame size" msgstr "Μέγεθος πλαισίου CPU" @@ -619,7 +619,7 @@ msgid "Image Format:" msgstr "Τύπος Εικόνας:" msgid "Block Size:" -msgstr "Block Size:" +msgstr "Μέγεθος Block:" msgid "Floppy drives:" msgstr "Οδηγοί δισκέτας:" @@ -721,10 +721,10 @@ msgid "Turbo" msgstr "Turbo" msgid "On" -msgstr "On" +msgstr "Ενεργό" msgid "Off" -msgstr "Off" +msgstr "Ανενεργό" msgid "All images" msgstr "Όλες οι εικόνες" @@ -1080,7 +1080,7 @@ msgid "Cartridge %1: %2" msgstr "Κασέτα δεδομένων %1: %2" msgid "Car&tridge %1: %2" -msgstr "Car&tridge %1: %2" +msgstr "&Κασέτα δεδομένων %1: %2" msgid "Cartridge images" msgstr "Εικόνες κασέτας δεδομένων" @@ -1460,13 +1460,13 @@ msgid "HDX image" msgstr "Εικόνα HDX" msgid "Fixed-size VHD" -msgstr "Fixed-size VHD" +msgstr "Σταθερό-μέγεθος VHD" msgid "Dynamic-size VHD" -msgstr "Dynamic-size VHD" +msgstr "Δυναμικό-μέγεθος VHD" msgid "Differencing VHD" -msgstr "Differencing VHD" +msgstr "Διαφοροποίηση VHD" msgid "(N/A)" msgstr "(Μ/Δ)" @@ -1481,19 +1481,19 @@ msgid "HDX image (.hdx)" msgstr "Εικόνα HDX (.hdx)" msgid "Fixed-size VHD (.vhd)" -msgstr "Fixed-size VHD (.vhd)" +msgstr "Σταθερό-μέγεθος VHD (.vhd)" msgid "Dynamic-size VHD (.vhd)" -msgstr "Dynamic-size VHD (.vhd)" +msgstr "Δυναμικό-μέγεθος VHD (.vhd)" msgid "Differencing VHD (.vhd)" -msgstr "Differencing VHD (.vhd)" +msgstr "Διαφοροποίηση VHD (.vhd)" msgid "Large blocks (2 MB)" -msgstr "Large blocks (2 MB)" +msgstr "Μεγάλα blocks (2 MB)" msgid "Small blocks (512 KB)" -msgstr "Small blocks (512 KB)" +msgstr "Μικρά blocks (512 KB)" msgid "VHD files" msgstr "Αρχεία VHD" @@ -2964,7 +2964,7 @@ msgid "version" msgstr "έκδοση" msgid "build" -msgstr "build" +msgstr "δομή" msgid "You are currently running version %1." msgstr "Τρέχετε την έκδοση %1." From 460c8c73939364dc167b745f81d948631b2f2252 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:07:21 -0600 Subject: [PATCH 24/49] Headland: Make ROMCS Disable bit only affect E0000-EFFFF per the HT18 datasheet --- src/chipset/headland.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 480766103..1c122e126 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -220,9 +220,10 @@ memmap_state_default(headland_t *dev, uint8_t ht_romcs) mem_mapping_disable(&dev->mid_mapping); if (ht_romcs) - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); else - mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0e0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_ROMCS | MEM_WRITE_ROMCS); mem_mapping_disable(&dev->shadow_mapping[0]); From 66f9e0396fb0ab72364bd4853525041e356006ff Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Wed, 4 Feb 2026 20:40:07 -0600 Subject: [PATCH 25/49] Add the Tandy 1000 RSX Machine mostly works but IDE hard disks do not work yet --- src/include/86box/machine.h | 1 + src/include/86box/sound.h | 1 + src/machine/m_at_386sx.c | 27 +++++++++++++++++++++++ src/machine/machine_table.c | 44 +++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 824183673..21e279da7 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -569,6 +569,7 @@ extern int machine_at_acer100t_init(const machine_t *); /* HT18 */ extern int machine_at_ama932j_init(const machine_t *); +extern int machine_at_tandy1000rsx_init(const machine_t *); /* Intel 82335 */ extern int machine_at_adi386sx_init(const machine_t *); diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 71cd65e5a..5cf11bc3c 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -245,6 +245,7 @@ extern const device_t soundman_device; /* Tandy PSSJ */ extern const device_t pssj_device; extern const device_t pssj_isa_device; +extern const device_t pssj_1e0_device; /* Tandy PSG */ extern const device_t tndy_device; diff --git a/src/machine/m_at_386sx.c b/src/machine/m_at_386sx.c index 9ad29e2e8..6b5c4414c 100644 --- a/src/machine/m_at_386sx.c +++ b/src/machine/m_at_386sx.c @@ -42,6 +42,7 @@ #include <86box/vid_cga.h> #include <86box/flash.h> #include <86box/machine.h> +#include <86box/sound.h> /* ISA */ /* @@ -369,6 +370,32 @@ machine_at_ama932j_init(const machine_t *model) return ret; } +int +machine_at_tandy1000rsx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tandy1000rsx/tandy-1000rsx-1-10.00.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&headland_ht18c_device); + device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + device_add(&pssj_1e0_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} + /* Intel 82335 */ int machine_at_adi386sx_init(const machine_t *model) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index c64e15af8..4bf04b2d6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -5468,6 +5468,50 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has unknown KBC firmware */ + { + .name = "[HT18] Tandy 1000 RSX", + .internal_name = "tandy1000rsx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_HT18, + .init = machine_at_tandy1000rsx_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_GAMEPORT, + .ram = { + .min = 1024, + .max = 9216, + .step = 512 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = 0x00000000, + .kbc_p1 = 0x000004f0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5402_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* Most likely has a Phoenix MultiKey/42 keyboard controller. */ { .name = "[Intel 82335] ADI 386SX", From ad2f5c381d59acece210aca3cabe8a623393f953 Mon Sep 17 00:00:00 2001 From: Jeffrey Hope Date: Thu, 5 Feb 2026 05:28:13 +0000 Subject: [PATCH 26/49] Translated using Weblate (Spanish) Currently translated at 100.0% (1005 of 1005 strings) Translation: 86Box/86Box Translate-URL: https://weblate.86box.net/projects/86box/86box/es/ --- src/qt/languages/es-ES.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 4f34c34f5..af2e1e75e 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-11-29 00:34+0000\n" -"Last-Translator: OBattler \n" +"PO-Revision-Date: 2026-02-06 05:57+0000\n" +"Last-Translator: Jeffrey Hope \n" "Language-Team: Spanish \n" "Language: es-ES\n" "MIME-Version: 1.0\n" @@ -1108,7 +1108,7 @@ msgid "Not running" msgstr "No en ejecución" msgid "Running" -msgstr "En ejeución" +msgstr "En ejecución" msgid "Paused" msgstr "En pausa" From 50b961e0b63644657f08d8a46fd5f8aca5b8ef52 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Fri, 6 Feb 2026 20:02:32 +0100 Subject: [PATCH 27/49] ESC/P 2: Add "Auto LF" DIP switch --- src/printer/prt_escp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e8ccb74f9..ad8d2745b 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -265,6 +265,8 @@ typedef struct escp_t { uint8_t ctrl; PALETTE palcol; + + uint8_t auto_lf; } escp_t; /* Codepage table, needed for ESC t ( */ @@ -1749,7 +1751,7 @@ process_char(escp_t *dev, uint8_t ch) case 0x0d: /* Carriage Return (CR) */ dev->curr_x = dev->left_margin; - if (!dev->autofeed) + if (!dev->autofeed && !dev->auto_lf) return 1; fallthrough; @@ -2214,7 +2216,9 @@ escp_init(const device_t *info) dev->page_height = LETTER_PAGE_HEIGHT; } - dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; + dev->auto_lf = device_get_config_int("auto_lf"); + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2328,6 +2332,17 @@ static const device_config_t lpt_prt_escp_config[] = { }, .bios = { { 0 } } }, + { + .name = "auto_lf", + .description = "Auto LF", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } }; // clang-format on From c3094d022dc52d8e292103a9019cc2312927289d Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Fri, 6 Feb 2026 22:32:46 +0100 Subject: [PATCH 28/49] ESC/P 2: Exact paper sizes, 1/36" margins --- src/include/86box/prt_papersizes.h | 24 ++++++++++++------------ src/printer/prt_escp.c | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index e468abb35..f0c9e626a 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -28,27 +28,27 @@ #define LEDGER_PAGE_HEIGHT 17.0 /* Standard A0 */ -#define A0_PAGE_WIDTH 33.125 -#define A0_PAGE_HEIGHT 46.75 +#define A0_PAGE_WIDTH 33.110236 +#define A0_PAGE_HEIGHT 46.811023 /* Standard A1 */ -#define A1_PAGE_WIDTH 23.375 -#define A1_PAGE_HEIGHT 33.125 +#define A1_PAGE_WIDTH 23.385826 +#define A1_PAGE_HEIGHT 33.110236 /* Standard A2 */ -#define A2_PAGE_WIDTH 16.5 -#define A2_PAGE_HEIGHT 23.375 +#define A2_PAGE_WIDTH 16.535433 +#define A2_PAGE_HEIGHT 23.385826 /* Standard A3 */ -#define A3_PAGE_WIDTH 11.75 -#define A3_PAGE_HEIGHT 16.5 +#define A3_PAGE_WIDTH 11.692913 +#define A3_PAGE_HEIGHT 16.535433 /* Standard A4 */ -#define A4_PAGE_WIDTH 8.25 -#define A4_PAGE_HEIGHT 11.75 +#define A4_PAGE_WIDTH 8.267716 +#define A4_PAGE_HEIGHT 11.692913 /* Standard B4 */ -#define B4_PAGE_WIDTH 9.875 -#define B4_PAGE_HEIGHT 13.875 +#define B4_PAGE_WIDTH 9.8425197 +#define B4_PAGE_HEIGHT 13.897637 #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index ad8d2745b..7164ec835 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -542,7 +542,7 @@ init_codepage(escp_t *dev, uint16_t num) static void reset_printer(escp_t *dev) { - dev->top_margin = dev->left_margin = 0.0; + dev->top_margin = dev->left_margin = 1.0 / 36.0; dev->right_margin = dev->page_width; switch (dev->paper_size) { case PAPER_A4: @@ -558,7 +558,7 @@ reset_printer(escp_t *dev) default: dev->page_height = LETTER_PAGE_HEIGHT; } - dev->bottom_margin = dev->page_height; + dev->bottom_margin = dev->page_height - 1.0 / 36.0; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; dev->curr_x = dev->curr_y = 0.0; From eaa4c7063fcac9474add27d52b5e7b69ae0309a5 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:25:34 -0800 Subject: [PATCH 29/49] SLiRP: Support for changing the network. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the default 10.0.2.0/24 (or 10.0.3.0... etc) address can conflict with a LAN (as it does in my case), this feature now adds the ability to set custom network prefixes in the configuration file. I believe this is an “advanced” usage feature (like port forwarding) and should not be exposed in the GUI, therefore no GUI changes have been made. In the `[Network]` section of 86box.cfg, each of the four NICs can be set to have a custom address like such: ``` net_01_addr = 10.80.88.0 net_02_addr = 10.82.86.0 net_03_addr = 10.84.86.0 net_04_addr = 10.85.86.0 ``` The last octet of the address is effectively ignored and always set to 0 again when the configuration file is saved. Only a /24 CIDR (netmask 255.255.255.0) is supported. IPv4 has three local-scope ranges: 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0. Finding a network prefix within these that do not conflict with your real LAN should not pose a problem. --- src/config.c | 36 ++++++++++++++++++++++++++++++++++-- src/include/86box/network.h | 1 + src/network/net_slirp.c | 31 ++++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/config.c b/src/config.c index 52eb05dae..01bffb7f7 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,11 @@ * -DANSI_CFG for use on these systems. */ +#ifdef _WIN32 +# include +#else +# include +#endif #include #ifdef ENABLE_CONFIG_LOG #include @@ -886,6 +891,25 @@ load_network(void) } else strcpy(nc->host_dev_name, "none"); + if (nc->net_type == NET_TYPE_SLIRP) { + sprintf(temp, "net_%02i_addr", c + 1); + p = ini_section_get_string(cat, temp, ""); + if (p && *p) { + struct in_addr addr; + if (inet_aton(p, &addr)) { + uint8_t *bytes = (uint8_t *)&addr.s_addr; + bytes[3] = 0; + sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + } else { + nc->slirp_net[0] = '\0'; + } + sprintf(temp, "net_%02i_switch_group", c + 1); nc->switch_group = ini_section_get_int(cat, temp, NET_SWITCH_GRP_MIN); if (nc->switch_group < NET_SWITCH_GRP_MIN) @@ -1458,7 +1482,7 @@ load_floppy_and_cdrom_drives(void) int c; int d; int count = cdrom_get_type_count(); - + #ifndef DISABLE_FDD_AUDIO fdd_audio_load_profiles(); #endif @@ -1532,7 +1556,7 @@ load_floppy_and_cdrom_drives(void) fdd_set_audio_profile(c, d); #else fdd_set_audio_profile(c, 0); -#endif +#endif for (int i = 0; i < MAX_PREV_IMAGES; i++) { fdd_image_history[c][i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char)); @@ -2987,6 +3011,14 @@ save_network(void) else ini_section_set_int(cat, temp, nc->link_state); + if (nc->net_type == NET_TYPE_SLIRP && nc->slirp_net[0] != '\0') { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_set_string(cat, temp, nc->slirp_net); + } else { + sprintf(temp, "net_%02i_addr", c + 1); + ini_section_delete_var(cat, temp); + } + sprintf(temp, "net_%02i_switch_group", c + 1); if (nc->switch_group == NET_SWITCH_GRP_MIN) ini_section_delete_var(cat, temp); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2c91a6d9f..f3f1b1f8a 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -99,6 +99,7 @@ typedef struct netcard_conf_t { uint32_t link_state; uint8_t switch_group; uint8_t promisc_mode; + char slirp_net[16]; char nrs_hostname[128]; } netcard_conf_t; diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index c7243baac..f29122727 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -493,13 +493,30 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv slirp->pfd = calloc(1, slirp->pfd_size); #endif - /* Set the IP addresses to use. */ - struct in_addr net = { .s_addr = htonl(0x0a000000 | (slirp_card_num << 8)) }; /* 10.0.x.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000002 | (slirp_card_num << 8)) }; /* 10.0.x.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00000f | (slirp_card_num << 8)) }; /* 10.0.x.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000003 | (slirp_card_num << 8)) }; /* 10.0.x.3 */ - struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ + struct in_addr net; + struct in_addr host; + struct in_addr dhcp; + struct in_addr dns; + + /* Set the IP addresses to use. + Use a configured address if set, otherwise 10.0.x.0 */ + const char *slirp_net = net_cards_conf[card->card_num].slirp_net; + if (slirp_net[0] != '\0') { + struct in_addr addr; + inet_aton(slirp_net, &addr); + net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); + host.s_addr = htonl(ntohl(addr.s_addr) + 2); + dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); + dns.s_addr = htonl(ntohl(addr.s_addr) + 3); + } else { + net.s_addr = htonl(0x0a000000 | (slirp_card_num << 8)); /* 10.0.x.0 */ + host.s_addr = htonl(0x0a000002 | (slirp_card_num << 8)); /* 10.0.x.2 */ + dhcp.s_addr = htonl(0x0a00000f | (slirp_card_num << 8)); /* 10.0.x.15 */ + dns.s_addr = htonl(0x0a000003 | (slirp_card_num << 8)); /* 10.0.x.3 */ + } + + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ + struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */ const SlirpConfig slirp_config = { #if SLIRP_CHECK_VERSION(4, 9, 0) From 85e4122f9f7612db323cac0ca7add0fcbb9b3664 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:49:02 -0800 Subject: [PATCH 30/49] Try to fix the build on Windows. Still untested on the OS, but Grok pointed me to the alternative function to use. Hope it works. --- src/config.c | 6 +++++- src/network/net_slirp.c | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 01bffb7f7..fed9541e7 100644 --- a/src/config.c +++ b/src/config.c @@ -28,7 +28,7 @@ */ #ifdef _WIN32 -# include +# include #else # include #endif @@ -896,7 +896,11 @@ load_network(void) p = ini_section_get_string(cat, temp, ""); if (p && *p) { struct in_addr addr; +#ifdef _WIN32 if (inet_aton(p, &addr)) { +#else + if (inet_pton(AF_INET, p, &addr)) { +#endif uint8_t *bytes = (uint8_t *)&addr.s_addr; bytes[3] = 0; sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index f29122727..569891b86 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -43,6 +43,7 @@ #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN # include +# include #else # include #endif @@ -503,7 +504,11 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv const char *slirp_net = net_cards_conf[card->card_num].slirp_net; if (slirp_net[0] != '\0') { struct in_addr addr; +#ifdef _WIN32 + inet_pton(AF_INET, slirp_net, &addr); +#else inet_aton(slirp_net, &addr); +#endif net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); host.s_addr = htonl(ntohl(addr.s_addr) + 2); dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); From 441f396ca10bdfdce22bd2b1ca67f7c46853438d Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Fri, 6 Feb 2026 17:58:42 -0800 Subject: [PATCH 31/49] Use `inet_pton` instead of `inet_aton` This exists on all platforms, no messy #ifdef needed. --- src/config.c | 4 ---- src/network/net_slirp.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/config.c b/src/config.c index fed9541e7..06049713c 100644 --- a/src/config.c +++ b/src/config.c @@ -896,11 +896,7 @@ load_network(void) p = ini_section_get_string(cat, temp, ""); if (p && *p) { struct in_addr addr; -#ifdef _WIN32 - if (inet_aton(p, &addr)) { -#else if (inet_pton(AF_INET, p, &addr)) { -#endif uint8_t *bytes = (uint8_t *)&addr.s_addr; bytes[3] = 0; sprintf(nc->slirp_net, "%d.%d.%d.0", bytes[0], bytes[1], bytes[2]); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 569891b86..86c0896a7 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -504,11 +504,7 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, UNUSED(void *priv const char *slirp_net = net_cards_conf[card->card_num].slirp_net; if (slirp_net[0] != '\0') { struct in_addr addr; -#ifdef _WIN32 inet_pton(AF_INET, slirp_net, &addr); -#else - inet_aton(slirp_net, &addr); -#endif net.s_addr = htonl(ntohl(addr.s_addr) & 0xffffff00); host.s_addr = htonl(ntohl(addr.s_addr) + 2); dhcp.s_addr = htonl(ntohl(addr.s_addr) + 15); From 6fa6e5c1ea7882f7a52c20fdbc773a56b8abc9b2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 7 Feb 2026 18:37:11 +0100 Subject: [PATCH 32/49] Fix video initialization on four 486 machines and the IDE SET DRIVE PARAMETERS command. --- src/disk/hdc_ide.c | 4 ++-- src/machine/m_at_socket1.c | 2 ++ src/machine/m_at_socket2.c | 4 ++++ src/machine/m_at_socket3.c | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 56548766a..8b955c315 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -2610,8 +2610,8 @@ ide_callback(void *priv) err = ABRT_ERR; else { /* Only accept after RESET or DIAG. */ - if (ide->params_specified) { - ide->cfg_spt = ide->tf->secount; + if (!ide->params_specified) { + ide->cfg_spt = (ide->tf->secount == 0) ? 256 : ide->tf->secount; ide->cfg_hpc = ide->tf->head + 1; ide->params_specified = 1; diff --git a/src/machine/m_at_socket1.c b/src/machine/m_at_socket1.c index 7d16e1381..ac836e05f 100644 --- a/src/machine/m_at_socket1.c +++ b/src/machine/m_at_socket1.c @@ -396,6 +396,8 @@ machine_at_tuliptc38_init(const machine_t *model) device_add(&ide_isa_device); device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI)); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) { bios_load_aux_linear("roms/machines/tuliptc38/VBIOS.BIN", 0x000c0000, 32768, 0); diff --git a/src/machine/m_at_socket2.c b/src/machine/m_at_socket2.c index d8fdd79f1..5ec4039b2 100644 --- a/src/machine/m_at_socket2.c +++ b/src/machine/m_at_socket2.c @@ -311,6 +311,8 @@ machine_at_dell466np_init(const machine_t *model) machine_at_common_init(model); device_add(&sis_85c461_device); + video_reset(gfxcard[0]); + if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); else { @@ -354,6 +356,8 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 if (fdc_current[0] == FDC_INTERNAL) device_add(&fdc_at_device); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i); diff --git a/src/machine/m_at_socket3.c b/src/machine/m_at_socket3.c index bd044d65c..7c8c801f6 100644 --- a/src/machine/m_at_socket3.c +++ b/src/machine/m_at_socket3.c @@ -490,6 +490,8 @@ machine_at_tg486g_init(const machine_t *model) device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); + video_reset(gfxcard[0]); + if (gfxcard[0] != VID_INTERNAL) { for (uint16_t i = 0; i < 32768; i++) rom[i] = mem_readb_phys(0x000c0000 + i); From 0b2cc7cee84caebb49aabd94b656328eeda189c1 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 7 Feb 2026 23:07:56 +0100 Subject: [PATCH 33/49] ESC/P 2: Fix dot size and non-adjacent mode with graphics --- src/printer/prt_escp.c | 73 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 7164ec835..e9f6ca71e 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -151,8 +151,8 @@ enum { /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x + 1] * 256 + dev->esc_parms[x]) -#define PIXX ((unsigned) floor(dev->curr_x * dev->dpi + 0.5)) -#define PIXY ((unsigned) floor(dev->curr_y * dev->dpi + 0.5)) +#define PIXX ((unsigned) round(dev->curr_x * dev->dpi)) +#define PIXY ((unsigned) round(dev->curr_y * dev->dpi)) typedef struct psurface_t { int8_t dirty; /* has the page been printed on? */ @@ -204,10 +204,11 @@ typedef struct escp_t { /* bit graphics data */ uint16_t bg_h_density; /* in dpi */ uint16_t bg_v_density; /* in dpi */ - int8_t bg_adjacent; /* print adjacent pixels (ignored) */ + int8_t bg_adjacent; /* print adjacent pixels */ uint8_t bg_bytes_per_column; uint16_t bg_remaining_bytes; /* #bytes left before img is complete */ uint8_t bg_column[6]; /* #bytes of the current and last col */ + uint8_t bg_previous[6]; // for non-adjacent pixels in graphics mode uint8_t bg_bytes_read; /* #bytes read so far for current col */ /* handshake data */ @@ -402,13 +403,11 @@ timeout_timer(void *priv) static void fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, escp_t *dev) { - uint8_t colormask; + const uint8_t colormask = colorID <<= 5; - double red = (double) redmax / (double) 30.9; - double green = (double) greenmax / (double) 30.9; - double blue = (double) bluemax / (double) 30.9; - - colormask = colorID <<= 5; + const double red = (double) redmax / (double) 30.9; + const double green = (double) greenmax / (double) 30.9; + const double blue = (double) bluemax / (double) 30.9; for (uint8_t i = 0; i < 32; i++) { dev->palcol[i + colormask].r = 255 - (uint8_t) floor(red * (double) i); @@ -777,6 +776,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) escp_log("ESC/P: Unsupported bit image density %d.\n", density); break; } + for (uint8_t i = 0; i < dev->bg_bytes_per_column; ++i) + dev->bg_previous[i] = 0; dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; dev->bg_bytes_read = 0; @@ -1879,10 +1880,6 @@ draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broke static void print_bit_graph(escp_t *dev, uint8_t ch) { - uint8_t pixel_w; /* width of the "pixel" */ - uint8_t pixel_h; /* height of the "pixel" */ - double old_y; - dev->bg_column[dev->bg_bytes_read++] = ch; dev->bg_remaining_bytes--; @@ -1890,16 +1887,18 @@ print_bit_graph(escp_t *dev, uint8_t ch) if (dev->bg_bytes_read < dev->bg_bytes_per_column) return; - old_y = dev->curr_y; + /* vertical density is how big the dot is + * (horziontal / vertical / 2) is how many middle points between two full dots are + * if horizontal < vertical, this means a column is printed multiple times + */ + uint8_t dot_size_x; + const uint8_t dot_size_y = round((double) dev->dpi / (double) dev->bg_v_density); + if (dev->bg_h_density < dev->bg_v_density) + dot_size_x = round((double) dev->dpi / (double) dev->bg_h_density); + else + dot_size_x = dot_size_y; - pixel_w = 1; - pixel_h = 1; - - if (dev->bg_adjacent) { - /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ - pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; - pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; - } + const double old_y = dev->curr_y; for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { /* for each byte */ @@ -1908,11 +1907,21 @@ print_bit_graph(escp_t *dev, uint8_t ch) break; /* for each bit */ if (dev->bg_column[i] & j) { - /* draw a "pixel" */ - for (uint8_t xx = 0; xx < pixel_w; xx++) { - for (uint8_t yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) - *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); + if (!(dev->bg_adjacent) && (dev->bg_previous[i] & j)) { + dev->bg_column[i] &= ~j; + dev->curr_y += 1.0 / (double) dev->bg_v_density; + continue; + } + /* draw a dot */ + for (uint8_t xx = 0; xx < dot_size_x; ++xx) { + if ((PIXX + xx) >= (unsigned) dev->page->w) + break; + + for (uint8_t yy = 0; yy < dot_size_y; ++yy) { + if ((PIXY + yy) >= (unsigned) dev->page->h) + break; + + *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); } } } @@ -1921,6 +1930,8 @@ print_bit_graph(escp_t *dev, uint8_t ch) } } + memcpy(dev->bg_previous, dev->bg_column, dev->bg_bytes_per_column * sizeof(uint8_t)); + /* Mark page dirty. */ dev->page->dirty = 1; @@ -2229,14 +2240,13 @@ escp_init(const device_t *info) memset(dev->page->pixels, 0x00, (size_t) dev->page->pitch * dev->page->h); /* Initialize parameters. */ + /* 0 = all white needed for logic 000 */ for (uint8_t i = 0; i < 32; i++) { dev->palcol[i].r = 255; dev->palcol[i].g = 255; dev->palcol[i].b = 255; } - /* 0 = all white needed for logic 000 */ - fill_palette(0, 0, 0, 1, dev); /* 1 = magenta* 001 */ fill_palette(0, 255, 0, 1, dev); /* 2 = cyan* 010 */ @@ -2290,11 +2300,6 @@ escp_close(void *priv) } // clang-format off -#if 0 -static const device_config_t lpt_prt_escp_config[] = { - { .name = "", .description = "", .type = CONFIG_END } -}; -#endif static const device_config_t lpt_prt_escp_config[] = { { .name = "language", From 543a17f0868d1a76e0053586b6261ff0a3062412 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sat, 7 Feb 2026 16:17:17 -0600 Subject: [PATCH 34/49] Headland: Fix shadow RAM enable --- src/chipset/headland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 1c122e126..f52e3fe77 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -273,7 +273,7 @@ memmap_state_update(headland_t *dev) } } - switch (ht_cr0) { + switch (ht_cr0 & 0x18) { case 0x18: if ((mem_size << 10) > 0xe0000) { mem_set_mem_state(0x0e0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); From 284304ad356038df77555ef928211f2891868771 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 8 Feb 2026 00:16:44 +0100 Subject: [PATCH 35/49] Don't write on pixtrans reads (8514/A compatibles) 1. See above. 2. Reuse the 4k ROM with proper loading mechanism so that extended ATI modes can be used with the ATI 8514 Ultra 4k ROM (add-on). 3. Disable excess logging. 4. Apparently 8514/A bresenham line must always draw the last pixel unlike the vector lines, fixes missing pixels in some programs e.g.: calculator on Windows 3.x using 8514/A drivers. --- src/include/86box/vid_svga.h | 5 +- src/video/vid_8514a.c | 151 +++-- src/video/vid_ati_mach8.c | 1053 +++++++++++++++++----------------- src/video/vid_svga.c | 1 + 4 files changed, 598 insertions(+), 612 deletions(-) diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 252463af7..3d6bf3caf 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -352,8 +352,9 @@ extern void ati8514_out(uint16_t addr, uint8_t val, void *priv); extern uint8_t ati8514_in(uint16_t addr, void *priv); extern void ati8514_recalctimings(svga_t *svga); extern uint8_t ati8514_mca_read(int port, void *priv); -extern uint8_t ati8514_rom_readb(uint32_t addr, void *priv); -extern uint16_t ati8514_rom_readw(uint32_t addr, void *priv); +extern uint8_t ati8514_bios_rom_readb(uint32_t addr, void *priv); +extern uint16_t ati8514_bios_rom_readw(uint32_t addr, void *priv); +extern uint32_t ati8514_bios_rom_readl(uint32_t addr, void *priv); extern void ati8514_mca_write(int port, uint8_t val, void *priv); extern void ati8514_pos_write(uint16_t port, uint8_t val, void *priv); extern void ati8514_init(svga_t *svga, void *ext8514, void *dev8514); diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 872743b72..d44d9e9d8 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -45,7 +45,7 @@ # undef CLAMP #endif -#define BIOS_MACH8_ROM_PATH "roms/video/mach8/11301113140_ROM.BIN" +#define BIOS_MACH8_ROM_PATH "roms/video/mach8/11301113140_4k.BIN" static void ibm8514_accel_outb(uint16_t port, uint8_t val, void *priv); static void ibm8514_accel_outw(uint16_t port, uint16_t val, void *priv); @@ -1197,8 +1197,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat old_mix_dat = mix_dat; - if (cmd != 0) - ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw); + ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw); /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on @@ -1215,41 +1214,43 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; + if (ibm8514_cpu_src(svga) || !cpu_input) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; - default: - break; - } + default: + break; + } - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if (dev->accel.ssv_draw) { - if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if (dev->accel.ssv_draw) { + if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } } } } @@ -1837,20 +1838,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { - mix_dat = mix_mask; /* Mix data = forced to foreground register. */ - } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { - /* Mix data = current video memory value. */ - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, mix_dat); - mix_dat = ((mix_dat & rd_mask) == rd_mask); - mix_dat = mix_dat ? mix_mask : 0; - } - - if (ibm8514_cpu_dest(svga)) { - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); - if (pixcntl == 3) - src_dat = ((src_dat & rd_mask) == rd_mask); - } else + if (ibm8514_cpu_src(svga) || !cpu_input) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; @@ -1869,21 +1857,18 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat break; } - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x04) && dev->accel.sy) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); } } @@ -4038,10 +4023,8 @@ ibm8514_vblank_start(void *priv) static void * ibm8514_init(const device_t *info) { - FILE *fp; - uint8_t *rom_load = NULL; - uint32_t bios_addr = 0; uint16_t bios_rom_eeprom = 0x0000; + uint32_t bios_addr; if (svga_get_pri() == NULL) return NULL; @@ -4067,37 +4050,34 @@ ibm8514_init(const device_t *info) dev->bpp = 0; dev->extensions = device_get_config_int("extensions"); - bios_addr = device_get_config_hex20("bios_addr"); + dev->bios_addr = device_get_config_hex20("bios_addr"); if (dev->type & DEVICE_MCA) - bios_addr = 0xc6800; + dev->bios_addr = 0xc6800; switch (dev->extensions) { case ATI: if (rom_present(BIOS_MACH8_ROM_PATH)) { mach_t * mach = (mach_t *) calloc(1, sizeof(mach_t)); svga->ext8514 = mach; - fp = rom_fopen(BIOS_MACH8_ROM_PATH, "rb"); - if (bios_addr & 0x800) - (void) fseek(fp, 0x000, SEEK_SET); - else - (void) fseek(fp, 0x800, SEEK_SET); + bios_addr = dev->bios_addr; - rom_load = malloc(0x2000); - (void) !fread(rom_load, 0x2000, 1, fp); - (void) fclose(fp); - memset(&dev->bios_rom, 0x00, sizeof(rom_t)); + dev->bios_rom.rom = malloc(0x2000); + memset(dev->bios_rom.rom, 0xff, 0x2000); - dev->bios_rom.rom = rom_load; + (void) rom_load_linear(BIOS_MACH8_ROM_PATH, bios_addr, 0x2000, 0x0000, dev->bios_rom.rom + (bios_addr & 0x0800)); + dev->bios_rom.sz = 0x2000; dev->bios_rom.mask = 0x1fff; - mem_mapping_add(&dev->bios_rom.mapping, bios_addr, 0x2000, - ati8514_rom_readb, ati8514_rom_readw, NULL, + + mem_mapping_add(&dev->bios_rom.mapping, bios_addr, dev->bios_rom.sz, + ati8514_bios_rom_readb, ati8514_bios_rom_readw, ati8514_bios_rom_readl, NULL, NULL, NULL, dev->bios_rom.rom, MEM_MAPPING_EXTERNAL | MEM_MAPPING_ROM_WS, dev); + ati8514_init(svga, svga->ext8514, svga->dev8514); if (dev->type & DEVICE_MCA) { - dev->accel.scratch0 = (((bios_addr >> 7) - 0x1000) >> 4); - dev->accel.scratch0 |= ((dev->accel.scratch0 + 0x01) << 8); - bios_rom_eeprom = dev->accel.scratch0; + mach->accel.scratch0 = (((dev->bios_addr >> 7) - 0x1000) >> 4); + mach->accel.scratch0 |= ((mach->accel.scratch0 + 0x01) << 8); + bios_rom_eeprom = mach->accel.scratch0; dev->pos_regs[0] = 0x88; dev->pos_regs[1] = 0x80; mach->eeprom.data[1] = bios_rom_eeprom; @@ -4105,8 +4085,9 @@ ibm8514_init(const device_t *info) ati_eeprom_load_mach8(&mach->eeprom, "ati8514_mca.nvr", 1); mem_mapping_disable(&dev->bios_rom.mapping); } else { - dev->accel.scratch0 = ((bios_addr >> 7) - 0x1000) >> 4; - dev->accel.scratch0 |= ((dev->accel.scratch0 + 0x01) << 8); + mach->accel.scratch0 = ((dev->bios_addr >> 7) - 0x1000) >> 4; + mach->accel.scratch0 |= ((mach->accel.scratch0 + 0x01) << 8); + ibm8514_log("Scratch0 init val=%04x, bios=%06x, base=%06x.\n", mach->accel.scratch0, dev->bios_addr, dev->bios_rom.mapping.base); ati_eeprom_load_mach8(&mach->eeprom, "ati8514.nvr", 0); } break; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index fff9bce3e..ab38e26f6 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -333,7 +333,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } } - mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d, cl = %d, cr = %d, ct = %d, cb = %d, accel_bpp = %d, pitch = %d, hicolbpp = %d, pattlen = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y, clip_l, clip_r, clip_t, clip_b, dev->accel_bpp, dev->pitch, dev->bpp, mach->accel.patt_len); + if (cmd_type == 1 || cmd_type == 3 || cmd_type == 4) { + if (mach->accel.linedraw_opt & 0x04) + mach_log("cmd_type = %i, frgd_sel = %i, bkgd_sel = %i, mono_src = %i, dpconfig = %04x, cur_x = %d, cur_y = %d, cl = %d, cr = %d, ct = %d, cb = %d, accel_bpp = %d, pitch = %d, hicolbpp = %d, pattlen = %d.\n", cmd_type, frgd_sel, bkgd_sel, mono_src, mach->accel.dp_config, dev->accel.cur_x, dev->accel.cur_y, clip_l, clip_r, clip_t, clip_b, dev->accel_bpp, dev->pitch, dev->bpp, mach->accel.patt_len); + } switch (cmd_type) { case 1: /*Extended Raw Linedraw from bres_count register (0x96ee)*/ @@ -437,88 +440,84 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill = !mach->accel.poly_fill; - } - - if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); - - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; break; case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (!compare) { - if (mach_pixel_write(mach)) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; + + default: + break; + } + + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if (mach->accel.linedraw_opt & 0x04) { - if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -647,89 +646,84 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) - src_dat = cpu_dat; - else { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); - if (mono_src == 3) { - src_dat = (src_dat & rd_mask) == rd_mask; - } - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill = !mach->accel.poly_fill; - } - - if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { - READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); - - switch (compare_mode) { + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; case 1: - compare = 1; + src_dat = frgd_color; break; case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + src_dat = cpu_dat; break; case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, src_dat); + if (mono_src == 3) + src_dat = (src_dat & rd_mask) == rd_mask; break; case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; break; default: break; } - if (!compare) { - if (mach_pixel_write(mach)) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill = !mach->accel.poly_fill; + } + + if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { + READ(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; + + default: + break; + } + + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if (mach->accel.linedraw_opt & 0x04) { - if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + if (mach->accel.dp_config & 0x10) { + if (mach->accel.linedraw_opt & 0x04) { + if (((mono_src != 1) && (dev->accel.sx < mach->accel.width)) || ((mono_src == 1) && count)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch) + dev->accel.dx, dest_dat); } } } @@ -906,23 +900,27 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.sx_end > mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_end - mach->accel.sx_start); mach->accel.src_stepx = 1; - mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Positive X: wh(%d,%d), srcwidth = %d, coordinates: %d,%d px, start: %d, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d, srcpitch = %d, dstpitch = %d, dststepx = %d, dststepy = %d, dx = %d, dy = %d.\n", mach->accel.width, mach->accel.height, mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_start, mach->accel.src_x_end, - mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1); + mach->accel.src_stepx, mach->accel.dp_config, mach->accel.src_width & 1, mach->accel.src_pitch, mach->accel.dst_pitch, mach->accel.stepx, mach->accel.stepy, dev->accel.dx, dev->accel.dy); } else if (mach->accel.sx_end < mach->accel.sx_start) { mach->accel.src_width = (mach->accel.sx_start - mach->accel.sx_end); mach->accel.src_stepx = -1; if (dev->accel.cx > 0) dev->accel.cx--; - mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", - mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, - mach->accel.src_width & 1); + + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Negative X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, mach->accel.dp_config, + mach->accel.src_width & 1); } else { mach->accel.src_stepx = 1; mach->accel.src_width = 0; - mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", - mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, - mach->accel.dp_config, mach->accel.src_width & 1); + if (mach->accel.dp_config == 0x6011) + mach_log("BitBLT: Src Indeterminate X: width = %d, coordinates: %d,%d px, end: %d px, stepx = %d, dpconfig = %04x, oddwidth = %d.\n", + mach->accel.src_width, dev->accel.cx, dev->accel.cy, mach->accel.src_x_end, mach->accel.src_stepx, + mach->accel.dp_config, mach->accel.src_width & 1); } mach->accel.sx = 0; if (mach->accel.patt_data_idx < 0x10) @@ -1075,98 +1073,94 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - if (mach->accel.dp_config & 0x02) { - READ(dev->accel.src + dev->accel.cx, poly_src); - poly_src = ((poly_src & rd_mask) == rd_mask); - if (poly_src) - mach->accel.poly_fill ^= 1; - } + if (mach_pixel_write(mach) || !cpu_input) { + if (mach->accel.dp_config & 0x02) { + READ(dev->accel.src + dev->accel.cx, poly_src); + poly_src = ((poly_src & rd_mask) == rd_mask); + if (poly_src) + mach->accel.poly_fill ^= 1; + } - if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach->accel.poly_fill || !(mach->accel.dp_config & 0x02)) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; + + default: + break; + } + + if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { + if (dev->accel.sy & 1) { + READ(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + } else { + READ(dev->accel.dest + dev->accel.dx, dest_dat); } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; - - default: - break; - } - - if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { - if (dev->accel.sy & 1) { - READ(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); } else { READ(dev->accel.dest + dev->accel.dx, dest_dat); } - } else { - READ(dev->accel.dest + dev->accel.dx, dest_dat); - } - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { - if (dev->accel.sy & 1) { - WRITE(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + if (mach->accel.dp_config & 0x10) { + if ((dev->accel_bpp == 24) && (mono_src == 1) && (frgd_sel == 5) && !mach->accel.mono_pattern_enable) { + if (dev->accel.sy & 1) { + WRITE(dev->accel.dest + dev->accel.dx - mach->accel.dst_pitch, dest_dat); + } else { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } } else { WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } - } else { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } } @@ -1186,15 +1180,29 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if ((mono_src == 3) || (frgd_sel == 3) || (bkgd_sel == 3) || (mach->accel.dp_config & 0x02)) { dev->accel.cx += mach->accel.src_stepx; mach->accel.sx++; - if (mach->accel.sx >= mach->accel.src_width) { - mach->accel.sx = 0; - if (mach->accel.src_stepx == -1) - dev->accel.cx += mach->accel.src_width; - else - dev->accel.cx -= mach->accel.src_width; + if (mach->accel.dp_config == 0x6011) { + mach_log("DX=%d, DY=%d, SX=%d, SY=%d, SRCSX=%d, SRCWIDTH=%d, CX=%d, CY=%d, srcydir=%d, srcoffset=%08x.\n", dev->accel.dx, dev->accel.dy, dev->accel.sx, dev->accel.sy, mach->accel.sx - 1, mach->accel.src_width, dev->accel.cx - mach->accel.src_stepx, dev->accel.cy, mach->accel.src_y_dir, mach->accel.src_ge_offset); + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) + dev->accel.cx += mach->accel.src_width; + else + dev->accel.cx -= mach->accel.src_width; - dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); - dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + dev->accel.cy += mach->accel.stepy; + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + } + } else { + if (mach->accel.sx >= mach->accel.src_width) { + mach->accel.sx = 0; + if (mach->accel.src_stepx == -1) + dev->accel.cx += mach->accel.src_width; + else + dev->accel.cx -= mach->accel.src_width; + + dev->accel.cy += mach->accel.src_y_dir; + dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); + } } } @@ -1211,7 +1219,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.dx += mach->accel.stepx; dev->accel.sx++; if ((dev->accel.sx >= mach->accel.width) || (dev->accel.dx >= 0x600)) { - dev->accel.sx = 0; + dev->accel.sx = 0; if (mach->accel.stepx == -1) dev->accel.dx += mach->accel.width; else @@ -1318,71 +1326,68 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else + break; + case 3: src_dat = 0; - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1448,86 +1453,82 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - if (mach->accel.linedraw_opt & 0x02) { - READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); - if (poly_src) - mach->accel.poly_fill ^= 1; - } + if (mach_pixel_write(mach) || !cpu_input) { + if (mach->accel.linedraw_opt & 0x02) { + READ(mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch) + dev->accel.cx, poly_src); + if (poly_src) + mach->accel.poly_fill ^= 1; + } - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; if (mach->accel.poly_fill || !(mach->accel.linedraw_opt & 0x02)) { MIX(mix, dest_dat, src_dat); } dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (mach->accel.linedraw_opt & 0x04) { - if (dev->accel.sx < mach->accel.width) { + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -1583,73 +1584,69 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } } } else mach->accel.clip_overrun = ((mach->accel.clip_overrun + 1) & 0x0f); @@ -1715,78 +1712,74 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; mach->accel.clip_overrun = 0; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: src_dat = 0; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + READ(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { - if (mach->accel.linedraw_opt & 0x04) { - if (dev->accel.sx < mach->accel.width) { + if ((mach->accel.dp_config & 0x10) && (cmd_type == 3)) { + if (mach->accel.linedraw_opt & 0x04) { + if (dev->accel.sx < mach->accel.width) { + WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); + } + } else { WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } - } else { - WRITE(mach->accel.dst_ge_offset + (dev->accel.cy * mach->accel.dst_pitch) + dev->accel.cx, dest_dat); } } } else @@ -2016,7 +2009,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 cx--; } - cy += (mach->accel.src_y_dir ? 1 : -1); + cy += mach->accel.src_y_dir; dev->accel.src = mach->accel.src_ge_offset + (cy * mach->accel.src_pitch); } @@ -2099,75 +2092,71 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 (dev->accel.dy >= clip_t) && (dev->accel.dy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch (mix ? frgd_sel : bkgd_sel) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - if (mach_pixel_read(mach)) + if (mach_pixel_write(mach) || !cpu_input) { + switch (mix ? frgd_sel : bkgd_sel) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: src_dat = cpu_dat; - else { + break; + case 3: READ(dev->accel.src + dev->accel.cx, src_dat); if (mono_src == 3) src_dat = (src_dat & rd_mask) == rd_mask; - } - break; - case 5: - if (dev->bpp) - src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; - else - src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; - break; + break; + case 5: + if (dev->bpp) + src_dat = mach->accel.color_pattern_hicol[mach->accel.color_pattern_idx]; + else + src_dat = mach->accel.color_pattern[mach->accel.color_pattern_idx]; + break; - default: - break; - } + default: + break; + } - READ(dev->accel.dest + dev->accel.dx, dest_dat); + READ(dev->accel.dest + dev->accel.dx, dest_dat); - switch (compare_mode) { - case 1: - compare = 1; - break; - case 2: - compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; - break; - case 3: - compare = (dest_dat < dest_cmp_clr) ? 0 : 1; - break; - case 4: - compare = (dest_dat != dest_cmp_clr) ? 0 : 1; - break; - case 5: - compare = (dest_dat == dest_cmp_clr) ? 0 : 1; - break; - case 6: - compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; - break; - case 7: - compare = (dest_dat > dest_cmp_clr) ? 0 : 1; - break; + switch (compare_mode) { + case 1: + compare = 1; + break; + case 2: + compare = (dest_dat >= dest_cmp_clr) ? 0 : 1; + break; + case 3: + compare = (dest_dat < dest_cmp_clr) ? 0 : 1; + break; + case 4: + compare = (dest_dat != dest_cmp_clr) ? 0 : 1; + break; + case 5: + compare = (dest_dat == dest_cmp_clr) ? 0 : 1; + break; + case 6: + compare = (dest_dat <= dest_cmp_clr) ? 0 : 1; + break; + case 7: + compare = (dest_dat > dest_cmp_clr) ? 0 : 1; + break; - default: - break; - } + default: + break; + } - if (!compare) { - if (mach_pixel_write(mach)) { + if (!compare) { old_dest_dat = dest_dat; MIX(mix, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); } - } - if (mach->accel.dp_config & 0x10) { - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + if (mach->accel.dp_config & 0x10) { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } } } @@ -2185,7 +2174,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 else dev->accel.cx -= mach->accel.src_width; - dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); + dev->accel.cy += mach->accel.src_y_dir; dev->accel.src = mach->accel.src_ge_offset + (dev->accel.cy * mach->accel.src_pitch); } @@ -3942,7 +3931,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u } else dev->_8514crt = 1; - if (dev->mode != VGA_MODE) + if ((dev->mode != VGA_MODE) && ATI_MACH32) mach_set_resolution(mach, svga); else svga_recalctimings(svga); @@ -4067,9 +4056,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x52ef: mach_log("ATI 8514/A: (0x%04x) ScratchPad0 val=%04x.\n", port, val); if (len == 2) - dev->accel.scratch0 = val; + mach->accel.scratch0 = val; else { - WRITE8(port, dev->accel.scratch0, val); + WRITE8(port, mach->accel.scratch0, val); } break; @@ -4077,9 +4066,9 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x56ef: mach_log("ATI 8514/A: (0x%04x) ScratchPad1 val=%04x.\n", port, val); if (len == 2) - dev->accel.scratch1 = val; + mach->accel.scratch1 = val; else { - WRITE8(port, dev->accel.scratch1, val); + WRITE8(port, mach->accel.scratch1, val); } break; @@ -4360,7 +4349,8 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0xc2ee: - mach->accel.src_y_dir = val & 1; + mach->accel.src_y_dir = (val & 1) ? 1 : -1; + mach_log("Source Y Direction=%x.\n", val); break; case 0xc6ee: @@ -5170,16 +5160,16 @@ mach_accel_in_call(uint16_t port, mach_t *mach, svga_t *svga, ibm8514_t *dev) case 0x52ee: case 0x52ef: - READ8(port, dev->accel.scratch0); - mach_log("ScratchPad0=%x.\n", dev->accel.scratch0); - if (dev->accel.scratch0 == 0x1234) + READ8(port, mach->accel.scratch0); + mach_log("ScratchPad0=%x.\n", mach->accel.scratch0); + if (mach->accel.scratch0 == 0x1234) temp = 0x0000; break; case 0x56ee: case 0x56ef: - READ8(port, dev->accel.scratch1); - mach_log("ScratchPad1=%x.\n", dev->accel.scratch1); + READ8(port, mach->accel.scratch1); + mach_log("ScratchPad1=%x.\n", mach->accel.scratch1); break; case 0x5eee: @@ -7326,34 +7316,47 @@ mach_reset(void *priv) } uint8_t -ati8514_rom_readb(uint32_t addr, void *priv) +ati8514_bios_rom_readb(uint32_t addr, void *priv) { const ibm8514_t *dev = (ibm8514_t *) priv; const rom_t *rom = &dev->bios_rom; - uint8_t ret; + uint8_t ret = 0xff; - mach_log("ROM1RB=%05x, ", addr); + mach_log("%04X:%08X: ROM1RB=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; - addr &= 0x1fff; ret = rom->rom[addr]; - - mach_log("ReadBAddr1=%03x, ret=%02x.\n", addr, ret); + mach_log("BIOS: ReadBAddr1=%04x, ret=%02x.\n", addr, ret); return (ret); } uint16_t -ati8514_rom_readw(uint32_t addr, void *priv) +ati8514_bios_rom_readw(uint32_t addr, void *priv) { const ibm8514_t *dev = (ibm8514_t *) priv; const rom_t *rom = &dev->bios_rom; - uint16_t ret; + uint16_t ret = 0xffff; - mach_log("ROM1RW=%05x, ", addr); + mach_log("%04X:%08X: ROM1RW=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; - addr &= 0x1fff; ret = (*(uint16_t *) &(rom->rom[addr])); + mach_log("BIOS: ReadWAddr1=%04x, ret=%04x.\n", addr, ret); + return (ret); +} - mach_log("ReadWAddr1=%03x, ret=%04x.\n", addr, ret); +uint32_t +ati8514_bios_rom_readl(uint32_t addr, void *priv) +{ + const ibm8514_t *dev = (ibm8514_t *) priv; + const rom_t *rom = &dev->bios_rom; + uint32_t ret = 0xffffffff; + + mach_log("%04X:%08X: ROM1RL=%05x, ", CS, cpu_state.pc, addr); + addr &= rom->mask; + + ret = (*(uint32_t *) &(rom->rom[addr])); + mach_log("BIOS: ReadLAddr1=%04x, ret=%08x.\n", addr, ret); return (ret); } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 2409d1202..0a2866413 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -814,6 +814,7 @@ svga_recalctimings(svga_t *svga) svga->render = svga_render_2bpp_highres; } else { svga->map8 = svga->pallook; + svga_log("Map8.\n"); if (svga->lowres) { /*Low res (320)*/ svga->render = svga_render_8bpp_lowres; svga_log("8 bpp low res.\n"); From 0805907f9130a9eb05b9c4a302756b8fad9258bb Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sat, 7 Feb 2026 21:54:33 -0600 Subject: [PATCH 36/49] PSSJ: Bit 4 of port C7/1E7 is reserved and not used for amplitude --- src/sound/snd_pssj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 7de8ec824..da141dafd 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -78,7 +78,7 @@ pssj_write(uint16_t port, uint8_t val, void *priv) break; case 3: pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); - pssj->amplitude = val >> 4; + pssj->amplitude = (val & 0xef) >> 4; break; default: From 3ffe89c966962d051654c39a3b445535be949f2c Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sat, 7 Feb 2026 21:58:59 -0600 Subject: [PATCH 37/49] PSSJ: Actually clear the DAC IRQ when port C4/1E4 has bit 3 cleared, fixes Tandy DAC Win3.1 driver --- src/sound/snd_pssj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index da141dafd..1b10fdd8d 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -55,8 +55,10 @@ pssj_write(uint16_t port, uint8_t val, void *priv) if (!pssj->enable) timer_disable(&pssj->timer_count); sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); - if (!(val & 8)) + if (!(val & 8)) { pssj->irq = 0; + picintc(1 << 7); + } pssj_update_irq(pssj); break; case 1: From 9aa6008e545164f750bceeab7137722ad9feadc5 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sun, 8 Feb 2026 09:57:49 +0100 Subject: [PATCH 38/49] ESC/P 2: Implement DC1 and DC3 --- src/printer/prt_escp.c | 63 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e9f6ca71e..14f76d880 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -106,19 +106,19 @@ enum { }; /* Font styles. */ -#define STYLE_PROP 0x0001 -#define STYLE_CONDENSED 0x0002 -#define STYLE_BOLD 0x0004 -#define STYLE_DOUBLESTRIKE 0x0008 -#define STYLE_DOUBLEWIDTH 0x0010 -#define STYLE_ITALICS 0x0020 -#define STYLE_UNDERLINE 0x0040 -#define STYLE_SUPERSCRIPT 0x0080 -#define STYLE_SUBSCRIPT 0x0100 -#define STYLE_STRIKETHROUGH 0x0200 -#define STYLE_OVERSCORE 0x0400 -#define STYLE_DOUBLEWIDTHONELINE 0x0800 -#define STYLE_DOUBLEHEIGHT 0x1000 +#define STYLE_PROP 0x0002 +#define STYLE_CONDENSED 0x0004 +#define STYLE_BOLD 0x0008 +#define STYLE_DOUBLESTRIKE 0x0010 +#define STYLE_DOUBLEWIDTH 0x0020 +#define STYLE_ITALICS 0x0040 +#define STYLE_UNDERLINE 0x0080 +#define STYLE_SUPERSCRIPT 0x0100 +#define STYLE_SUBSCRIPT 0x0200 +#define STYLE_STRIKETHROUGH 0x0400 +#define STYLE_OVERSCORE 0x0800 +#define STYLE_DOUBLEWIDTHONELINE 0x1000 +#define STYLE_DOUBLEHEIGHT 0x2000 /* Underlining styles. */ #define SCORE_NONE 0x00 @@ -179,6 +179,8 @@ typedef struct escp_t { char page_fn[260]; uint8_t color; + uint8_t selected; + /* page data (TODO: make configurable) */ double page_width; /* all in inches */ double page_height; @@ -560,6 +562,7 @@ reset_printer(escp_t *dev) dev->bottom_margin = dev->page_height - 1.0 / 36.0; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; + dev->selected = 1; dev->curr_x = dev->curr_y = 0.0; dev->esc_seen = 0; dev->fss_seen = 0; @@ -1169,24 +1172,11 @@ process_char(escp_t *dev, uint8_t ch) case '!': /* master select */ dev->cpi = (dev->esc_parms[0]) & 0x01 ? 12.0 : 10.0; - /* Reset first seven bits. */ - dev->font_style &= 0xFF80; - if (dev->esc_parms[0] & 0x02) - dev->font_style |= STYLE_PROP; - if (dev->esc_parms[0] & 0x04) - dev->font_style |= STYLE_CONDENSED; - if (dev->esc_parms[0] & 0x08) - dev->font_style |= STYLE_BOLD; - if (dev->esc_parms[0] & 0x10) - dev->font_style |= STYLE_DOUBLESTRIKE; - if (dev->esc_parms[0] & 0x20) - dev->font_style |= STYLE_DOUBLEWIDTH; - if (dev->esc_parms[0] & 0x40) - dev->font_style |= STYLE_ITALICS; - if (dev->esc_parms[0] & 0x80) { + /* Reset first seven style bits (starting from two as CPI had one). */ + dev->font_style &= 0xFF01; + dev->font_style |= dev->esc_parms[0]; + if (dev->esc_parms[0] & 0x80) dev->font_score = SCORE_SINGLE; - dev->font_style |= STYLE_UNDERLINE; - } dev->hmi = -1; dev->multipoint_mode = 0; @@ -1409,7 +1399,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'T': /* cancel superscript/subscript printing */ - dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); update_font(dev); break; @@ -1737,7 +1727,7 @@ process_char(escp_t *dev, uint8_t ch) } if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { - dev->font_style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; update_font(dev); } return 1; @@ -1784,8 +1774,8 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x11: /* select printer (DC1) */ - /* Ignore. */ - return 0; + dev->selected = 1; + return 1; case 0x12: /* cancel condensed printing (DC2) */ dev->hmi = -1; @@ -1794,7 +1784,7 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x13: /* deselect printer (DC3) */ - /* Ignore. */ + dev->selected = 0; return 1; case 0x14: /* cancel double-width printing (one line) (DC4) */ @@ -1957,6 +1947,9 @@ handle_char(escp_t *dev, uint8_t ch) if (dev->page == NULL) return; + if (!(dev->selected) && ch != 0x11) + return; + /* MSB mode */ if (dev->msb != 255) { if (dev->msb == 0) From 0f7b52ab45c801730c87b11c3f11b95fa644521d Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sun, 8 Feb 2026 13:10:07 +0100 Subject: [PATCH 39/49] ESC/P 2: license, printing quality switch, stdbool.h, some clean-up --- src/printer/prt_cpmap.c | 316 ++++------------------------------------ src/printer/prt_escp.c | 193 +++++++++++------------- 2 files changed, 117 insertions(+), 392 deletions(-) diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c index 370e258ce..37243f0db 100644 --- a/src/printer/prt_cpmap.c +++ b/src/printer/prt_cpmap.c @@ -1,75 +1,24 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * Various ASCII to Unicode maps, for the various codepages. + * This file is part of the 86Box distribution. * - * Authors: Michael Drüing, - * Fred N. van Kempen, + * Code page to Unicode mapping + * for a generic ESC/P 2 dot-matrix printer. * - * Based on code by Frederic Weymann (originally for DosBox.) + * Authors: Lili Kurek, * - * Copyright 2018 Michael Drüing. - * Copyright 2018 Fred N. van Kempen. + * Based on code by Frederic Weymann (originally for DOSBox.) * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright 2025-2026 Lili Kurek. */ #include #include -#include -#include -#include -#include <86box/86box.h> -#include <86box/plat.h> -#include <86box/printer.h> -static const uint16_t cp437Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp437Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -88,23 +37,7 @@ static const uint16_t cp437Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp737Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp737Map[128] = { 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, @@ -123,23 +56,7 @@ static const uint16_t cp737Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp775Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp775Map[128] = { 0x0106, 0x00fc, 0x00e9, 0x0101, 0x00e4, 0x0123, 0x00e5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012b, 0x0179, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x014d, 0x00f6, 0x0122, 0x00a2, 0x015a, @@ -158,23 +75,7 @@ static const uint16_t cp775Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp850Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp850Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -193,23 +94,7 @@ static const uint16_t cp850Map[256] = { 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp852Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp852Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7, 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106, 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a, @@ -228,23 +113,7 @@ static const uint16_t cp852Map[256] = { 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0 }; -static const uint16_t cp855Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp855Map[128] = { 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c, @@ -263,23 +132,7 @@ static const uint16_t cp855Map[256] = { 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x00a0 }; -static const uint16_t cp857Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp857Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -298,23 +151,7 @@ static const uint16_t cp857Map[256] = { 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp860Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp860Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e3, 0x00e0, 0x00c1, 0x00e7, 0x00ea, 0x00ca, 0x00e8, 0x00cd, 0x00d4, 0x00ec, 0x00c3, 0x00c2, 0x00c9, 0x00c0, 0x00c8, 0x00f4, 0x00f5, 0x00f2, 0x00da, 0x00f9, @@ -333,23 +170,7 @@ static const uint16_t cp860Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp861Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp861Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00d0, 0x00f0, 0x00de, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00fe, 0x00fb, 0x00dd, @@ -368,23 +189,7 @@ static const uint16_t cp861Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp862Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp862Map[128] = { 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, @@ -403,23 +208,7 @@ static const uint16_t cp862Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp863Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp863Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00c2, 0x00e0, 0x00b6, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x2017, 0x00c0, 0x00a7, 0x00c9, 0x00c8, 0x00ca, 0x00f4, 0x00cb, 0x00cf, 0x00fb, 0x00f9, @@ -438,23 +227,7 @@ static const uint16_t cp863Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp864Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066a, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp864Map[128] = { 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c, 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518, 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab, @@ -473,23 +246,7 @@ static const uint16_t cp864Map[256] = { 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, 0x00a0 }; -static const uint16_t cp865Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp865Map[128] = { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, @@ -508,23 +265,7 @@ static const uint16_t cp865Map[256] = { 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 }; -static const uint16_t cp866Map[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, +static const uint16_t cp866Map[128] = { 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, @@ -570,7 +311,7 @@ static const struct { void select_codepage(uint16_t code, uint16_t *curmap) { - uint16_t i = 0; + uint8_t i = 0; const uint16_t *map_to_use; map_to_use = maps[0].map; @@ -583,6 +324,9 @@ select_codepage(uint16_t code, uint16_t *curmap) i++; } - for (uint16_t j = 0; j < 256; j++) - curmap[j] = map_to_use[j]; + for (i = 0; i < 128; ++i) + curmap[i] = i; + + for (; i != 0; ++i) + curmap[i] = map_to_use[i - 128]; } diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 14f76d880..5a507ad30 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1,63 +1,30 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * Implementation of the Generic ESC/P 2 Dot-Matrix printer. + * This file is part of the 86Box distribution. * - * Authors: Michael Drüing, - * Fred N. van Kempen, + * Implementation of a generic ESC/P 2 dot-matrix printer. * - * Based on code by Frederic Weymann (originally for DosBox.) + * Authors: Lili Kurek, * - * Copyright 2018-2019 Michael Drüing. - * Copyright 2019 Fred N. van Kempen. + * Based on code by Frederic Weymann (originally for DOSBox.) * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Copyright 2025-2026 Lili Kurek. */ + #include +#include #include #include -#include -#include -#include #include #include #include FT_FREETYPE_H #define HAVE_STDARG_H #include <86box/86box.h> -#include <86box/device.h> #include "cpu.h" -#include <86box/machine.h> #include <86box/timer.h> #include <86box/mem.h> #include <86box/rom.h> @@ -79,6 +46,11 @@ enum { LANG_ESCP2 }; +enum { + QUALITY_DRAFT = 0, + QUALITY_LQ +}; + enum { PAPER_LETTER = 0, PAPER_A4, @@ -88,7 +60,7 @@ enum { /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_CPI 10.0 /* standard310 cpi */ +#define PAGE_CPI 10.0 /* standard 10 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ /* FreeType library handles - global so they can be shared. */ @@ -127,10 +99,6 @@ enum { #define SCORE_SINGLEBROKEN 0x05 #define SCORE_DOUBLEBROKEN 0x06 -/* Print quality. */ -#define QUALITY_DRAFT 0x01 -#define QUALITY_LQ 0x02 - /* Typefaces. */ enum { TYPEFACE_ROMAN = 0, @@ -179,7 +147,7 @@ typedef struct escp_t { char page_fn[260]; uint8_t color; - uint8_t selected; + bool dc1_selected; /* page data (TODO: make configurable) */ double page_width; /* all in inches */ @@ -215,16 +183,16 @@ typedef struct escp_t { /* handshake data */ uint8_t data; - uint8_t ack; - uint8_t select; - uint8_t busy; - uint8_t int_pending; - uint8_t error; - uint8_t autofeed; + bool ack; + bool select; + bool busy; + bool int_pending; + bool error; + bool autofeed; /* ESC command data */ - int8_t esc_seen; /* set to 1 if an ESC char was seen */ - int8_t fss_seen; + bool esc_seen; /* set if an ESC char was seen */ + bool fss_seen; uint16_t esc_pending; /* in which ESC command are we */ uint8_t esc_parms_req; uint8_t esc_parms_curr; @@ -269,7 +237,7 @@ typedef struct escp_t { PALETTE palcol; - uint8_t auto_lf; + bool auto_lf; } escp_t; /* Codepage table, needed for ESC t ( */ @@ -330,18 +298,13 @@ static const uint16_t intCharSets[15][12] = { }; #ifdef ENABLE_ESCP_LOG -int escp_do_log = ENABLE_ESCP_LOG; - static void escp_log(const char *fmt, ...) { va_list ap; - - if (escp_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } #else # define escp_log(fmt, ...) @@ -384,7 +347,7 @@ pulse_timer(void *priv) escp_t *dev = (escp_t *) priv; if (dev->ack) { - dev->ack = 0; + dev->ack = false; lpt_irq(dev->lpt, 1); } @@ -428,7 +391,7 @@ update_font(escp_t *dev) double vpoints = 10.5; /* We need the FreeType library. */ - if (ft_lib == NULL) + if (!ft_lib) return; /* Release current font if we have one. */ @@ -562,10 +525,10 @@ reset_printer(escp_t *dev) dev->bottom_margin = dev->page_height - 1.0 / 36.0; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; - dev->selected = 1; + dev->dc1_selected = true; dev->curr_x = dev->curr_y = 0.0; - dev->esc_seen = 0; - dev->fss_seen = 0; + dev->esc_seen = false; + dev->fss_seen = false; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; dev->lpi = PAGE_LPI; @@ -573,7 +536,7 @@ reset_printer(escp_t *dev) dev->cpi = PAGE_CPI; dev->curr_char_table = 1; dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; + dev->print_quality = device_get_config_int("quality"); dev->extra_intra_space = 0.0; dev->print_upper_control = 1; dev->bg_remaining_bytes = 0; @@ -603,7 +566,7 @@ reset_printer(escp_t *dev) dev->num_horizontal_tabs = 32; dev->num_vertical_tabs = -1; - if (dev->page != NULL) + if (dev->page) dev->page->dirty = 0; escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", @@ -614,7 +577,7 @@ reset_printer(escp_t *dev) static void reset_printer_hard(escp_t *dev) { - dev->ack = 0; + dev->ack = false; timer_disable(&dev->pulse_timer); timer_stop(&dev->timeout_timer); reset_printer(dev); @@ -806,7 +769,7 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_pending = ch; if (dev->fss_seen) dev->esc_pending |= 0x800; - dev->esc_seen = dev->fss_seen = 0; + dev->esc_seen = dev->fss_seen = false; dev->esc_parms_curr = 0; escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); @@ -1258,6 +1221,10 @@ process_char(escp_t *dev, uint8_t ch) dev->print_upper_control = 0; break; + case '8': // disable + case '9': // enable paper-out sensor + // We don't have real paper, ignore. + case '<': /* unidirectional mode (one line) */ /* We don't have a print head, so just * ignore this. */ @@ -1774,7 +1741,7 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x11: /* select printer (DC1) */ - dev->selected = 1; + dev->dc1_selected = true; return 1; case 0x12: /* cancel condensed printing (DC2) */ @@ -1784,7 +1751,7 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x13: /* deselect printer (DC3) */ - dev->selected = 0; + dev->dc1_selected = false; return 1; case 0x14: /* cancel double-width printing (one line) (DC4) */ @@ -1797,13 +1764,13 @@ process_char(escp_t *dev, uint8_t ch) return 1; case 0x1b: /* ESC */ - dev->esc_seen = 1; + dev->esc_seen = true; return 1; case 0x1c: /* FS (IBM Proprinter II) TODO: Make an IBM printer. */ if (dev->lang == LANG_ESCP2) { - dev->fss_seen = 1; + dev->fss_seen = true; return 1; } @@ -1822,7 +1789,7 @@ blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) uint8_t *dst; /* check if freetype is available */ - if (ft_lib == NULL) + if (!ft_lib) return; for (unsigned int y = 0; y < bitmap->rows; y++) { @@ -1944,19 +1911,18 @@ handle_char(escp_t *dev, uint8_t ch) uint16_t line_y; double x_advance; - if (dev->page == NULL) - return; - - if (!(dev->selected) && ch != 0x11) + if (!(dev->page)) return; /* MSB mode */ - if (dev->msb != 255) { - if (dev->msb == 0) - ch &= 0x7f; - else if (dev->msb == 1) - ch |= 0x80; - } + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; + // else it's neutral at 255 + + if (!(dev->dc1_selected) && ch != 0x11) + return; if (dev->bg_remaining_bytes > 0) { print_bit_graph(dev, ch); @@ -1974,7 +1940,7 @@ handle_char(escp_t *dev, uint8_t ch) } /* We cannot print if we have no font loaded. */ - if (dev->fontface == NULL) + if (!(dev->fontface)) return; if (ch == 0x01) @@ -2059,7 +2025,7 @@ write_data(uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; dev->data = val; @@ -2070,7 +2036,7 @@ strobe(uint8_t old, uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; /* Data is strobed to the parallel printer on the falling edge of the @@ -2087,7 +2053,7 @@ strobe(uint8_t old, uint8_t val, void *priv) #endif } /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; + dev->ack = true; timer_set_delay_u64(&dev->pulse_timer, ISACONST); timer_on_auto(&dev->timeout_timer, 5000000.0); @@ -2099,17 +2065,17 @@ write_ctrl(uint8_t val, void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; if (val & 0x08) { /* SELECT */ /* select printer */ - dev->select = 1; + dev->select = true; } if ((val & 0x04) && !(dev->ctrl & 0x04)) { /* reset printer */ - dev->select = 0; + dev->select = false; reset_printer_hard(dev); } @@ -2128,7 +2094,7 @@ write_ctrl(uint8_t val, void *priv) #endif } /* ACK it, will be read on next READ STATUS. */ - dev->ack = 1; + dev->ack = true; timer_set_delay_u64(&dev->pulse_timer, ISACONST); timer_on_auto(&dev->timeout_timer, 5000000.0); @@ -2167,11 +2133,11 @@ escp_init(const device_t *info) escp_t *dev = NULL; /* Initialize FreeType. */ - if (ft_lib == NULL) { + if (!ft_lib) { if (FT_Init_FreeType(&ft_lib)) { pclog("ESC/P: FT_Init_FreeType failed\n"); ft_lib = NULL; - return (NULL); + return(NULL); } } @@ -2190,7 +2156,7 @@ escp_init(const device_t *info) ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_ESCP_ERROR_TITLE), plat_get_string(STRING_ESCP_ERROR_DESC)); free(dev); - return (NULL); + return(NULL); } /* Create the full path for the page images. */ @@ -2257,7 +2223,7 @@ escp_init(const device_t *info) dev->color = COLOR_BLACK; dev->fontface = 0; - dev->autofeed = 0; + dev->autofeed = false; reset_printer(dev); @@ -2275,15 +2241,15 @@ escp_close(void *priv) { escp_t *dev = (escp_t *) priv; - if (dev == NULL) + if (!dev) return; - if (dev->page != NULL) { + if (dev->page) { /* Print last page if it contains data. */ if (dev->page->dirty) dump_page(dev); - if (dev->page->pixels != NULL) + if (dev->page->pixels) free(dev->page->pixels); free(dev->page); } @@ -2330,6 +2296,21 @@ static const device_config_t lpt_prt_escp_config[] = { }, .bios = { { 0 } } }, + { + .name = "quality", + .description = "Quality", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Draft", .value = QUALITY_DRAFT }, + { .description = "(Near) Letter", .value = QUALITY_LQ }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "auto_lf", .description = "Auto LF", From ba1c24de183761bfac631fe18d0662f423452ca5 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 9 Feb 2026 01:43:44 +0900 Subject: [PATCH 40/49] Added IBM 5551-Bxx emulation --- src/cpu/808x.c | 102 +- src/device/keyboard_at.c | 4 +- src/device/postcard.c | 2 + src/dma.c | 13 +- src/floppy/fdc.c | 122 +- src/floppy/fdd.c | 4 + src/include/86box/fdc.h | 3 + src/include/86box/keyboard.h | 1 + src/include/86box/machine.h | 4 + src/include/86box/pit.h | 2 + src/machine/CMakeLists.txt | 1 + src/machine/m_xt_ibm5550.c | 2149 ++++++++++++++++++++++++++++++++++ src/machine/machine_table.c | 43 + src/pit.c | 15 + 14 files changed, 2457 insertions(+), 8 deletions(-) create mode 100644 src/machine/m_xt_ibm5550.c diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 4e2e830d0..cf091874e 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -43,7 +43,7 @@ /* Is the CPU 8088 or 8086. */ int is8086 = 0; - +int calllevel = 0; uint8_t use_custom_nmi_vector = 0; uint32_t custom_nmi_vector = 0x00000000; @@ -1959,6 +1959,106 @@ execx86(int cycs) } completed = 1; + // switch (opcode) { + // case 0x9A: + // case 0xE8: + // pclog("[%04X:%04X] %d CALL\n", CS, cpu_state.pc, calllevel); + // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", + // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); + // calllevel += 1; + // if (CS == 0xfcbf && cpu_state.pc == 0x83) { + // pclog("[bp+n]:"); + // for (int i = 0; i < 0x58; i++) + // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); + // pclog("\n"); + // } + // break; + // case 0xC3: + // case 0xCB: + // case 0xC2: + // case 0xCA: + // pclog("[%04X:%04X] %d RET\n", CS, cpu_state.pc, calllevel); + // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X FL=%04X\n", + // cs >> 4, cpu_state.pc, AX, BX, CX, DX, ES, DI, DS, SI, cpu_state.flags); + // calllevel -= 1; + // break; + // case 0xFB: + // pclog("[%04X:%04X] STI\n", CS, cpu_state.pc); + // break; + // case 0xFA: + // pclog("[%04X:%04X] CLI\n", CS, cpu_state.pc); + // break; + // } + // if ((CS == 0xFD6E) || (CS == 0xFcbf)) { + // if (DI == 0x48aa) + // pclog("[%04X:%04X] AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", + // CS, cpu_state.pc,AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); + // if ((CS == 0xFD6E) || (CS == 0xFcbf)) { + // switch (opcode) { + // case 0x3C: + // case 0x80: + // case 0x83: + // pclog("[%04X:%04X] CMP AX=%04X\n", CS, cpu_state.pc, AX); + // // if(CS == 0xFD6E && cpu_state.pc < 0x20) { + // // pclog("[bx+n]:"); + // // for(int i=0;i<0x12;i++) + // // pclog(" [%02X]%02X", i, read_mem_b((DS << 4) + BX + i)); + // // pclog("\n"); + // // } + // break; + // case 0xE2: + // pclog("[%04X:%04X] LOOP CX=%02X**\n", CS, cpu_state.pc, CX>>8); + // break; + // case 0xF6: + // pclog("[%04X:%04X] TEST AX=%04X\n", CS, cpu_state.pc, AX); + // break; + // case 0xEB: + // case 0xE9: + // case 0xEA: + // pclog("[%04X:%04X] JMP\n", CS, cpu_state.pc); + // break; + // case 0x77: + // pclog("[%04X:%04X] JA\n", CS, cpu_state.pc); + // break; + // case 0x73: + // pclog("[%04X:%04X] JAE\n", CS, cpu_state.pc); + // break; + // case 0x72: + // pclog("[%04X:%04X] JB\n", CS, cpu_state.pc); + // if (CS == 0xFD6E && cpu_state.pc < 0x28) { + // pclog("[bx+n]:"); + // for (int i = 0; i < 0x20; i++) + // pclog(" [%02X]%02X", i, read_mem_b((DS << 4) + BX + i)); + // pclog("\n"); + // } + // break; + // case 0x76: + // pclog("[%04X:%04X] JNA\n", CS, cpu_state.pc); + // break; + // case 0x74: + // pclog("[%04X:%04X] JE\n", CS, cpu_state.pc); + // if (CS == 0xfcbf && cpu_state.pc == 0x8A) { + // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", + // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); + // pclog("[bp+n]:"); + // for (int i = 0; i < 0x58; i++) + // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); + // pclog("\n"); + // } + // break; + // case 0x75: + // pclog("[%04X:%04X] JNE\n", CS, cpu_state.pc); + // if (CS == 0xFD6E && cpu_state.pc == 0x16E) { + // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", + // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); + // pclog("[bp+n]:"); + // for (int i = 0; i < 0x58; i++) + // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); + // pclog("\n"); + // } + // break; + // } + // } // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); if (is186) { switch (opcode) { diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index fd8d11503..2dbc2322f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -4758,7 +4758,7 @@ static const scancode scancode_set82[512] = { // clang-format on }; /* Scancode set 8Ah : IBM 5556 keyboard compatible scancode set used by J-DOS */ -static scancode scancode_set8a[512] = +const scancode scancode_set8a[512] = { // clang-format off {.mk = { 0 }, .brk = { 0 } }, /* 000 */ @@ -4817,7 +4817,7 @@ static scancode scancode_set8a[512] = {.mk = { 0x0a, 0 }, .brk = { 0 } }, /* 035 */ {.mk = { 0x39, 0 }, .brk = { 0xb9, 0 } }, /* 036 RSHIFT */ {.mk = { 0x64, 0 }, .brk = { 0 } }, /* 037 * (asterisk) */ - {.mk = { 0x3A, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */ + {.mk = { 0x3a, 0 }, .brk = { 0xba, 0 } }, /* 038 0x3A LALT = Kanji */ {.mk = { 0x34, 0 }, .brk = { 0 } }, /* 039 */ {.mk = { 0x32, 0 }, .brk = { 0xb2, 0 } }, /* 03a CAPSLOCK */ {.mk = { 0x68, 0 }, .brk = { 0 } }, /* 03b F1 */ diff --git a/src/device/postcard.c b/src/device/postcard.c index f33574452..f842cbb33 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -195,6 +195,8 @@ postcard_init(UNUSED(const device_t *info)) postcard_port = 0x190; /* ISA PS/2 machines */ else if (strstr(machines[machine].name, " IBM XT ")) postcard_port = 0x60; /* IBM XT */ + else if (strstr(machines[machine].name, " Multistation ")) + postcard_port = 0xA1; /* IBM 5550 */ else if (strstr(machines[machine].name, " IBM PCjr")) { postcard_port = 0x10; /* IBM PCjr */ postcard_ports_num = 3; /* IBM PCjr error ports 11h and 12h */ diff --git a/src/dma.c b/src/dma.c index bfc294f2a..df9d4ac0e 100644 --- a/src/dma.c +++ b/src/dma.c @@ -978,10 +978,15 @@ dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) addr &= 0x0f; dmaregs[2][addr] = val; - if (addr >= 8) - addr = convert[addr & 0x07] | 4; - else - addr = convert[addr & 0x07]; + if (machines[machine].init == machine_xt_ibm5550_init) { + if (addr >= 4) + addr = 8; + } else { + if (addr >= 8) + addr = convert[addr & 0x07] | 4; + else + addr = convert[addr & 0x07]; + } if (addr < 8) { dma[addr].page_l = val; diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index d6d27da3b..cfc51f2b0 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -664,6 +664,21 @@ real_drive(fdc_t *fdc, int drive) return drive; } +void +fdc_diskchange_interrupt(fdc_t *fdc, int drive) +{ + /* + For the IBM 5550 machine to detect the disk in the drive has been changed. + A hardware interrupt is caused by the FDC (NEC uPD765A) when the Ready line from the drive changes its state. + Other PCs never use the Ready line. + */ + if (fdc->flags & FDC_FLAG_5550) { + fdc->st0 = 0xc0 | (drive & 3); + fdc_int(fdc, 1); + fdd_changed[drive] = 0; + } +} + /* FDD notifies FDC when seek operation is complete */ void fdc_seek_complete_interrupt(fdc_t *fdc, int drive) @@ -822,8 +837,47 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 0: return; case 1: + if (fdc->flags & FDC_FLAG_5550) { + val = 0; + if (!(val & 0x08)) { /* Drive 2 active */ + val = 0x42; + } + if (!(val & 0x04)) { /* Drive 1 active */ + val &= 0xf0; + val |= 0x21; + } + if (!(val & 0x02)) { /* Drive 0 active */ + val &= 0xf0; + val |= 0x10; + } + /* Update the DOR because this emulation module depend on it */ + fdc->dor &= 0x0c; + fdc->dor |= val; + /* We can now simplify this since each motor now spins separately. */ + for (int i = 0; i < FDD_NUM; i++) { + drive_num = real_drive(fdc, i); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) + val &= ~(0x10 << drive_num); + else + fdd_set_motor_enable(i, (val & (0x10 << drive_num))); + } + drive_num = real_drive(fdc, val & 0x03); + current_drive = drive_num; + fdc->st0 = (fdc->st0 & 0xf8) | (val & 0x03) | (fdd_get_head(drive_num) ? 4 : 0); + fdc_log("val:%x, dor=%x, drv=%x\n", val, fdc->dor, drive_num); + } return; case 2: /*DOR*/ + if (fdc->flags & FDC_FLAG_5550) { /* Reset */ + fdd_stop(fdc->drive); + for (int i = 0; i < FDD_NUM; i++) + fdd_set_motor_enable(i, 0); /* Need to restart fdd timer */ + fdc->stat = 0x00; + fdc->pnum = fdc->ptot = 0; + fdc_soft_reset(fdc); + fdc->dor = 0x0c; + return; + } if (fdc->flags & FDC_FLAG_PCJR) { if ((fdc->dor & 0x40) && !(val & 0x40)) { timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); @@ -903,6 +957,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } return; case 4: /* DSR */ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (!(fdc->flags & FDC_FLAG_NO_DSR_RESET)) { if (!(val & 0x80)) { timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); @@ -914,6 +970,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->dsr = val; return; case 5: /*Command register*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (fdc->fifointest) { /* Write FIFO buffer in the test mode (PS/55) */ fdc_log("FIFO buffer position = %X\n", ((fifo_t *) fdc->fifo_p)->end); @@ -948,7 +1006,33 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->command = val; fdc->stat |= 0x10; - fdc_log("Starting FDC command %02X\n", fdc->command); + fdc_log("Starting FDC command %02X ", fdc->command); + switch (fdc->command & 0x1f) { + case 0x06: + fdc_log("READ DATA\n"); + break; + case 0x0a: + fdc_log("READ ID\n"); + break; + case 0x07: + fdc_log("RECALIB\n"); + break; + case 0x08: + fdc_log("SENSE INTERRUPT\n"); + break; + case 0x03: + fdc_log("SPECIFY\n"); + break; + case 0x04: + fdc_log("SENSE DRIVE\n"); + break; + case 0x0f: + fdc_log("SEEK\n"); + break; + default: + fdc_log("\n"); + break; + } fdc->error = 0; if (((fdc->command & 0x1f) == 0x02) || ((fdc->command & 0x1f) == 0x05) || @@ -1106,6 +1190,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (command_has_drivesel[fdc->command & 0x1F]) { if (fdc->flags & FDC_FLAG_PCJR) fdc->drive = 0; + else if (fdc->flags & FDC_FLAG_5550) + fdc->drive = fdc->params[0] & 3; else fdc->drive = fdc->dor & 3; fdc->rw_drive = fdc->params[0] & 3; @@ -1115,6 +1201,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } if (fdc->pnum == fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); + for (int i = 0; i < fdc->ptot; i++) + fdc_log(" [%d] %02x\n", i, fdc->params[i]); fifo_reset(fdc->fifo_p); fdc->interrupt = fdc->processed_cmd; fdc->reset_stat = 0; @@ -1451,6 +1539,8 @@ fdc_read(uint16_t addr, void *priv) ret = 0xc0; ret |= (fdc->dor & 0x01) << 5; /* Drive Select 0 */ ret |= (fdc->dor & 0x30) >> 4; /* Motor Select 1, 0 */ + } else if (fdc->flags & FDC_FLAG_5550) { + ret = 0; } else { if (is486 || !fdc->enable_3f1) ret = 0xff; @@ -1503,9 +1593,13 @@ fdc_read(uint16_t addr, void *priv) ret = (fdc->rwc[drive] << 4) | (fdc->media_id << 6); break; case 4: /*Status*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); ret = fdc->stat; break; case 5: /*Data*/ + if (fdc->flags & FDC_FLAG_5550) + picintc(1 << fdc->irq); if (fdc->fifointest) { /* Read FIFO buffer in the test mode (PS/55) */ ret = fifo_read(fdc->fifo_p); @@ -1733,6 +1827,8 @@ fdc_callback(void *priv) } if (writeprot[fdc->drive]) fdc->res[10] |= 0x40; + if ((fdc->flags & FDC_FLAG_5550) && drive_empty[fdc->drive])//IBM 5550 + fdc->res[10] &= 0xdf; /* Set Not Ready */ fdc->stat = (fdc->stat & 0xf) | 0xd0; fdc->paramstogo = 1; @@ -2349,6 +2445,10 @@ fdc_set_base(fdc_t *fdc, int base) if (fdc->flags & FDC_FLAG_NSC) { io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else if (fdc->flags & FDC_FLAG_5550) { + io_sethandler(base, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2383,6 +2483,10 @@ fdc_remove(fdc_t *fdc) if (fdc->flags & FDC_FLAG_NSC) { io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else if (fdc->flags & FDC_FLAG_5550) { + io_removehandler(fdc->base_address, 0x0003, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 4, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 5, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); @@ -2534,6 +2638,8 @@ fdc_init(const device_t *info) fdc->irq = FDC_TERTIARY_IRQ; else if (fdc->flags & FDC_FLAG_QUA) fdc->irq = FDC_QUATERNARY_IRQ; + else if (fdc->flags & FDC_FLAG_5550) + fdc->irq = 4; else fdc->irq = FDC_PRIMARY_IRQ; @@ -2686,6 +2792,20 @@ const device_t fdc_xt_umc_um8398_device = { .config = NULL }; +const device_t fdc_xt_5550_device = { + .name = "IBM 5550 Floppy Drive Controller", + .internal_name = "fdc_xt_5550", + .flags = 0, + .local = FDC_FLAG_5550, + .init = fdc_init, + .close = fdc_close, + .reset = fdc_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t fdc_pcjr_device = { .name = "PCjr Floppy Drive Controller", .internal_name = "fdc_pcjr", diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 89ec2e9f6..592258cee 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -777,6 +777,10 @@ fdd_poll(void *priv) if (!fdd_notfound) fdc_noidam(fdd_fdc); } + + if (fdd_changed[drive]) { + fdc_diskchange_interrupt(fdd_fdc, drive); + } } int diff --git a/src/include/86box/fdc.h b/src/include/86box/fdc.h index ff56aa0ef..e1a818147 100644 --- a/src/include/86box/fdc.h +++ b/src/include/86box/fdc.h @@ -59,6 +59,7 @@ #define FDC_FLAG_TER 0x40000 /* Is Tertiary */ #define FDC_FLAG_QUA 0x80000 /* Is Quaternary */ #define FDC_FLAG_SMC661 0x100000 /* SM(s)C FDC37C661 - different TDR enhanced mode */ +#define FDC_FLAG_5550 0x200000 /* IBM Multistation 5550 */ typedef struct fdc_t { uint8_t dor; @@ -252,6 +253,7 @@ extern void fdc_reset(void *priv); extern uint8_t fdc_get_current_drive(void); extern void fdc_seek_complete_interrupt(fdc_t *fdc, int drive); +extern void fdc_diskchange_interrupt(fdc_t *fdc, int drive); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; @@ -262,6 +264,7 @@ extern const device_t fdc_xt_t1x00_device; extern const device_t fdc_xt_tandy_device; extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_xt_umc_um8398_device; +extern const device_t fdc_xt_5550_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_sec_device; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 8b32851bb..16aec312f 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -170,6 +170,7 @@ extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); extern void kbd_adddata_process_10x(uint16_t val, void (*adddata)(uint16_t val)); extern const scancode scancode_xt[512]; +extern const scancode scancode_set8a[512]; extern uint8_t keyboard_set3_flags[512]; extern uint8_t keyboard_set3_all_repeat; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index a7920bad0..75dd4f40e 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1494,6 +1494,10 @@ extern int machine_xt_iskra3104_init(const machine_t *); extern int machine_xt_lxt3_init(const machine_t *); extern int machine_xt_compaq_deskpro_init(const machine_t *); +/* m_xt_ibm5550.c */ + +extern int machine_xt_ibm5550_init(const machine_t *); + /* m_xt_t1000.c */ #ifdef EMU_DEVICE_H extern const device_t t1000_video_device; diff --git a/src/include/86box/pit.h b/src/include/86box/pit.h index 991be4424..bc346f549 100644 --- a/src/include/86box/pit.h +++ b/src/include/86box/pit.h @@ -90,6 +90,8 @@ typedef struct pit_intf_t { void (*write)(uint16_t addr, uint8_t val, void *priv); /* Gets a counter's count. */ uint16_t (*get_count)(void *data, int counter_id); + /* Gets a counter's out. */ + int (*get_outlevel)(void *data, int counter_id); /* Sets a counter's GATE input. */ void (*set_gate)(void *data, int counter_id, int gate); /* Sets if a counter's CLOCK input is from the timer or not - used by PCjr. */ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 816c9d38c..30d9da51d 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -26,6 +26,7 @@ add_library(mch OBJECT m_europc.c m_elt.c m_xt_olivetti.c + m_xt_ibm5550.c m_tandy.c m_v86p.c m_at_t3100e.c diff --git a/src/machine/m_xt_ibm5550.c b/src/machine/m_xt_ibm5550.c new file mode 100644 index 000000000..9ea03f494 --- /dev/null +++ b/src/machine/m_xt_ibm5550.c @@ -0,0 +1,2149 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the IBM 5550 machine. + * + * The IBM 5550 was launched with three models: + * 5551-Axx: 12" monochrome CRT with 16x16 font + * (replaced by model D) + * 5551-Bxx: 15" monochrome CRT with 24x24 font + * (replaced by model G, J, M) + * 5551-Cxx: 14" color CRT with 16x16 font + * (replaced by model E, H, K, P) + * These first-gen models have 1-3 DSQD diskette drives. + * You need select "Type: 5.25" 720k" in the Settings dialog - Floppy & CD-ROM drives. + * + * Currently, this module only support the model B configuration without hard disk. + * + * Authors: Akamaki. + * + * Copyright 2026 Akamaki. + */ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/dma.h> +#include <86box/pic.h> +#include <86box/ppi.h> +#include <86box/nmi.h> +#include <86box/mem.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/nvr.h> +#include <86box/keyboard.h> +#include <86box/rom.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/serial.h> +#include <86box/snd_speaker.h> +#include <86box/video.h> +#include <86box/machine.h> +#include <86box/plat_unused.h> +#define EMU_DEVICE_H +#include <86box/pit.h> + +// #define EPOCH_FONTROM_SIZE (1024 * 1024) +// #define EPOCH_FONTROM_MASK 0xffff +// #define EPOCH_FONTROM_BASESBCS 0x98000 +#define EPOCH_VRAM_SBCS 0x38000 +#define EPOCH_VRAM_SBEX 0x30000 +#define EPOCH_INVALIDACCESS8 0xffu +#define EPOCH_INVALIDACCESS16 0xffffu +#define EPOCH_INVALIDACCESS32 0xffffffffu +#define EPOCH_SIZE_VRAM (256 * 1024) /* 0x40000 */ +#define EPOCH_SIZE_CRAM (4 * 1024) /* 0x1000 */ +#define EPOCH_MASK_A000 0x1ffff /* 0x1FFFF */ +#define EPOCH_MASK_CRAM 0xfff /* 0xFFF */ +#define EPOCH_MASK_VRAM 0x3ffff /* 0xFFFFF */ +// #define EPOCH_MASK_VRAMPLANE 0x1ffff /* 0x1FFFF */ +#define EPOCH_PIXELCLOCK 40000000.0 /* 40 MHz interlaced */ + +#define LC_INDEX 0x3D0 +#define LC_DATA 0x3D1 +#define LS_ENABLE 0x3D2 +#define LS_DISABLE 0x3D3 +#define LC_HORIZONTAL_TOTAL 0x00 /* -1 */ +#define LC_HORIZONTAL_DISPLAYED 0x01 +#define LC_H_SYNC_POSITION 0x02 +#define LC_SYNC_WIDTH 0x03 +#define LC_VERTICAL_TOTAL 0x04 /* -1 */ +#define LC_V_TOTAL_ADJUST 0x05 +#define LC_VERTICAL_DISPLAYED 0x06 +#define LC_V_SYNC_POSITION 0x07 +#define LC_INTERLACE_AND_SKEW 0x08 +#define LC_MAXIMUM_SCAN_LINE 0x09 /* -1 */ +#define LC_CURSOR_ROW_START 0x0A +#define LC_CURSOR_ROW_END 0x0B +#define LC_START_ADDRESS_HIGH 0x0C +#define LC_START_ADDRESS_LOW 0x0D +#define LC_CURSOR_LOC_HIGH 0x0E +#define LC_CURSOR_LOC_LOWJ 0x0F +#define LC_LIGHT_PEN_HIGH 0x10 +#define LC_LIGHT_PEN_LOW 0x11 +// #define LV_PORT 0x3E8 +// #define LV_PALETTE_0 0x00 +// #define LV_MODE_CONTROL 0x10 +// #define LV_OVERSCAN_COLOR 0x11 +// #define LV_COLOR_PLANE_ENAB 0x12 +// #define LV_PANNING 0x13 +// #define LV_VIEWPORT1_BG 0x14 +// #define LV_VIEWPORT2_BG 0x15 +// #define LV_VIEWPORT3_BG 0x16 +// #define LV_BLINK_COLOR 0x17 +// #define LV_BLINK_CODE 0x18 +// #define LV_GR_CURSOR_ROTATION 0x19 +// #define LV_GR_CURSOR_COLOR 0x1A +// #define LV_GR_CURSOR_CONTROL 0x1B +// #define LV_COMMAND 0x1C +// #define LV_VP_BORDER_LINE 0x1D +// #define LV_SYNC_POLARITY 0x1F +// #define LV_CURSOR_CODE_0 0x20 +// #define LV_GRID_COLOR_0 0x34 +// #define LV_GRID_COLOR_1 0x35 +// #define LV_GRID_COLOR_2 0x36 +// #define LV_GRID_COLOR_3 0x37 +// #define LV_ATTRIBUTE_CNTL 0x38 +// #define LV_CURSOR_COLOR 0x3A +// #define LV_CURSOR_CONTROL 0x3B +// #define LV_RAS_STATUS_VIDEO 0x3C +// #define LV_PAS_STATUS_CNTRL 0x3D +// #define LV_IDENTIFICATION 0x3E +// #define LV_OUTPUT 0x3E +// #define LV_COMPATIBILITY 0x3F + +#define TIMER_CTR_0 0 //DMA +#define TIMER_CTR_1 1 //8253 timer +#define TIMER_CTR_2 2 //Speaker + +#define EPOCH_IRQ3_BIT (1 << 3) //Keyboard +#define EPOCH_IRQ6_BIT (1 << 6) //Timer + +enum epoch_nvr_ADDR { + epoch_nvr_SECOND1, + epoch_nvr_SECOND10, + epoch_nvr_MINUTE1, + epoch_nvr_MINUTE10, + epoch_nvr_HOUR1, + epoch_nvr_HOUR10, + epoch_nvr_WEEKDAY, + epoch_nvr_DAY1, + epoch_nvr_DAY10, + epoch_nvr_MONTH1, + epoch_nvr_MONTH10, + epoch_nvr_YEAR1, + epoch_nvr_YEAR10, + epoch_nvr_UNKOWN_D, + epoch_nvr_UNKOWN_E, + epoch_nvr_UNKOWN_F, + epoch_nvr_CONTROL /* Internal data for configuration port (I/O 360h) */ +}; + +#ifndef RELEASE_BUILD +// #define ENABLE_EPOCH_LOG 1 +#endif + +#ifdef ENABLE_EPOCH_LOG +// # define ENABLE_EPOCH_DEBUGIO 1 +int epoch_do_log = ENABLE_EPOCH_LOG; + +static void +epoch_log(const char *fmt, ...) +{ + va_list ap; + + if (epoch_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define epoch_log(fmt, ...) +#endif +#ifdef ENABLE_EPOCH_DEBUGIO +# define epoch_iolog epoch_log +#else +# define epoch_iolog(fmt, ...) +#endif + +typedef struct epoch_t { + mem_mapping_t cmapping; + + uint16_t crtc[32]; + // uint16_t crtc_vpreg[128]; + // uint8_t crtc_vpsel; + uint8_t crtmode; + // uint8_t attrc[0x40]; + // int attraddr, attrff; + // int attr_palette_enable; + int outflipflop; + int inflipflop; + int iolatch; + + int crtcaddr; + + uint8_t cgastat; + + // int writemode, readplane; + // uint8_t planemask; + + uint8_t egapal[16]; + uint32_t pallook[64]; + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres; + int rowcount; + double clock; + uint32_t memaddr_latch, ca_adj; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + uint64_t epochconst; + + int dispon; + int hdisp_on; + + uint32_t memaddr, memaddr_backup, cursoraddr; + int vc; + int scanline; + int linepos, vslines, linecountff; + int cursorvisible, cursoron, blink; + int scrollcache; + int char_width; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + int oddeven; + + /* Attribute Buffer E0000-E0FFFh (4 KB) */ + uint8_t *cram; + /* SBCS Font Buffer D8000-DBFFFh (16 KB) */ + /* APA Buffer A0000-DFFFFh (256 KB) */ + uint8_t *vram; + mem_mapping_t cmap, vmap, paritymap; + /* Font ROM card option (?KB) */ + // struct { + // int bank; + // mem_mapping_t map; + // uint8_t *rom; + // int charset; + // int portdata; + // } fontcard; + // uint8_t *changedvram; + uint32_t vram_display_mask; + + int parityerror; + int parityenabled; + uint8_t parityerroraddr; + int lowmemorydisabled; + int crtioenabled; + + int fullchange; + + void (*render)(struct epoch_t *epoch); + + nvr_t nvr; + int nvrctrl; + int nvrdata; + +} epoch_t; + +static void epoch_recalctimings(epoch_t *epoch); +static void epoch_reset(void *priv); + +/* +[IRQ] +The IBM 5550 has different IRQ assignments like the 6580 Displaywriter System. + +| IRQ | 5550 | Displaywriter | PC/XT | +| --- | ---------- | ---------------------------------- | ---------------- | +| 0 | ? | Incoming data for printer sharing | Timer | +| 1 | Async Comm | Transfer data to commo data link | Keyboard | +| 2 | Fixed Disk | Printer and Mag Card data transfer | Reserved | +| 3 | Keyboard | Keyboard incoming data | Async Comm (Sec) | +| 4 | Diskette | Diskette interrupt | Async Comm (Pri) | +| 5 | ? | Not used | Fixed Disk | +| 6 | Timer | Software timer | Diskette | +| 7 | ? | Error on commo data link | Printer | + +[Memory map] +| Start Address | Function | +| ------------- | ----------------------------------------------------- | +| 0 | 256 KB RAM on System Board | +| 40000h | 128 KB Expansion RAM Card | +| 60000h | 128 KB Expansion RAM Card | +| 80000h | 128 KB Expansion RAM Card | +| A0000h | 256 KB Video RAM | +| E0000h | 4 KB Code/Attribute Buffer | +| E8000h | ? KB Hard Disk Control Local Memory (not implemented) | +| F0000h | Kanji Font Card (not implemented) | +| FC000h | ROM | +*/ + +static void +epoch_out(uint16_t addr, uint16_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + int oldval; + epoch_iolog("%04X:%04X epoch Out addr %03X val %02X\n", cs >> 4, cpu_state.pc, addr, val); + switch (addr) { + case LC_INDEX: + epoch->crtcaddr = val; + break; + case LC_DATA: + if (epoch->crtcaddr > 0x1f) + return; + if (epoch->crtioenabled == 0) + return; + if (!(epoch->crtcaddr == LC_CURSOR_LOC_HIGH || epoch->crtcaddr == LC_CURSOR_LOC_LOWJ)) + epoch_iolog("%04X:%04X epoch Out addr %03X idx %02X val %02X (%d)\n", cs >> 4, cpu_state.pc, addr, epoch->crtcaddr, val, val); + if (!(epoch->crtc[epoch->crtcaddr] ^ val)) + return; + // switch (epoch->crtcaddr) { + // // case LC_CRTC_OVERFLOW: + // // // return; + // // break; + // case LC_MAXIMUM_SCAN_LINE: + // // if (!(epoch->ioctl[LS_MODE] & 0x01)) /* 16 or 256 color graphics mode */ + // // val = 0; + // break; + // // case LC_VERTICAL_TOTALJ: /* Vertical Total */ + // // break; + // } + switch (epoch->crtcaddr) { + case LC_START_ADDRESS_HIGH: + case LC_CURSOR_LOC_HIGH: + case LC_LIGHT_PEN_HIGH: + val &= 0x3F; + break; + } + epoch->crtc[epoch->crtcaddr] = val; + switch (epoch->crtcaddr) { + case LC_HORIZONTAL_DISPLAYED: + case LC_VERTICAL_DISPLAYED: + case LC_MAXIMUM_SCAN_LINE: + case LC_START_ADDRESS_HIGH: + case LC_START_ADDRESS_LOW: + epoch->fullchange = changeframecount; + epoch_recalctimings(epoch); + break; + default: + break; + } + break; + case LS_ENABLE: + // mem_mapping_disable(&epoch->paritymap); + epoch->crtioenabled = 1; + mem_mapping_enable(&epoch->cmap); + mem_mapping_enable(&epoch->vmap); + break; + case LS_DISABLE: + epoch->crtioenabled = 0; + mem_mapping_disable(&epoch->cmap); + mem_mapping_disable(&epoch->vmap); + // mem_mapping_enable(&epoch->paritymap); + break; + case 0x3D8: + epoch->crtmode = val; + epoch_recalctimings(epoch); + // epoch->attrff ^= 1; + break; + // case LV_PORT: + // // epoch_iolog("epoch Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, epoch->attrff,cs >> 4, cpu_state.pc); + // if (!epoch->attrff) { + // epoch->attraddr = val & 0x3f; + // if ((val & 0x20) != (epoch->attr_palette_enable & 0x20)) { + // epoch->fullchange = 3; + // epoch->attr_palette_enable = val & 0x20; + // epoch_recalctimings(epoch); + // } + // // epoch_iolog("set attraddr: %X\n", epoch->attraddr); + // } else { + // if ((epoch->attraddr == LV_PANNING) && (epoch->attrc[LV_PANNING] != val)) + // epoch->fullchange = changeframecount; + // if (epoch->attrc[epoch->attraddr & 0x3f] != val) + // epoch_iolog("attr changed %x: %x -> %x\n", epoch->attraddr & 0x3f, epoch->attrc[epoch->attraddr & 0x3f], val); + // epoch->attrc[epoch->attraddr & 0x3f] = val; + // // epoch_iolog("set attrc %x: %x\n", epoch->attraddr & 31, val); + // if (epoch->attraddr < 16) + // epoch->fullchange = changeframecount; + // if (epoch->attraddr == LV_MODE_CONTROL || epoch->attraddr < 0x10) { + // for (uint8_t c = 0; c < 16; c++) { + // // if (epoch->attrc[LV_MODE_CONTROL] & 0x80) + // // epoch->egapal[c] = epoch->attrc[c] & 0xf; + // // else + // // epoch->egapal[c] = epoch->attrc[c] & 0x3f; + // } + // } + // switch (epoch->attraddr) { + // case LV_COLOR_PLANE_ENAB: + // if ((val & 0xff) != epoch->plane_mask) + // epoch->fullchange = changeframecount; + // epoch->plane_mask = val & 0xff; + // break; + // case LV_CURSOR_CONTROL: + // switch (val & 0x18) { + // case 0x08: /* fast blink */ + // epoch->blinkconf = 0x10; + // break; + // case 0x18: /* slow blink */ + // epoch->blinkconf = 0x20; + // break; + // default: /* no blink */ + // epoch->blinkconf = 0xff; + // break; + // } + // break; + // case LV_MODE_CONTROL: + // case LV_ATTRIBUTE_CNTL: + // case LV_COMPATIBILITY: + // epoch_recalctimings(epoch); + // break; + // default: + // break; + // } + // } + // epoch->attrff ^= 1; + // break; + // case LV_PORT+1: + // /* VZ Editor's CURSOR.COM writes data via this port */ + // epoch->attrc[epoch->attraddr & 0x3f] = val; + // break; + default: + epoch_iolog("epoch? Out addr %03X val %02X\n", addr, val); + break; + } +} + +static uint16_t +epoch_in(uint16_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint16_t temp = 0xff; + + switch (addr) { + case LC_INDEX: + temp = epoch->crtcaddr; + break; + case LC_DATA: + if (epoch->crtcaddr > 0x1f) + return EPOCH_INVALIDACCESS16; + if (epoch->crtioenabled == 0) + return EPOCH_INVALIDACCESS16; + temp = epoch->crtc[epoch->crtcaddr]; + break; + // case LV_PORT: + // temp = epoch->attraddr | epoch->attr_palette_enable; + // break; + // case LV_PORT + 1: + // switch (epoch->attraddr) { + // case LV_RAS_STATUS_VIDEO: /* this maybe equivalent to 3ba / 3da ISR1 */ + // if (epoch->cgastat & 0x01) + // epoch->cgastat &= ~0x30; + // else + // epoch->cgastat ^= 0x30; /* toggle */ + // if (epoch->cgastat & 0x08) + // epoch->cgastat &= ~0x08; + // else + // epoch->cgastat ^= 0x08; /* toggle */ + // temp = epoch->cgastat; + // break; + // case LV_IDENTIFICATION: + // temp = 0x28; + // break; + // default: + // temp = epoch->attrc[epoch->attraddr]; + // break; + // } + // // epoch_iolog("epoch In %04X(%02X) %04X %04X:%04X\n", addr, epoch->attraddr, temp, cs >> 4, cpu_state.pc); + // epoch->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */ + // break; + case 0x3DA: + temp = 0xff; + if (!(epoch->crtmode & 0x08)) {/* The video out is active */ + if(epoch->cgastat & 8) + temp &= 0x7f; + } + temp &= 0xfe;/* equipment ? color or monochrome monitor */ + // temp |= 0x01; + break; + } + if (addr != 0x3DA) + epoch_iolog("%04X:%04X epoch In %04X %04X\n", cs >> 4, cpu_state.pc, addr, temp); + return temp; +} +/* + * Write I/O + * out b(idx), out b(data), out b(data) + * out b(idx), out w(data) + * out b(idx), out w(data), out b(data) + * out w(idx) + * Read I/O + * out b(idx), in b(data) + * out b(idx), in b, in b(data) + * out b(idx), in w(data) + */ +static void +epoch_outb(uint16_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_iolog("%04X:%04X epoch Outb addr %03X val %02X es:di=%x:%x ds:si=%x:%x\n", cs >> 4, cpu_state.pc, addr, val, ES, DI, DS, SI); + epoch->inflipflop = 0; + switch (addr) { + // case LS_DATA: + // case LF_DATA: + case LC_DATA: + if (epoch->outflipflop) { + /* out b(idx), out b(data), out b(data) */ + epoch->iolatch |= (uint16_t) val << 8; + epoch->outflipflop = 0; + } else { // + epoch->iolatch = val; + epoch->outflipflop = 1; + } + break; + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + default: + epoch->iolatch = val; + epoch->outflipflop = 0; + break; + } + epoch_out(addr, epoch->iolatch, epoch); +} +void +epoch_outw(uint16_t addr, uint16_t val, void *priv) +{ + epoch_iolog("epoch Outw addr %03X val %04X\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + epoch->inflipflop = 0; + switch (addr) { + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + // case LG_INDEX: + epoch_out(addr, val & 0xff, epoch); + epoch->iolatch = val >> 8; + epoch_out(addr + 1, epoch->iolatch, epoch); + epoch->outflipflop = 1; + break; + // case LV_PORT: + // // epoch->attrff = 0; + // epoch_out(addr, val & 0xff, epoch); + // epoch_out(addr, val >> 8, epoch); + // epoch->outflipflop = 0; + // break; + // case LS_DATA: + // case LF_DATA: + case LC_DATA: + // case LG_DATA: + default: + epoch_out(addr, val, epoch); + epoch->outflipflop = 0; + break; + } +} +static uint8_t +epoch_inb(uint16_t addr, void *priv) +{ + uint8_t temp; + epoch_t *epoch = (epoch_t *) priv; + epoch->outflipflop = 0; + switch (addr) { + case LC_DATA: + if (epoch->inflipflop) { + /* out b(idx), in b(low data), in b(high data) */ + temp = epoch->iolatch >> 8; + epoch->inflipflop = 0; + } else { // + epoch->iolatch = epoch_in(addr, epoch); + temp = epoch->iolatch & 0xff; + epoch->inflipflop = 1; + } + break; + // case LS_INDEX: + // case LF_INDEX: + case LC_INDEX: + // case LS_DATA: + // case LF_DATA: + default: + temp = epoch_in(addr, epoch) & 0xff; + epoch->inflipflop = 0; + break; + } + // epoch_iolog("epoch Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc); + return temp; +} +static uint16_t +epoch_inw(uint16_t addr, void *priv) +{ + uint16_t temp; + epoch_t *epoch = (epoch_t *) priv; + epoch->inflipflop = 0; + epoch->outflipflop = 0; + temp = epoch_in(addr, epoch); + epoch_iolog("epoch Inw addr %03X val %04X\n", addr, temp); + return temp; +} + +/* Get character line pattern from jfont rom or gaiji volatile memory */ +static uint32_t +getfont_ps55dbcs(int32_t code, int32_t line, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint32_t font = 0; + int32_t fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ + if (code < 1536) { + code *= 0x80; + font = epoch->vram[code + line * 4]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 1]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 2]; + font <<= 8; + font |= epoch->vram[code + line * 4 + 3]; + } else + font = EPOCH_INVALIDACCESS32; + return font; +} + +/* Get the foreground color from the attribute byte */ +static uint8_t +getPS55ForeColor(uint8_t attr, epoch_t *epoch) +{ + uint8_t foreground = ~attr & 0x08; /* 0000 1000 */ + foreground <<= 2; /* 0010 0000 */ + foreground |= ~attr & 0xc0; /* 1110 0000 */ + foreground >>= 4; /* 0000 1110 */ + // if (epoch->attrc[LV_PAS_STATUS_CNTRL] & 0x40) + // foreground |= 0x01; /* bright color palette */ + return foreground; +} + +static void +epoch_render_blank(epoch_t *epoch) +{ + int x, xx; + + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + + for (x = 0; x < epoch->hdisp + epoch->scrollcache; x++) { + for (xx = 0; xx < epoch->char_width; xx++) + ((uint32_t *) buffer32->line[epoch->displine])[(x * epoch->char_width) + xx] = 0; + } +} +/* Display Adapter Mode 8, E Drawing */ +static void +epoch_render_text(epoch_t *epoch) +{ + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + + if (epoch->fullchange) { + int offset = (8 - epoch->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[epoch->displine])[offset]; + int x; + int drawcursor; + uint8_t chr, attr; + int fg, bg; + uint32_t chr_dbcs; + int chr_wide = 0; + // int colormode = ((epoch->attrc[LV_PAS_STATUS_CNTRL] & 0x80) == 0x80); + int colormode = 0; + // epoch_log("displ: %x, first: %x, epochma: %x, epochsc: %x\n", + // epoch->displine , epoch->firstline_draw, epoch->memaddr, epoch->scanline); + for (x = 0; x < epoch->hdisp; x += 13) { + chr = epoch->cram[(epoch->memaddr) & EPOCH_MASK_CRAM]; + attr = epoch->cram[(epoch->memaddr + 1) & EPOCH_MASK_CRAM]; + // if(chr!=0x20) epoch_log("chr: %x, attr: %x ", chr, attr); + if (colormode) /* IO 3E8h, Index 1Dh */ + { /* --Parse attribute byte in color mode-- */ + bg = 0; /* bg color is always black (the only way to change background color is programming PAL) */ + fg = getPS55ForeColor(attr, epoch); + if (attr & 0x04) { /* reverse 0000 0100 */ + bg = fg; + fg = 0; + } + } else { /* --Parse attribute byte in monochrome mode-- */ + if (attr & 0x08) + fg = 3; /* Highlight 0000 1000 */ + else + fg = 2; + bg = 0; /* Background is always color #0 (default is black) */ + if (!(~attr & 0xCC)) /* Invisible 11xx 11xx -> 00xx 00xx */ + { + fg = bg; + attr &= 0x33; /* disable blinkking, underscore, highlight and reverse */ + } + if (attr & 0x04) { /* reverse 0000 0100 */ + bg = fg; + fg = 0; + } + /* Blinking 1000 0000 */ + fg = ((epoch->blink & 0x20) || (!(attr & 0x80))) ? fg : bg; + // if(chr!=0x20) epoch_log("chr: %x, %x, %x, %x, %x ", chr, attr, fg, epoch->egapal[fg], epoch->pallook[epoch->egapal[fg]]); + } + /* Draw character */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[bg]]; /* draw blank */ + /* SBCS or DBCS left half */ + if (chr_wide == 0) { + if (attr & 0x01) + chr_wide = 1; + // chr_wide = 0; + /* Stay drawing If the char code is DBCS and not at last column. */ + if (chr_wide) { + /* Get high DBCS code from the next video address */ + chr_dbcs = epoch->cram[(epoch->memaddr + 2) & EPOCH_MASK_CRAM]; + chr_dbcs <<= 8; + chr_dbcs |= chr; + /* Get the font pattern */ + uint32_t font = getfont_ps55dbcs(chr_dbcs, epoch->scanline, epoch); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x80000000) ? fg : bg]]; + font <<= 1; + } + } else { + /* the char code is SBCS (ANK) */ + uint32_t fontbase; + if (attr & 0x02) /* second map of SBCS font */ + fontbase = EPOCH_VRAM_SBEX; + else + fontbase = EPOCH_VRAM_SBCS; + uint16_t font = epoch->vram[fontbase + chr * 0x80 + epoch->scanline * 4]; /* w13xh29 font */ + font <<= 8; + font |= epoch->vram[fontbase + chr * 0x80 + epoch->scanline * 4 + 1]; /* w13xh29 font */ + // if(chr!=0x20) epoch_log("memaddr: %x, scanline: %x, chr: %x, font: %x ", epoch->memaddr, epoch->scanline, chr, font); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + } + } + /* right half of DBCS */ + else { + uint32_t font = getfont_ps55dbcs(chr_dbcs, epoch->scanline, epoch); + /* Draw 13 dots */ + for (uint32_t n = 0; n < 13; n++) { + p[n] = epoch->pallook[epoch->egapal[(font & 0x8000) ? fg : bg]]; + font <<= 1; + } + chr_wide = 0; + } + /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ + if (epoch->scanline == 28 && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[fg]]; /* under line (white) */ + } + /* Column 1 (Vertical Line) */ + if (attr & 0x10) { + p[0] = epoch->pallook[epoch->egapal[2]]; /* vertical line (white) */ + } + if (epoch->scanline == 0 && attr & 0x20) { /* HGrid */ + for (uint32_t n = 0; n < 13; n++) + p[n] = epoch->pallook[epoch->egapal[2]]; /* horizontal line (white) */ + } + /* Drawing text cursor */ + drawcursor = ((epoch->memaddr == epoch->cursoraddr) && epoch->cursorvisible && epoch->cursoron); + if (drawcursor && epoch->scanline >= epoch->crtc[LC_CURSOR_ROW_START] && epoch->scanline <= epoch->crtc[LC_CURSOR_ROW_END]) { + // int cursorwidth = (epoch->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); + int cursorwidth = 13; + int cursorcolor = 2; /* Choose color 2 if mode 8 */ + fg = ((attr & 0x08) ? 3 : 2); + bg = 0; + if (attr & 0x04) { /* Color 0 if reverse */ + bg = fg; + fg = 0; + } + for (uint32_t n = 0; n < cursorwidth; n++) + if (p[n] == epoch->pallook[epoch->egapal[cursorcolor]] || epoch->egapal[bg] == epoch->egapal[cursorcolor]) + p[n] = (p[n] == epoch->pallook[epoch->egapal[bg]]) ? epoch->pallook[epoch->egapal[fg]] : epoch->pallook[epoch->egapal[bg]]; + else + p[n] = (p[n] == epoch->pallook[epoch->egapal[bg]]) ? epoch->pallook[epoch->egapal[cursorcolor]] : p[n]; + } + epoch->memaddr += 2; + p += 13; + } + } +} + +static void +epoch_render_color_4bpp(epoch_t *epoch) +{ + // int changed_offset = epoch->memaddr >> 9; + // epoch_log("memaddr %x cf %x\n", epoch->memaddr, changed_offset); + // epoch->plane_mask &= 1; /*safety */ + + // if (epoch->changedvram[changed_offset] || epoch->changedvram[changed_offset + 1] || epoch->fullchange) { + int x; + int offset = (8 - epoch->scrollcache) + 24; + uint32_t *p = &((uint32_t *) buffer32->line[epoch->displine])[offset]; + + if (epoch->firstline_draw == 2000) + epoch->firstline_draw = epoch->displine; + epoch->lastline_draw = epoch->displine; + // epoch_log("d %X\n", epoch->memaddr); + int readvaddr = (epoch->memaddr * 8) + (epoch->scanline * 128); + for (x = 0; x <= epoch->hdisp; x += 8) /* hdisp = 1024 */ + { + uint8_t edat[8]; + uint8_t dat; + + /* get 8 pixels from vram */ + readvaddr &= epoch->vram_display_mask; + *(uint8_t *) (&edat[0]) = *(uint8_t *) (&epoch->vram[readvaddr]); + readvaddr += 1; + + dat = ((edat[0] >> 7) & 1); + p[0] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 6) & 1); + p[1] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 5) & 1); + p[2] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 4) & 1); + p[3] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 3) & 1); + p[4] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 2) & 1); + p[5] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 1) & 1); + p[6] = epoch->pallook[epoch->egapal[dat]]; + dat = ((edat[0] >> 0) & 1); + p[7] = epoch->pallook[epoch->egapal[dat]]; + p += 8; + } +} + +/* + INT 10h video modes supported in DOS K3.44. + Mode Type Colors Text Base Address PELs Render + 2 A/N 3 80 x 25 E0000h 1040 x 725 text + 8 A/N/K 3 80 x 25 E0000h 1040 x 725 text + Ah APA 2 78 x 25 A0000h 1024 x 768 color_4bpp + Bh APA 16 40 x 25 A0000h 360 x 512 n/a + Ch APA 16 80 x 25 A0000h 720 x 512 n/a + Dh APA 16 78 x 25 A0000h 1024 x 768 n/a + Eh A/N/K 16 80 x 25 E0000h 1040 x 725 n/a +*/ +static void +epoch_recalctimings(epoch_t *epoch) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + + epoch->vblankstart = epoch->crtc[LC_VERTICAL_TOTAL] & 0x7f; + epoch->dispend = epoch->crtc[LC_VERTICAL_DISPLAYED] & 0x7f; + epoch->vsyncstart = epoch->crtc[LC_V_SYNC_POSITION] & 0x7f; + epoch->vblankstart += 1; + epoch->vtotal = epoch->vblankstart + (epoch->crtc[LC_V_TOTAL_ADJUST] & 0x1f); + epoch->hdisp = epoch->crtc[LC_HORIZONTAL_DISPLAYED] & 0xff; + + // epoch->hdisp -= epoch->crtc[LC_START_H_DISPLAY_ENAB]; + // epoch->dispend -= epoch->crtc[LC_START_V_DISPLAY_ENAB]; + //epoch_log("Dispend %d\n", epoch->dispend); + // epoch->vsyncstart += 1; + //epoch->vtotal += 1; + + epoch->htotal = epoch->crtc[LC_HORIZONTAL_TOTAL] & 0xff; + epoch->htotal += 1; + + // epoch->rowoffset = epoch->crtc[LC_OFFSET]; /* number of bytes in a scanline */ + epoch->rowoffset = epoch->crtc[LC_HORIZONTAL_DISPLAYED] & 0xff; + + epoch->clock = epoch->epochconst; + + if (epoch->vtotal == 0) + epoch->vtotal = epoch->vsyncstart = epoch->vblankstart = 32; + if (epoch->htotal == 0) + epoch->htotal = epoch->dispend = epoch->hdisp = 64; + if (epoch->rowoffset == 0) + epoch->rowoffset = 64 * 2; /* To avoid causing a DBZ error */ + + epoch->memaddr_latch = ((epoch->crtc[LC_START_ADDRESS_HIGH] & 0x3f) << 8) | epoch->crtc[LC_START_ADDRESS_LOW]; + + epoch->ca_adj = 0; + epoch->rowcount = epoch->crtc[LC_MAXIMUM_SCAN_LINE] & 0x1f; + epoch->rowcount += 1; + + epoch->vtotal *= (epoch->rowcount + 1); + epoch->dispend *= (epoch->rowcount + 1); + epoch->vsyncstart *= (epoch->rowcount + 1); + epoch->vblankstart *= (epoch->rowcount + 1); + + epoch->hdisp_time = epoch->hdisp; + + /* determine display mode */ + if (epoch->crtmode & 0x02) { + epoch->hdisp *= 16; + epoch->char_width = 16; + /* PS/55 8-color */ + epoch_log("Set videomode to PS/55 4 bpp graphics.\n"); + epoch->render = epoch_render_color_4bpp; + epoch->vram_display_mask = EPOCH_MASK_A000; + } else { + /* PS/55 text(color/mono) */ + epoch_log("Set videomode to PS/55 Mode 8/E text.\n"); + epoch->render = epoch_render_text; + epoch->vram_display_mask = EPOCH_MASK_CRAM; + epoch->hdisp *= 13; + epoch->char_width = 13; + } + if (epoch->crtmode & 0x08) + epoch->render = epoch_render_blank; + + if (epoch->vblankstart < epoch->vsyncstart) + epoch->vsyncstart = epoch->vblankstart; + if (epoch->vsyncstart < epoch->dispend) + epoch->dispend = epoch->vsyncstart; + + crtcconst = epoch->clock * epoch->char_width; + + disptime = epoch->htotal; + _dispontime = epoch->hdisp_time; + + epoch_log("Disptime %f dispontime %f hdisp %i\n", disptime, _dispontime, epoch->hdisp); + + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + epoch->dispontime = (uint64_t) _dispontime; + epoch->dispofftime = (uint64_t) _dispofftime; + if (epoch->dispontime < TIMER_USEC) + epoch->dispontime = TIMER_USEC; + if (epoch->dispofftime < TIMER_USEC) + epoch->dispofftime = TIMER_USEC; + epoch_log("epoch horiz display end %i vidclock %f htotal %i\n", epoch->hdisp, epoch->clock, epoch->htotal); + epoch_log("epoch vert display end %i max row %i vsyncstart %i vtotal %i\n",epoch->dispend,epoch->rowcount,epoch->vsyncstart,epoch->vtotal); + epoch_log("epoch dispon %lu dispoff %lu on(us) %f off(us) %f\n",epoch->dispontime, epoch->dispofftime, + (double)epoch->dispontime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0, + (double)epoch->dispofftime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0); +} + +static void +epoch_doblit(int wx, int wy, epoch_t *epoch) +{ + if (wx != xsize || wy != ysize) { + xsize = wx; + ysize = wy; + set_screen_size(xsize, ysize); + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(32, 0, xsize, ysize); + frames++; + + video_res_x = wx; + video_res_y = wy; + video_bpp = 8; +} + +static void +epoch_poll(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + int x; + + if (!epoch->linepos) { + timer_advance_u64(&epoch->timer, epoch->dispofftime); + + epoch->cgastat |= 1; + epoch->linepos = 1; + + if (epoch->dispon) { + epoch->hdisp_on = 1; + + epoch->memaddr &= epoch->vram_display_mask; + if (epoch->firstline == 2000) { + epoch->firstline = epoch->displine; + video_wait_for_buffer(); + } + + if((epoch->displine ^ !epoch->oddeven) & 1) + epoch->render(epoch); + + if (epoch->lastline < epoch->displine) + epoch->lastline = epoch->displine; + } + + // epoch_log("%03i %06X %06X\n", epoch->displine, epoch->memaddr,epoch->vram_display_mask); + epoch->displine++; + if ((epoch->cgastat & 8) && ((epoch->displine & 0xf) == (epoch->vblankstart & 0xf)) && epoch->vslines) { + // epoch_log("Vsync off at line %i\n",displine); + epoch->cgastat &= ~8; + } + epoch->vslines++; + if (epoch->displine > 2000) + epoch->displine = 0; + } else { + // epoch_log("VC %i memaddr %05X\n", epoch->vc, epoch->memaddr); + timer_advance_u64(&epoch->timer, epoch->dispontime); + + if (epoch->dispon) + epoch->cgastat &= ~1; + epoch->hdisp_on = 0; + + epoch->linepos = 0; + if (epoch->scanline == (epoch->crtc[LC_CURSOR_ROW_END] & 0x1f)) + epoch->cursorvisible = 0; + if (epoch->dispon) { + if (epoch->scanline == epoch->rowcount) { + epoch->linecountff = 0; + epoch->scanline = 0; + + epoch->memaddr_backup += (epoch->rowoffset << 1); /* interlace */ + epoch->memaddr_backup &= epoch->vram_display_mask; + epoch->memaddr = epoch->memaddr_backup; + } else { + epoch->linecountff = 0; + epoch->scanline++; + epoch->scanline &= 0x1f; + epoch->memaddr = epoch->memaddr_backup; + } + } + + epoch->vc++; + epoch->vc &= 0x7ff; + + if (epoch->vc == epoch->dispend) { + epoch->dispon = 0; + if (!(epoch->crtmode & 0x02)) { /* in text mode */ + // if (epoch->attrc[LV_CURSOR_CONTROL] & 0x01) /* cursor blinking */ + // { + // epoch->cursoron = (epoch->blink | 1) & epoch->blinkconf; + epoch->cursoron = 1; + // } else { + // epoch->cursoron = 0; + // } + if (!(epoch->blink & (0x10 - 1))) /* force redrawing for cursor and blink attribute */ + epoch->fullchange = changeframecount; + } + epoch->blink++; + + // for (x = 0; x <= (EPOCH_MASK_VRAMPLANE >> 9); x++) { + // if (epoch->changedvram[x]) + // epoch->changedvram[x]--; + // } + // memset(changedvram,0,2048); del + if (epoch->fullchange) { + epoch->fullchange--; + } + } + if (epoch->vc == epoch->vsyncstart) { + int wx, wy; + // epoch_log("VC vsync %i %i\n", epoch->firstline_draw, epoch->lastline_draw); + epoch->dispon = 0; + epoch->cgastat |= 8; + x = epoch->hdisp; + + if (!epoch->oddeven) + epoch->lastline++; + if (epoch->oddeven) + epoch->firstline--; + + wx = x; + wy = epoch->lastline - epoch->firstline; + + epoch_doblit(wx, wy, epoch); + + epoch->firstline = 2000; + epoch->lastline = 0; + + epoch->firstline_draw = 2000; + epoch->lastline_draw = 0; + + epoch->oddeven ^= 1; + + epoch->vslines = 0; + + epoch->memaddr + = epoch->memaddr_backup = epoch->memaddr_latch << 1; + epoch->cursoraddr = ((epoch->crtc[LC_CURSOR_LOC_HIGH] << 8) | epoch->crtc[LC_CURSOR_LOC_LOWJ]) + epoch->ca_adj; + epoch->cursoraddr <<= 1; + + // epoch_log("Addr %08X vson %03X vsoff %01X\n",epoch->memaddr,epoch->vsyncstart,epoch->crtc[0x11]&0xF); + } + if (epoch->vc == epoch->vtotal) { + // epoch_log("VC vtotal\n"); + // printf("Frame over at line %i %i %i %i\n",displine,vc,epoch_vsyncstart,epoch_dispend); + epoch->vc = 0; + epoch->scanline = 0; + epoch->dispon = 1; + epoch->displine = 0; + // epoch->scrollcache = epoch->attrc[LV_PANNING] & 0x07; + epoch->scrollcache = 0; + } + if (epoch->scanline == (epoch->crtc[LC_CURSOR_ROW_START] & 31)) + epoch->cursorvisible = 1; + } +} + +static void +epoch_vram_write(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~0xfff) != 0xE0000) return; + addr -= 0xA0000; + addr &= EPOCH_MASK_VRAM; + epoch->vram[addr] = val; + epoch->fullchange = changeframecount; + // if(val == 0x66) + // epoch_log("66 %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI,ES,DI); +} +static void +epoch_vram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("epoch_vram_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + epoch_vram_write(addr, val, epoch); +} +static void +epoch_vram_writew(uint32_t addr, uint16_t val, void *priv) +{ + // epoch_log("epoch_vram_writ ew: Write to %x, val %x\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_write_w; + epoch_vram_write(addr, val & 0xff, epoch); + epoch_vram_write(addr + 1, val >> 8, epoch); +} + +static uint8_t +epoch_vram_read(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~epoch_MASK_CRAM) != 0xE0000) + // return epoch_INVALIDACCESS8; + addr -= 0xA0000; + addr &= EPOCH_MASK_VRAM; + return epoch->vram[addr]; +} +static uint8_t +epoch_vram_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_b; + return epoch_vram_read(addr, epoch); +} + +static uint16_t +epoch_vram_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_w; + return epoch_vram_read(addr, epoch) | (epoch_vram_read(addr + 1, epoch) << 8); +} + + +static void +epoch_cram_write(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~0xfff) != 0xE0000) return; + addr &= EPOCH_MASK_CRAM; + epoch->cram[addr] = val; + epoch->fullchange = changeframecount;; + // epoch_log("cw %04X:%04X %04X %02X\n", cs >> 4, cpu_state.pc, addr, val); +} +static void +epoch_cram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("epoch_cram_writeb: Write to %x, val %x\n", addr, val); + cycles -= video_timing_write_b; + epoch_cram_write(addr, val, epoch); +} +static void +epoch_cram_writew(uint32_t addr, uint16_t val, void *priv) +{ + // epoch_log("epoch_cram_writ ew: Write to %x, val %x\n", addr, val); + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_write_w; + epoch_cram_write(addr, val & 0xff, epoch); + epoch_cram_write(addr + 1, val >> 8, epoch); +} + +static uint8_t +epoch_cram_read(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // if ((addr & ~epoch_MASK_CRAM) != 0xE0000) + // return epoch_INVALIDACCESS8; + addr &= EPOCH_MASK_CRAM; + return epoch->cram[addr]; +} +static uint8_t +epoch_cram_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_b; + return epoch_cram_read(addr, epoch); +} + +static uint16_t +epoch_cram_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + cycles -= video_timing_read_w; + return epoch_cram_read(addr, epoch) | (epoch_cram_read(addr + 1, epoch) << 8); +} + +static uint8_t +epoch_parity_readb(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if ((epoch->parityerror != 0) && (epoch->parityenabled != 0)) { + epoch->parityerroraddr = (addr >> 16) & 0xFF; /* X000:0 */ + epoch_log("%04X:%04X perror at %0X\n", cs >> 4, cpu_state.pc, addr); + if (nmi_mask) + nmi_raise(); + } + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mrerror at %0X\n", cs >> 4, cpu_state.pc, addr); + return EPOCH_INVALIDACCESS8; + } + } + // return EPOCH_INVALIDACCESS8; + return mem_read_ram(addr, priv); +} + +static uint16_t +epoch_parity_readw(uint32_t addr, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if ((epoch->parityerror != 0) && (epoch->parityenabled != 0)) { + epoch->parityerroraddr = (addr >> 16) & 0xFF; + epoch_log("%04X:%04X perror at %X\n", cs >> 4, cpu_state.pc, addr); + if (nmi_mask) + nmi_raise(); + } + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mrerror at %X\n", cs >> 4, cpu_state.pc, addr); + return EPOCH_INVALIDACCESS16; + } + } + return mem_read_ramw(addr, priv); +} + +static void +epoch_parity_writeb(uint32_t addr, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + // epoch_log("%04X:%04X mw %0X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled == 0) + epoch->parityerror = 1; + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mwerror at %X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled) + epoch->parityerror = 1; + return; + } + } + // if (val == 0xcb) + // epoch_log("CB %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI, ES, DI); + mem_write_ram(addr, val, priv); +} +static void +epoch_parity_writew(uint32_t addr, uint16_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + if (epoch->parityenabled == 0) + epoch->parityerror = 1; + if (epoch->lowmemorydisabled) { + if ((addr >= 0x40000) && (addr < 0xA0000)) { + epoch_log("%04X:%04X mwerror at %X\n", cs >> 4, cpu_state.pc, addr); + if (epoch->parityenabled) + epoch->parityerror = 1; + return; + } + } + mem_write_ramw(addr, val, priv); +} + +static uint8_t +epoch_misc_in(uint16_t port, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + uint8_t ret = 0xff; + + switch (port) { +/* +I/O A0h R: +xxxx xxx1: Memory or parity error? +0xxx xxxx: Coprocessor installed? +*/ + case 0xA0: + if(!epoch->parityenabled) + ret &= 0xfe; + else + ret = epoch->parityerror & 1; + if (fpu_type == FPU_NONE) + ret |= 0x80; + break; + case 0xA1: /* High address where memory error occured */ + ret = epoch->parityerroraddr; + break; +/* +I/O A2h R: +xxxx 0x0x: Color CRT +xxxx 1x0x: Mono 24 CRT ? +xxxx xx1x: 16 pixel CRT +xx1x xxxx: No hard drive +x1xx xxxx: No floppy drive +1xxx xxxx: No (bootable?) hard drive +*/ + case 0xA2: + ret = 0xA8;/* Mono 24 */ + // ret = 0xA8;/* Mono 16 */ + break; +/* +I/O A3h R: +xxxx x001: Main RAM 256 KB? +xxxx x011: Main RAM 384 KB? +xxxx x111: Main RAM 512 KB? +xxxx x000: Main RAM 640 KB? +xxxx 1xxx: Serial port 3f8h +xxx1 xxxx: Serial port 2f8h +*/ + case 0xA3: + ret = 0x08; + if (mem_size < 384) + ret |= 0x07; + else if (mem_size < 512) + ret |= 0x06; + else if (mem_size < 640) + ret |= 0x04; + break; + case 0xA4: + ret = 0; + break; + case 0xA5: + ret = 0x08; /* Bit 3: Keyboard connected? */ + break; + // case 0x164: + // switch (epoch->fontcard.portdata) { + // case 0x16A: + // ret = 0xFD; + // break; + // case 0x168: + // ret = 0xFE; + // break; + // } + // break; + default: + break; + } + epoch_log("%04X:%04X I/O In %02X: %02X\n", cs >> 4, cpu_state.pc, port, ret); + return ret; +} + +static void +epoch_misc_out(uint16_t port, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + + // dev->regs[port & 0x0007] = val; + // epoch_log("%04X:%04X I/O Out %02X: %02X\n AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X\n", + // cs >> 4, cpu_state.pc, port, val, AX, BX, CX, DX, ES, DI, DS, SI); + if(port != 0x44) + epoch_log("%04X:%04X I/O Out %02X: %02X\n", cs >> 4, cpu_state.pc, port, val); + + switch (port) { + case 0x44: + pit_intf_t *pit_intf = &pit_devs[0]; + for (uint8_t i = 0; i < 3; i++) { + pit_intf->set_gate(pit_intf->data, i, val & 1); + } + break; +/* +I/O A0h W: +x1xx xxxx: Enable parity update (Disable this -> Write data -> Enable this -> Read data, causes NMI) +1xxx xxxx: Enable NMI check +*/ + case 0xA0: + nmi_mask = val & 0x80; + epoch->parityenabled = val & 0x40; /* 1 = Enable read/write with parity */ + break; + case 0xA1: + /* Diagnostics LED (used by debug card module) */ + break; + case 0xA2: + /* Reset memory error bit */ + epoch->parityerror = 0; + break; + // case 0x160 ... 0x16A: + // mem_mapping_enable(&epoch->fontcard.map); + // epoch->fontcard.portdata = port; + // break; + case 0x310 ... 0x312: + epoch->lowmemorydisabled = 0; + epoch_log("Low memory enabled\n"); + break; + case 0x314 ... 0x316: + epoch->lowmemorydisabled = 1; + epoch_log("Low memory disabled\n"); + break; + } +} +typedef struct epochkbd_t { + int want_irq; + int blocked; + + uint8_t pa; + uint8_t pb; + uint8_t clock; + uint8_t key_waiting; + uint8_t reset_step; + + pc_timer_t send_delay_timer; +} epochkbd_t; + +static uint8_t key_queue[16]; +static int key_queue_start = 0; +static int key_queue_end = 0; + +static void +kbd_poll(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); + + if (kbd->pb & 0x04) + return; + + if (kbd->want_irq) { + kbd->want_irq = 0; + kbd->pa = kbd->key_waiting; + kbd->pb &= 0xF7; + kbd->blocked = 1; + picint(EPOCH_IRQ3_BIT); + epoch_log("epochkbd: kbd_poll(): keyboard_xt : take IRQ\n"); + } + + if ((key_queue_start != key_queue_end) && !kbd->blocked) { + kbd->key_waiting = key_queue[key_queue_start]; + epoch_log("epochkbd: reading %02X from the key queue at %i\n", + kbd->key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0x0f; + kbd->want_irq = 1; + } +} + +void +kbd_adddata_xt_common(uint16_t val) +{ + key_queue[key_queue_end] = val; + epoch_log("epochkbd: %02X added to key queue at %i\n", + val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0x0f; +} + +void +kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) +{ + uint8_t num_lock = 0; + uint8_t shift_states = 0; + + if (!adddata) + return; + + keyboard_get_states(NULL, &num_lock, NULL, NULL); + shift_states = keyboard_get_shift() & STATE_LSHIFT; + + /* If NumLock is on, invert the left shift state so we can always check for + the the same way flag being set (and with NumLock on that then means it + is actually *NOT* set). */ + if (num_lock) + shift_states ^= STATE_LSHIFT; + + switch (val) { + default: + adddata(val); + break; + } +} + +void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + epoch_log("XTkbd: %02X added to key queue at %i\n", + val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0x0f; +} + +static void +kbd_adddata_ex(uint16_t val) +{ + if (val < 0x100) + kbd_adddata_process(val, kbd_adddata); +} + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + uint8_t bit; + uint8_t set; + uint8_t new_clock; + epoch_log("%04X:%04X epochkbd: Port %04X out: %02X\n", cs >> 4, cpu_state.pc, port, val); + + switch (port) { + case 0x61: /* Keyboard Control Register (aka Port B) */ + if (val & 0x08) { + new_clock = !(val & 0x04); + if (kbd->clock && new_clock) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd->reset_step = 0; + /* Specific 5556 keyboards send three bytes of identification code, + but this simply sends AAh that can pass the IPL and DOS K3.4 init. */ + kbd_adddata(0xaa); + } else if (!(kbd->pb & 0x08)) { + kbd->pa = 0; + kbd->blocked = 0; + } + } + + kbd->pb = val; + if (kbd->pb & 0x08) + kbd->clock = !!(kbd->pb & 0x04); + ppi.pb = val; + + timer_process(); + + speaker_update(); + + speaker_gated = val & 2; + speaker_enable = val & 2; + + if (speaker_enable) + was_speaker_enable = 1; + pit_devs[0].set_gate(pit_devs[0].data, TIMER_CTR_2, val & 2); + + break; + + default: + break; + } +} + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: /* Keyboard Data Register (aka Port A) */ + ret = kbd->pa; + break; + + case 0x61: /* Keyboard Control Register (aka Port B) */ + /* Bit 3 and 2: Keyboard Data and Clk line ? */ + if (kbd->reset_step < 18) { + ret &= 0xf3; + if (kbd->reset_step & 1) + ret |= 0x04; + switch (kbd->reset_step) { /* AAh (1010 1010) in serial data */ + case 3: + case 7: + case 11: + case 15: + ret |= 0x00; + break; + default: + ret |= 0x08; + break; + } + kbd->reset_step += 1; + } + /* Bit 1: Timer 2 (Speaker) out state */ + if (pit_devs[0].get_outlevel(pit_devs[0].data, TIMER_CTR_2) && speaker_enable) + ret &= 0xfd;/* 1111 1101 */ + else + ret |= 0x02; + break; + + default: + break; + } + // epoch_log("%04X:%04X epochkbd: Port %04X in : %02X BX:%04x\n", cs >> 4, cpu_state.pc, port, ret, BX); + + return ret; +} + +static void +kbd_reset(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + kbd->want_irq = 0; + kbd->blocked = 0; + kbd->pa = 0x00; + kbd->pb = 0x00; + + keyboard_scan = 1; + + key_queue_start = 0; + key_queue_end = 0; +} + +static void * +kbd_init(const device_t *info) +{ + epochkbd_t *kbd; + + kbd = (epochkbd_t *) calloc(1, sizeof(epochkbd_t)); + + io_sethandler(0x0060, 4, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_ex; + kbd_reset(kbd); + + key_queue_start = key_queue_end = 0; + + timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1); + + keyboard_set_table(scancode_set8a); + keyboard_mode = 0x8a; + + return kbd; +} + +static void +kbd_close(void *priv) +{ + epochkbd_t *kbd = (epochkbd_t *) priv; + + /* Stop the timer. */ + timer_disable(&kbd->send_delay_timer); + + /* Disable scanning. */ + keyboard_scan = 0; + + keyboard_send = NULL; + + io_removehandler(0x0060, 2, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + + free(kbd); +} + +const device_t kbc_epoch_device = { + .name = "IBM 5550 Keyboard Controller", + .internal_name = "kbc_epoch", + .flags = 0, + .local = 0, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +static void +epoch_nvr_time_set(uint8_t *regs, struct tm *tm) +{ + regs[epoch_nvr_SECOND1] = tm->tm_sec % 10; + regs[epoch_nvr_SECOND10] = (tm->tm_sec / 10); + regs[epoch_nvr_MINUTE1] = (tm->tm_min % 10); + regs[epoch_nvr_MINUTE10] = (tm->tm_min / 10); + regs[epoch_nvr_HOUR1] = (tm->tm_hour % 10); + regs[epoch_nvr_HOUR10] = (tm->tm_hour / 10); + regs[epoch_nvr_WEEKDAY] = tm->tm_wday; + regs[epoch_nvr_DAY1] = (tm->tm_mday % 10); + regs[epoch_nvr_DAY10] = (tm->tm_mday / 10); + regs[epoch_nvr_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[epoch_nvr_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[epoch_nvr_YEAR1] = (tm->tm_year % 10); + regs[epoch_nvr_YEAR10] = ((tm->tm_year % 100) / 10); +} + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +epoch_nvr_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(epoch_nvr_SECOND); + tm->tm_min = nibbles(epoch_nvr_MINUTE); + tm->tm_hour = nibbles(epoch_nvr_HOUR); + tm->tm_wday = regs[epoch_nvr_WEEKDAY]; + tm->tm_mday = nibbles(epoch_nvr_DAY); + tm->tm_mon = (nibbles(epoch_nvr_MONTH) - 1); + tm->tm_year = (nibbles(epoch_nvr_YEAR)); +} + +/* This is called every second through the NVR/RTC hook. */ +static void +epoch_nvr_tick(nvr_t *nvr) +{ + struct tm tm; + if (!(nvr->regs[epoch_nvr_CONTROL] & 0x40)) { + /* Get the current time from the internal clock. */ + nvr_time_get(&tm); + /* Update registers with current time. */ + epoch_nvr_time_set(nvr->regs, &tm); + } +} + +static void +epoch_nvr_start(nvr_t *nvr) +{ + struct tm tm; + /* Initialize the internal and chip times. */ + if (time_sync & TIME_SYNC_ENABLED) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + epoch_nvr_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + epoch_nvr_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } +} + +/* Write to one of the chip registers. */ +static void +epoch_nvr_write(uint16_t port, uint8_t val, void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + int addr = 0; + + switch (port) { + case 0x360: + epoch->nvrctrl = val; + addr = val & 0xf; + if (val & 0x20) { /* Write */ + if (addr >= 0x8 && (epoch->nvr.regs[addr] != val)) + nvr_dosave = 1; + epoch->nvr.regs[addr] = epoch->nvrdata; + } + break; + case 0x361: + if(epoch->nvrctrl & 0x40) /* Is the access enabled? */ + epoch->nvrdata = val; + break; + } + // epoch_log("%04X:%04X I/O Out %02X: %02X\n", cs >> 4, cpu_state.pc, port, val); +} + +/* Read from one of the chip registers. */ +static uint8_t +epoch_nvr_read(uint16_t port, void *priv) +{ + const epoch_t *epoch = (epoch_t *) priv; + + switch (port) { + case 0x360: + return epoch->nvrctrl; + break; + case 0x361: + if(epoch->nvrctrl & 0x40) /* Is the access enabled? */ + return (epoch->nvr.regs[(epoch->nvrctrl & 0xf)]); + break; + } + return EPOCH_INVALIDACCESS8; +} + +/* Reset the RTC registers to a default state. */ +static void +epoch_nvr_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 0xc); + nvr->regs[epoch_nvr_CONTROL] = 0; +} + +static void +epoch_nvr_init(epoch_t *epoch, int size) +{ + nvr_t* nvr = &epoch->nvr; + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + /* Set up any local handlers here. */ + nvr->reset = epoch_nvr_reset; + nvr->start = epoch_nvr_start; + nvr->tick = epoch_nvr_tick; + /* Initialize the actual NVR. */ + nvr_init(nvr); + io_sethandler(0x0360, 2, + epoch_nvr_read, NULL, NULL, epoch_nvr_write, NULL, NULL, epoch); +} + +static uint8_t ibm5550_attr_mono[16] = +{ + 0,6,6,62,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +// static uint8_t ps55_attr_color[16] = /* for video mode 0eh color character */ +// { +// 0x00,0x38,0x24,0x3c,0x12,0x3a,0x36,0x3e,0x09,0x39,0x2d,0x3d,0x1b,0x3b,0x3f,0x3f +// }; + +/* 12-bit DAC color palette for IBMJ Display Adapter with color monitor */ +static uint8_t ps55_palette_color[64][3] = { + { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x2A }, { 0x00, 0x2A, 0x00 }, { 0x00, 0x2A, 0x2A }, + { 0x2A, 0x00, 0x00 }, { 0x2A, 0x00, 0x2A }, { 0x2A, 0x2A, 0x00 }, { 0x2A, 0x2A, 0x2A }, + { 0x00, 0x00, 0x15 }, { 0x00, 0x00, 0x3F }, { 0x00, 0x2A, 0x15 }, { 0x00, 0x2A, 0x3F }, + { 0x2A, 0x00, 0x15 }, { 0x2A, 0x00, 0x3F }, { 0x2A, 0x2A, 0x15 }, { 0x2A, 0x2A, 0x3F }, + { 0x00, 0x15, 0x00 }, { 0x00, 0x15, 0x2A }, { 0x00, 0x3F, 0x00 }, { 0x00, 0x3F, 0x2A }, + { 0x2A, 0x15, 0x00 }, { 0x2A, 0x15, 0x2A }, { 0x2A, 0x3F, 0x00 }, { 0x2A, 0x3F, 0x2A }, + { 0x00, 0x15, 0x15 }, { 0x00, 0x15, 0x3F }, { 0x00, 0x3F, 0x15 }, { 0x00, 0x3F, 0x3F }, + { 0x2A, 0x15, 0x15 }, { 0x2A, 0x15, 0x3F }, { 0x2A, 0x3F, 0x15 }, { 0x2A, 0x3F, 0x3F }, + { 0x15, 0x00, 0x00 }, { 0x15, 0x00, 0x2A }, { 0x15, 0x2A, 0x00 }, { 0x15, 0x2A, 0x2A }, + { 0x3F, 0x00, 0x00 }, { 0x3F, 0x00, 0x2A }, { 0x3F, 0x2A, 0x00 }, { 0x3F, 0x2A, 0x2A }, + { 0x15, 0x00, 0x15 }, { 0x15, 0x00, 0x3F }, { 0x15, 0x2A, 0x15 }, { 0x15, 0x2A, 0x3F }, + { 0x3F, 0x00, 0x15 }, { 0x3F, 0x00, 0x3F }, { 0x3F, 0x2A, 0x15 }, { 0x3F, 0x2A, 0x3F }, + { 0x15, 0x15, 0x00 }, { 0x15, 0x15, 0x2A }, { 0x15, 0x3F, 0x00 }, { 0x15, 0x3F, 0x2A }, + { 0x3F, 0x15, 0x00 }, { 0x3F, 0x15, 0x2A }, { 0x3F, 0x3F, 0x00 }, { 0x3F, 0x3F, 0x2A }, + { 0x15, 0x15, 0x15 }, { 0x15, 0x15, 0x3F }, { 0x15, 0x3F, 0x15 }, { 0x15, 0x3F, 0x3F }, + { 0x3F, 0x15, 0x15 }, { 0x3F, 0x15, 0x3F }, { 0x3F, 0x3F, 0x15 }, { 0x3F, 0x3F, 0x3F } +}; + +static video_timings_t timing_epoch_vid = +{ .type = VIDEO_ISA, .write_b = 8, .write_w = 8, .write_l = 16, .read_b = 8, .read_w = 8, .read_l = 16 }; + +static void +epoch_reset(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + + epoch->parityerror = 0; + epoch->parityenabled = 1; + epoch->lowmemorydisabled = 1; + epoch->crtioenabled = 0; + // epoch->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ + epoch->crtc[LC_HORIZONTAL_TOTAL] = 103; /* Horizontal Total */ + epoch->crtc[LC_VERTICAL_TOTAL] = 26; /* Vertical Total (These two must be set before the timer starts.) */ + epoch->crtmode = 0x08; + epoch->vram_display_mask = EPOCH_MASK_CRAM; + // epoch->plane_mask = 1; + epoch->oddeven = 0; + // epoch->memaddr_latch = 0; + // epoch->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ + // epoch->attr_palette_enable = 0; /* disable attribute generator */ + + // epoch->attrc[LV_PAS_STATUS_CNTRL] = 0; + // epoch->attrc[LV_PANNING] = 0; + + /* Set internal color palette registers */ + for (uint16_t i = 0; i < 16; i++) { + epoch->egapal[i] = ibm5550_attr_mono[i]; + } + /* Set color palette for video output */ + for (uint16_t i = 0; i < 64; i++) { + epoch->vgapal[i].r = ps55_palette_color[i & 0x3F][0]; + epoch->vgapal[i].g = ps55_palette_color[i & 0x3F][1]; + epoch->vgapal[i].b = ps55_palette_color[i & 0x3F][2]; + epoch->pallook[i] = makecol32((epoch->vgapal[i].r & 0x3f) * 4, (epoch->vgapal[i].g & 0x3f) * 4, (epoch->vgapal[i].b & 0x3f) * 4); + } + + // mem_mapping_disable(&epoch->fontcard.map); + + epoch_log("epoch_reset done.\n"); +} + +/* +//[Font ROM Map (DA1)] +//Bank 0 +// 0000-581Fh Pointers (Low) for each character font? +// 5820-7FFFh Pointers (High) for each character font? +// 8000- * h Font Data +*/ +// static void +// epoch_video_load_font(char *fname, epoch_t *epoch) +// { +// uint8_t buf; +// uint64_t fsize; +// if (!fname) +// return; +// if (*fname == '\0') +// return; +// FILE *mfile = rom_fopen(fname, "rb"); +// if (!mfile) { +// // da2_log("MSG: Can't open binary ROM font file: %s\n", fname); +// return; +// } +// fseek(mfile, 0, SEEK_END); +// fsize = ftell(mfile); /* get filesize */ +// fseek(mfile, 0, SEEK_SET); +// if (fsize > EPOCH_FONTROM_SIZE) { +// fsize = EPOCH_FONTROM_SIZE; /* truncate read data */ +// // da2_log("MSG: The binary ROM font is truncated: %s\n", fname); +// // fclose(mfile); +// // return 1; +// } +// uint32_t j = 0; +// while (ftell(mfile) < fsize) { +// (void) !fread(&buf, sizeof(uint8_t), 1, mfile); +// epoch->fontcard.rom[j] = buf; +// j++; +// } +// fclose(mfile); +// return; +// } + +// static void +// epoch_font_writeb(uint32_t addr, uint8_t val, void *priv) +// { +// epoch_t *epoch = (epoch_t *) priv; +// epoch->fontcard.bank = val; +// // if ((addr & ~0xfff) != 0xE0000) return; +// epoch_log("cw %04X %02X %04X %04X %04X %04X\n", addr, val, DS, SI, ES, DI); +// } +// static uint8_t +// epoch_font_readb(uint32_t addr, void *priv) +// { +// epoch_t *epoch = (epoch_t *) priv; +// uint32_t readaddr = epoch->fontcard.bank; +// addr &= EPOCH_FONTROM_MASK; +// readaddr *= 0xc000;/* xxx x000 0000 0000 0000 (8000h) */ +// readaddr += addr; +// if (readaddr >= EPOCH_FONTROM_SIZE) +// return EPOCH_INVALIDACCESS8; +// // epoch_log("cr %X %x %04X %04X %04X %04X\n", readaddr, epoch->fontcard.rom[readaddr], DS, SI, ES, DI); +// // if(epoch->vram[addr] == 0xcb) +// // epoch_log("CB %04X:%04X %04X:%04X>%04X:%04X\n", cs >> 4, cpu_state.pc, DS, SI,ES,DI); +// return epoch->fontcard.rom[readaddr]; +// } +static void * +epoch_init(UNUSED(const device_t *info)) +{ + epoch_t *epoch = calloc(1, sizeof(epoch_t)); + video_inform(VIDEO_FLAG_TYPE_NONE, &timing_epoch_vid); + video_update_timing(); + + epoch->dispontime = 1000ull << 32; + epoch->dispofftime = 1000ull << 32; + // epoch->changedvram = calloc(1, (EPOCH_MASK_VRAMPLANE + 1) >> 9); /* XX000h */ + changeframecount = 3; + + epoch->vram = calloc(1, 256* 1024); + epoch->cram = calloc(1, 4 * 1024); + // epoch->fontcard.rom = calloc(1, EPOCH_FONTROM_SIZE); + //epoch_video_load_font("roms/machines/ibm5550/GEN1FONT.BIN", epoch); + + epoch->epochconst = (uint64_t) ((cpuclock / EPOCH_PIXELCLOCK) * (double) (1ull << 32)); + + epoch_reset(epoch); + + mem_mapping_add(&epoch->cmap, 0xE0000, 0x1000, epoch_cram_readb, epoch_cram_readw, NULL, + epoch_cram_writeb, epoch_cram_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + mem_mapping_add(&epoch->vmap, 0xA0000, 0x40000, epoch_vram_readb, epoch_vram_readw, NULL, + epoch_vram_writeb, epoch_vram_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + // mem_mapping_add(&epoch->fontcard.map, 0xF0000, 0xC000, epoch_font_readb, NULL, NULL, + // epoch_font_writeb, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, epoch); + + mem_mapping_disable(&epoch->cmap); + mem_mapping_disable(&epoch->vmap); + // mem_mapping_disable(&epoch->fontcard.map); + mem_mapping_add(&epoch->paritymap, 0, 0xA0000, epoch_parity_readb, epoch_parity_readw, NULL, + epoch_parity_writeb, epoch_parity_writew, NULL, NULL, MEM_MAPPING_CACHE, epoch); + + io_sethandler(0x03d0, 0x0020, epoch_inb, epoch_inw, NULL, epoch_outb, epoch_outw, NULL, epoch); + + io_sethandler(0x44, 0x0001, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + io_sethandler(0xA0, 0x0005, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + io_sethandler(0x310, 0x0008, + epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + // io_sethandler(0x160, 0x0010, + // epoch_misc_in, NULL, NULL, epoch_misc_out, NULL, NULL, epoch); + + timer_add(&epoch->timer, epoch_poll, epoch, 1); + + epoch_nvr_init(epoch, 17); + + return epoch; +} + +static void +epoch_close(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + + /* dump mem for debug */ +#ifdef ENABLE_EPOCH_LOG + FILE *fp; + fp = fopen("epoch_cram.dmp", "wb"); + if (fp != NULL) { + fwrite(epoch->cram, EPOCH_SIZE_CRAM, 1, fp); + fclose(fp); + } + fp = fopen("epoch_vram.dmp", "wb"); + if (fp != NULL) { + fwrite(epoch->vram, EPOCH_SIZE_VRAM, 1, fp); + fclose(fp); + } + // fp = fopen("epoch_attrpal.dmp", "wb"); + // if (fp != NULL) { + // fwrite(epoch->attrc, 32, 1, fp); + // fclose(fp); + // } + fp = fopen("epoch_daregs.txt", "w"); + if (fp != NULL) { + // for (uint8_t i = 0; i < 0x10; i++) + // fprintf(fp, "3e1(ioctl) %02X: %4X %d\n", i, epoch->ioctl[i], epoch->ioctl[i]); + // for (uint8_t i = 0; i < 0x20; i++) + // fprintf(fp, "3e3(fctl) %02X: %4X %d\n", i, epoch->fctl[i], epoch->fctl[i]); + for (uint8_t i = 0; i < 0x20; i++) + fprintf(fp, "3e5(crtc) %02X: %4X %d\n", i, epoch->crtc[i], epoch->crtc[i]); + // for (uint8_t i = 0; i < 0x40; i++) + // fprintf(fp, "3e8(attr) %02X: %4X %d\n", i, epoch->attrc[i], epoch->attrc[i]); + // for (uint8_t i = 0; i < 0x10; i++) + // fprintf(fp, "3eb(gcr) %02X: %4X\n", i, epoch->gdcreg[i]); + // for (uint8_t i = 0; i < 0x20; i++) { + // fprintf(fp, "vp %02X: %4X %4X %4X %4X\n", i, + // epoch->crtc_vpreg[0 + i], epoch->crtc_vpreg[0x20 + i], epoch->crtc_vpreg[0x40 + i], epoch->crtc_vpreg[0x60 + i]); + // } + fclose(fp); + } + fp = fopen("ram_low.dmp", "wb"); + if (fp != NULL) { + fwrite(ram, 0x40000, 1, fp); + fclose(fp); + } + epoch_log("closed %04X:%04X AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X\n", + cs >> 4, cpu_state.pc, AX, BX, CX, DX, ES, DI, DS, SI); + epoch_log("PIC IRR=%02X ISR=%02X IMR=%02X ICW1=%02X ICW2=%02X ICW3=%02X ICW4=%02X OCW2=%02X OCW3=%02X\n", + pic.irr, pic.isr, pic.imr, pic.icw1, pic.icw2, pic.icw3, pic.icw4, pic.ocw2, pic.ocw3); +#endif + free(epoch->cram); + free(epoch->vram); + // free(epoch->fontcard.rom); + // free(epoch->changedvram); + free(epoch); +} + +static void +epoch_speed_changed(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + epoch->epochconst = (uint64_t) ((cpuclock / EPOCH_PIXELCLOCK) * (double) (1ull << 32)); + epoch_recalctimings(epoch); +} + +static void +epoch_force_redraw(void *priv) +{ + epoch_t *epoch = (epoch_t *) priv; + epoch->fullchange = changeframecount; +} + +const device_t epoch_device = { + .name = "IBM 5550 Video Controller (Epoch)", + .internal_name = "ibm5550vid", + .flags = DEVICE_ISA, + .local = 0, + .init = epoch_init, + .close = epoch_close, + .reset = epoch_reset, + .available = NULL, + .speed_changed = epoch_speed_changed, + .force_redraw = epoch_force_redraw, + .config = NULL +}; + +void +pit_irq6_timer(int new_out, int old_out, UNUSED(void *priv)) +{ + // epoch_log("%04X:%04X IRQ6 Timer triggered.\n", cs >> 4, cpu_state.pc); + if (new_out && !old_out) + picint(EPOCH_IRQ6_BIT); + + if (!new_out) + picintc(EPOCH_IRQ6_BIT); +} + +pit_t * +pit_ibm5550_init() +{ + void *pit; + + pit_intf_t *pit_intf = &pit_devs[0]; + + pit = device_add(&i8253_device); + *pit_intf = pit_classic_intf; + + pit_intf->data = pit; + + for (uint8_t i = 0; i < 3; i++) { + pit_intf->set_gate(pit_intf->data, i, 1); + pit_intf->set_using_timer(pit_intf->data, i, 1); + } + + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_1, pit_irq6_timer); + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_0, pit_refresh_timer_xt); + pit_intf->set_out_func(pit_intf->data, TIMER_CTR_2, pit_speaker_timer); + pit_intf->set_load_func(pit_intf->data, TIMER_CTR_2, speaker_set_count); + + pit_intf->set_gate(pit_intf->data, TIMER_CTR_2, 0); + + return pit; +} + +int +machine_xt_ibm5550_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/ibm5550/ipl5550.rom", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + device_add(&fdc_xt_5550_device); + + device_add(&kbc_epoch_device); + + pic_init(); + dma_init(); + pit_ibm5550_init(); + nmi_mask = 0; + + epoch_t *epoch = device_add(&epoch_device); + + device_add(&lpt_port_device); + serial_t *uart = device_add(&ns8250_device); + serial_setup(uart, 0x3f8, 1);/* Use IRQ 1 */ + + return ret; +} diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9b7211d8c..5f3b82ba6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -3033,6 +3033,49 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[8086] IBM Multistation 5550", + .internal_name = "ibm5550", + .type = MACHINE_TYPE_8086, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_ibm5550_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_8086, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_VIDEO_FIXED | MACHINE_KEYBOARD, + .ram = { + .min = 256, + .max = 640, + .step = 128 + }, + .nvrmask = 15, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 286 AT machines */ /* Has IBM AT KBC firmware. */ diff --git a/src/pit.c b/src/pit.c index 7c58a4b67..5a8078c97 100644 --- a/src/pit.c +++ b/src/pit.c @@ -420,6 +420,15 @@ pit_ctr_get_count(void *data, int counter_id) return (uint16_t) ctr->l; } +int +pit_ctr_get_outlevel(void *data, int counter_id) +{ + const pit_t *pit = (pit_t *) data; + const ctr_t *ctr = &pit->counters[counter_id]; + + return (int) ctr->out; +} + void pit_ctr_set_load_func(void *data, int counter_id, void (*func)(uint8_t new_m, int new_count)) { @@ -1208,6 +1217,11 @@ pit_set_clock(uint32_t clock) CGACONST = (uint64_t) ((cpuclock / (157500000.0 / 88.0)) * (double) (1ULL << 32)); #endif } + + if (machines[machine].init == machine_xt_ibm5550_init) { + PITCONSTD = (cpuclock / 2000000.0); /* CLK input 2.0 MHz */ + PITCONST = (uint64_t) (PITCONSTD * (double) (1ULL << 32)); + } ISACONST = (1ULL << 32ULL); } @@ -1263,6 +1277,7 @@ const pit_intf_t pit_classic_intf = { .read = &pit_read, .write = &pit_write, .get_count = &pit_ctr_get_count, + .get_outlevel = &pit_ctr_get_outlevel, .set_gate = &pit_ctr_set_gate, .set_using_timer = &pit_ctr_set_using_timer, .set_out_func = &pit_ctr_set_out_func, From 857fca5236ab425b3abb9f565afeeeb0fe563a71 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 9 Feb 2026 01:45:41 +0900 Subject: [PATCH 41/49] remove debug code from 808x.c --- src/cpu/808x.c | 102 +------------------------------------------------ 1 file changed, 1 insertion(+), 101 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index cf091874e..4e2e830d0 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -43,7 +43,7 @@ /* Is the CPU 8088 or 8086. */ int is8086 = 0; -int calllevel = 0; + uint8_t use_custom_nmi_vector = 0; uint32_t custom_nmi_vector = 0x00000000; @@ -1959,106 +1959,6 @@ execx86(int cycs) } completed = 1; - // switch (opcode) { - // case 0x9A: - // case 0xE8: - // pclog("[%04X:%04X] %d CALL\n", CS, cpu_state.pc, calllevel); - // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", - // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); - // calllevel += 1; - // if (CS == 0xfcbf && cpu_state.pc == 0x83) { - // pclog("[bp+n]:"); - // for (int i = 0; i < 0x58; i++) - // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); - // pclog("\n"); - // } - // break; - // case 0xC3: - // case 0xCB: - // case 0xC2: - // case 0xCA: - // pclog("[%04X:%04X] %d RET\n", CS, cpu_state.pc, calllevel); - // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X FL=%04X\n", - // cs >> 4, cpu_state.pc, AX, BX, CX, DX, ES, DI, DS, SI, cpu_state.flags); - // calllevel -= 1; - // break; - // case 0xFB: - // pclog("[%04X:%04X] STI\n", CS, cpu_state.pc); - // break; - // case 0xFA: - // pclog("[%04X:%04X] CLI\n", CS, cpu_state.pc); - // break; - // } - // if ((CS == 0xFD6E) || (CS == 0xFcbf)) { - // if (DI == 0x48aa) - // pclog("[%04X:%04X] AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", - // CS, cpu_state.pc,AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); - // if ((CS == 0xFD6E) || (CS == 0xFcbf)) { - // switch (opcode) { - // case 0x3C: - // case 0x80: - // case 0x83: - // pclog("[%04X:%04X] CMP AX=%04X\n", CS, cpu_state.pc, AX); - // // if(CS == 0xFD6E && cpu_state.pc < 0x20) { - // // pclog("[bx+n]:"); - // // for(int i=0;i<0x12;i++) - // // pclog(" [%02X]%02X", i, read_mem_b((DS << 4) + BX + i)); - // // pclog("\n"); - // // } - // break; - // case 0xE2: - // pclog("[%04X:%04X] LOOP CX=%02X**\n", CS, cpu_state.pc, CX>>8); - // break; - // case 0xF6: - // pclog("[%04X:%04X] TEST AX=%04X\n", CS, cpu_state.pc, AX); - // break; - // case 0xEB: - // case 0xE9: - // case 0xEA: - // pclog("[%04X:%04X] JMP\n", CS, cpu_state.pc); - // break; - // case 0x77: - // pclog("[%04X:%04X] JA\n", CS, cpu_state.pc); - // break; - // case 0x73: - // pclog("[%04X:%04X] JAE\n", CS, cpu_state.pc); - // break; - // case 0x72: - // pclog("[%04X:%04X] JB\n", CS, cpu_state.pc); - // if (CS == 0xFD6E && cpu_state.pc < 0x28) { - // pclog("[bx+n]:"); - // for (int i = 0; i < 0x20; i++) - // pclog(" [%02X]%02X", i, read_mem_b((DS << 4) + BX + i)); - // pclog("\n"); - // } - // break; - // case 0x76: - // pclog("[%04X:%04X] JNA\n", CS, cpu_state.pc); - // break; - // case 0x74: - // pclog("[%04X:%04X] JE\n", CS, cpu_state.pc); - // if (CS == 0xfcbf && cpu_state.pc == 0x8A) { - // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", - // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); - // pclog("[bp+n]:"); - // for (int i = 0; i < 0x58; i++) - // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); - // pclog("\n"); - // } - // break; - // case 0x75: - // pclog("[%04X:%04X] JNE\n", CS, cpu_state.pc); - // if (CS == 0xFD6E && cpu_state.pc == 0x16E) { - // pclog(" AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X SS=%04X BP=%04X\n", - // AX, BX, CX, DX, ES, DI, DS, SI, SS, BP); - // pclog("[bp+n]:"); - // for (int i = 0; i < 0x58; i++) - // pclog(" [%02X]%02X", i, read_mem_b((SS << 4) + BP + i)); - // pclog("\n"); - // } - // break; - // } - // } // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); if (is186) { switch (opcode) { From 214015fc3e5dd49a4cedb025d405e5fc201e596c Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 9 Feb 2026 03:32:21 +0900 Subject: [PATCH 42/49] fix some errors and warnings --- src/machine/m_xt_ibm5550.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/machine/m_xt_ibm5550.c b/src/machine/m_xt_ibm5550.c index 9ea03f494..a78a35fca 100644 --- a/src/machine/m_xt_ibm5550.c +++ b/src/machine/m_xt_ibm5550.c @@ -303,7 +303,6 @@ static void epoch_out(uint16_t addr, uint16_t val, void *priv) { epoch_t *epoch = (epoch_t *) priv; - int oldval; epoch_iolog("%04X:%04X epoch Out addr %03X val %02X\n", cs >> 4, cpu_state.pc, addr, val); switch (addr) { case LC_INDEX: @@ -612,7 +611,6 @@ getfont_ps55dbcs(int32_t code, int32_t line, void *priv) { epoch_t *epoch = (epoch_t *) priv; uint32_t font = 0; - int32_t fline = line - 2; /* Start line of drawing character (line >= 1 AND line < 24 + 1 ) */ if (code < 1536) { code *= 0x80; font = epoch->vram[code + line * 4]; @@ -1512,8 +1510,6 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { epochkbd_t *kbd = (epochkbd_t *) priv; - uint8_t bit; - uint8_t set; uint8_t new_clock; epoch_log("%04X:%04X epochkbd: Port %04X out: %02X\n", cs >> 4, cpu_state.pc, port, val); @@ -2092,7 +2088,7 @@ pit_irq6_timer(int new_out, int old_out, UNUSED(void *priv)) picintc(EPOCH_IRQ6_BIT); } -pit_t * +static pit_t * pit_ibm5550_init() { void *pit; @@ -2139,7 +2135,7 @@ machine_xt_ibm5550_init(const machine_t *model) pit_ibm5550_init(); nmi_mask = 0; - epoch_t *epoch = device_add(&epoch_device); + device_add(&epoch_device); device_add(&lpt_port_device); serial_t *uart = device_add(&ns8250_device); From 522b7437bbcd5ea198c2674df4b3a8b7ac8469f0 Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 9 Feb 2026 03:44:53 +0900 Subject: [PATCH 43/49] fix errors in kbd --- src/machine/m_xt_ibm5550.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/src/machine/m_xt_ibm5550.c b/src/machine/m_xt_ibm5550.c index a78a35fca..7bd9fa321 100644 --- a/src/machine/m_xt_ibm5550.c +++ b/src/machine/m_xt_ibm5550.c @@ -530,7 +530,7 @@ epoch_outb(uint16_t addr, uint8_t val, void *priv) } epoch_out(addr, epoch->iolatch, epoch); } -void +static void epoch_outw(uint16_t addr, uint16_t val, void *priv) { epoch_iolog("epoch Outw addr %03X val %04X\n", addr, val); @@ -1429,7 +1429,7 @@ static int key_queue_start = 0; static int key_queue_end = 0; static void -kbd_poll(void *priv) +kbd_epoch_poll(void *priv) { epochkbd_t *kbd = (epochkbd_t *) priv; @@ -1456,17 +1456,8 @@ kbd_poll(void *priv) } } -void -kbd_adddata_xt_common(uint16_t val) -{ - key_queue[key_queue_end] = val; - epoch_log("epochkbd: %02X added to key queue at %i\n", - val, key_queue_end); - key_queue_end = (key_queue_end + 1) & 0x0f; -} - -void -kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) +static void +kbd_epoch_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) { uint8_t num_lock = 0; uint8_t shift_states = 0; @@ -1490,8 +1481,8 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) } } -void -kbd_adddata(uint16_t val) +static void +kbd_epoch_adddata(uint16_t val) { key_queue[key_queue_end] = val; epoch_log("XTkbd: %02X added to key queue at %i\n", @@ -1503,7 +1494,7 @@ static void kbd_adddata_ex(uint16_t val) { if (val < 0x100) - kbd_adddata_process(val, kbd_adddata); + kbd_epoch_adddata_process(val, kbd_epoch_adddata); } static void @@ -1524,7 +1515,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd->reset_step = 0; /* Specific 5556 keyboards send three bytes of identification code, but this simply sends AAh that can pass the IPL and DOS K3.4 init. */ - kbd_adddata(0xaa); + kbd_epoch_adddata(0xaa); } else if (!(kbd->pb & 0x08)) { kbd->pa = 0; kbd->blocked = 0; @@ -1629,7 +1620,7 @@ kbd_init(const device_t *info) key_queue_start = key_queue_end = 0; - timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1); + timer_add(&kbd->send_delay_timer, kbd_epoch_poll, kbd, 1); keyboard_set_table(scancode_set8a); keyboard_mode = 0x8a; @@ -1656,7 +1647,7 @@ kbd_close(void *priv) free(kbd); } -const device_t kbc_epoch_device = { +static const device_t kbc_epoch_device = { .name = "IBM 5550 Keyboard Controller", .internal_name = "kbc_epoch", .flags = 0, @@ -2063,7 +2054,7 @@ epoch_force_redraw(void *priv) epoch->fullchange = changeframecount; } -const device_t epoch_device = { +static const device_t epoch_device = { .name = "IBM 5550 Video Controller (Epoch)", .internal_name = "ibm5550vid", .flags = DEVICE_ISA, @@ -2077,7 +2068,7 @@ const device_t epoch_device = { .config = NULL }; -void +static void pit_irq6_timer(int new_out, int old_out, UNUSED(void *priv)) { // epoch_log("%04X:%04X IRQ6 Timer triggered.\n", cs >> 4, cpu_state.pc); @@ -2089,7 +2080,7 @@ pit_irq6_timer(int new_out, int old_out, UNUSED(void *priv)) } static pit_t * -pit_ibm5550_init() +pit_ibm5550_init(void) { void *pit; From dfc0bba8d72621aad5aa1e9e6ef22c7e018c442b Mon Sep 17 00:00:00 2001 From: Akamaki <97360908+akmed772@users.noreply.github.com> Date: Mon, 9 Feb 2026 03:53:34 +0900 Subject: [PATCH 44/49] fix some warnings --- src/machine/m_xt_ibm5550.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/machine/m_xt_ibm5550.c b/src/machine/m_xt_ibm5550.c index 7bd9fa321..e1c842ecb 100644 --- a/src/machine/m_xt_ibm5550.c +++ b/src/machine/m_xt_ibm5550.c @@ -1367,6 +1367,7 @@ static void epoch_misc_out(uint16_t port, uint8_t val, void *priv) { epoch_t *epoch = (epoch_t *) priv; + pit_intf_t *pit_intf = &pit_devs[0]; // dev->regs[port & 0x0007] = val; // epoch_log("%04X:%04X I/O Out %02X: %02X\n AX=%04X BX=%04X CX=%04X DX=%04X ES=%04X DI=%04X DS=%04X SI=%04X\n", @@ -1376,7 +1377,6 @@ epoch_misc_out(uint16_t port, uint8_t val, void *priv) switch (port) { case 0x44: - pit_intf_t *pit_intf = &pit_devs[0]; for (uint8_t i = 0; i < 3; i++) { pit_intf->set_gate(pit_intf->data, i, val & 1); } @@ -1459,26 +1459,22 @@ kbd_epoch_poll(void *priv) static void kbd_epoch_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) { - uint8_t num_lock = 0; - uint8_t shift_states = 0; + // uint8_t num_lock = 0; + // uint8_t shift_states = 0; if (!adddata) return; - keyboard_get_states(NULL, &num_lock, NULL, NULL); - shift_states = keyboard_get_shift() & STATE_LSHIFT; + // keyboard_get_states(NULL, &num_lock, NULL, NULL); + // shift_states = keyboard_get_shift() & STATE_LSHIFT; - /* If NumLock is on, invert the left shift state so we can always check for - the the same way flag being set (and with NumLock on that then means it - is actually *NOT* set). */ - if (num_lock) - shift_states ^= STATE_LSHIFT; + // /* If NumLock is on, invert the left shift state so we can always check for + // the the same way flag being set (and with NumLock on that then means it + // is actually *NOT* set). */ + // if (num_lock) + // shift_states ^= STATE_LSHIFT; - switch (val) { - default: - adddata(val); - break; - } + adddata(val); } static void From 8a22d2468e2ee5dda27b58ec60e285fe42f1e59a Mon Sep 17 00:00:00 2001 From: Asem Arafa Date: Sun, 8 Feb 2026 20:12:56 +0000 Subject: [PATCH 45/49] Qt: Fix media file picker location persistence --- src/qt/qt_mediamenu.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 968858dd2..c9250f44c 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -592,10 +592,10 @@ MediaMenu::cdromMount(int i, int dir, const QString &arg) if (dir > 1) filename = QString::asprintf(R"(ioctl://%s)", arg.toUtf8().data()); else if (dir == 1) - filename = QFileDialog::getExistingDirectory(parentWidget); + filename = QFileDialog::getExistingDirectory(parentWidget, QString(), getMediaOpenDirectory()); else { filename = QFileDialog::getOpenFileName(parentWidget, QString(), - QString(), + getMediaOpenDirectory(), tr("CD-ROM images") % util::DlgFilter({ "iso", "cue", "mds", "mdx" }) % tr("All files") % util::DlgFilter({ "*" }, true)); } @@ -1199,10 +1199,13 @@ MediaMenu::nicUpdateMenu(int i) QString MediaMenu::getMediaOpenDirectory() { - QString openDirectory; + static bool firstCall = true; + QString openDirectory; - if (open_dir_usr_path > 0) + if (open_dir_usr_path > 0 && firstCall) { openDirectory = QString::fromUtf8(usr_path); + firstCall = false; + } return openDirectory; } From be68940f150d74570fd41a1260a081344dd2e69b Mon Sep 17 00:00:00 2001 From: Paradyx0392 Date: Mon, 9 Feb 2026 13:49:21 +0800 Subject: [PATCH 46/49] Update en-GB.po Corrected the translation + added more strings --- src/qt/languages/en-GB.po | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index fdc71fcb1..b2dc80dd7 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -15,6 +15,9 @@ msgstr "&RGB Greyscale" msgid "Generic RGBI color monitor" msgstr "Generic RGBI colour monitor" +msgid "Grayscale &conversion type" +msgstr "Greyscale &conversion type" + msgid "Time synchronization" msgstr "Time synchronisation" @@ -28,7 +31,7 @@ msgid "Failed to initialize network driver" msgstr "Failed to initialise network driver" msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." -msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behaviour should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Appl&y fullscreen stretch mode when maximised" @@ -78,9 +81,18 @@ msgstr "Enhanced Colour - Enhanced Mode (5154/ECD)" msgid "Gray" msgstr "Grey" +msgid "Grayscale" +msgstr "Greyscale" + msgid "Color" msgstr "Colour" +msgid "Color Interlaced" +msgstr "Colour Interlaced" + +msgid "Color Non-Interlaced" +msgstr "Colour Non-Interlaced" + msgid "Failed to initialize Vulkan renderer." msgstr "Failed to initialise Vulkan renderer." From ba5e89a996206f62b88582f12156f0544bb030e9 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:40:56 -0600 Subject: [PATCH 47/49] Headland: Add some basic logging --- src/chipset/headland.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index f52e3fe77..13dfe6799 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -18,11 +18,17 @@ * Copyright 2017-2019 Miran Grca. * Copyright 2017-2019 GreatPsycho. */ +#ifdef ENABLE_HEADLAND_LOG +#include +#endif #include #include #include #include #include +#ifdef ENABLE_HEADLAND_LOG +#define HAVE_STDARG_H +#endif #include <86box/86box.h> #include "cpu.h" #include "x86.h" @@ -35,6 +41,24 @@ #include <86box/plat_unused.h> #include <86box/port_92.h> #include <86box/chipset.h> +#include <86box/log.h> + +#ifdef ENABLE_HEADLAND_LOG +int headland_do_log = ENABLE_HEADLAND_LOG; + +static void +headland_log(void *priv, const char *fmt, ...) +{ + if (headland_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define headland_log(fmt, ...) +#endif enum { HEADLAND_GC103 = 0x00, @@ -82,6 +106,8 @@ typedef struct headland_t { mem_mapping_t high_mapping; mem_mapping_t shadow_mapping[2]; mem_mapping_t upper_mapping[24]; + + void * log; /* New logging system */ } headland_t; /* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, @@ -125,6 +151,8 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) other_shift = (dev->cr[0] & 0x80) ? 21 : 19; } + headland_log(dev->log, "Headland shift values: shift = %i, other_shift = %i\n", shift, other_shift); + /* Bank size = 1 << (bank shift + 2) . */ bank_shift[0] = bank_shift[1] = shift; @@ -248,6 +276,7 @@ memmap_state_update(headland_t *dev) memmap_state_default(dev, ht_romcs); + headland_log(dev->log, "Headland 384K Remap %sabled\n", ht_cr0 & 0x04 ? "Dis" : "En"); if (mem_size > 640) { if (ht_cr0 & 0x04) { mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, 0x40000); @@ -273,6 +302,7 @@ memmap_state_update(headland_t *dev) } } + headland_log(dev->log, "Headland shadow RAM val = %02X\n", ht_cr0 & 0x18); switch (ht_cr0 & 0x18) { case 0x18: if ((mem_size << 10) > 0xe0000) { @@ -331,6 +361,8 @@ hl_write(uint16_t addr, uint8_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; @@ -401,6 +433,8 @@ hl_writew(uint16_t addr, uint16_t val, void *priv) { headland_t *dev = (headland_t *) priv; + headland_log(dev->log, "[%04X:%08X] Headland: [W] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, val); + switch (addr) { case 0x01ec: dev->ems_mr[dev->ems_mar & 0x3f].mr = val; @@ -470,6 +504,8 @@ hl_read(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %02X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -490,6 +526,8 @@ hl_readw(uint16_t addr, void *priv) break; } + headland_log(dev->log, "[%04X:%08X] Headland [R] addr = %04X, val = %04X\n", CS, cpu_state.pc, addr, ret); + return ret; } @@ -584,6 +622,11 @@ headland_close(void *priv) { headland_t *dev = (headland_t *) priv; + if (dev->log != NULL) { + log_close(dev->log); + dev->log = NULL; + } + free(dev); } @@ -621,6 +664,8 @@ headland_init(const device_t *info) dev->ems_mr[i].headland = dev; } + dev->log = log_open("Headland"); + /* Turn off mem.c mappings. */ mem_mapping_disable(&ram_low_mapping); mem_mapping_disable(&ram_mid_mapping); From 4bf2bc7bce28c1346e340dd39b05c1e2dc21e93d Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:08:06 -0600 Subject: [PATCH 48/49] Headland: Fix incorrect memory bank handling, fixes Tandy 1000 RSX BIOS hang with 9MB RAM --- src/chipset/headland.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 13dfe6799..37ec8a1fe 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -143,12 +143,12 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) else if ((addr >= 0xfe0000) && (addr <= 0xffffff)) return addr & 0x0fffff; - if (dev->revision == 8) { - shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[6] & 0x01) ? 23 : 19); - other_shift = (dev->cr[0] & 0x80) ? ((dev->cr[6] & 0x01) ? 19 : 23) : 21; + if ((dev->revision == 8) && ((dev->cr[6] & 0x01) == 0x01)) { + shift = (dev->cr[0] & 0x80) ? 21 : ((dev->cr[1] & 0x40) ? 19 : 23); + other_shift = (dev->cr[0] & 0x80) ? 23 : ((dev->cr[1] & 0x40) ? 23 : 23); } else { shift = (dev->cr[0] & 0x80) ? 21 : 19; - other_shift = (dev->cr[0] & 0x80) ? 21 : 19; + other_shift = (dev->cr[0] & 0x80) ? 19 : 21; } headland_log(dev->log, "Headland shift values: shift = %i, other_shift = %i\n", shift, other_shift); @@ -158,14 +158,15 @@ get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) bank_base[0] = 0x00000000; bank_base[1] = bank_base[0] + (1 << shift); - bank_base[2] = bank_base[1] + (1 << shift); - if ((dev->revision > 0) && (dev->revision < 8) && (dev->cr[1] & 0x40)) { + if ((dev->revision > 0) && (dev->cr[1] & 0x40)) { bank_shift[2] = bank_shift[3] = other_shift; + bank_base[2] = bank_base[1] + (1 << other_shift); bank_base[3] = bank_base[2] + (1 << other_shift); /* First address after the memory is bank_base[3] + (1 << other_shift) */ } else { bank_shift[2] = bank_shift[3] = shift; + bank_base[2] = bank_base[1] + (1 << shift); bank_base[3] = bank_base[2] + (1 << shift); /* First address after the memory is bank_base[3] + (1 << shift) */ } From 3a1845398b70c5175f2b0c2aefd8462452200f73 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:15:06 -0600 Subject: [PATCH 49/49] Headland: Correctly set memory state when enabling/disabling 384K remap and add 384K remap handling for 640-1024K memory configs, fixes 384K remap on Tandy 1000 RSX --- src/chipset/headland.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/chipset/headland.c b/src/chipset/headland.c index 37ec8a1fe..337aefb00 100644 --- a/src/chipset/headland.c +++ b/src/chipset/headland.c @@ -284,9 +284,11 @@ memmap_state_update(headland_t *dev) mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); mem_mapping_disable(&dev->mid_mapping); if (mem_size > 1024) { - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_EXTANY | MEM_WRITE_EXTANY); } } else { /* 1 MB - 1 MB + 384k: RAM pointing to A0000-FFFFF @@ -296,9 +298,11 @@ memmap_state_update(headland_t *dev) mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); if (mem_size > 1024) { /* We have ram above 1 MB, we need to relocate that. */ - mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + mem_set_mem_state((mem_size << 10), 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } else if ((mem_size > 640) && (mem_size <=1024)) { + mem_set_mem_state(0x100000, (mem_size - 640) << 10, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); } } }