Merge branch '86Box:master' into master

This commit is contained in:
starfrost
2025-03-29 16:20:18 +00:00
committed by GitHub
82 changed files with 4252 additions and 2641 deletions

View File

@@ -1293,6 +1293,8 @@ pc_reset_hard_init(void)
* modules that are.
*/
keyboard_init();
/* Reset the IDE and SCSI presences */
other_ide_present = other_scsi_present = 0;

View File

@@ -723,7 +723,11 @@ host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p)
codegen_addbyte4(block, 0x41, 0x8a, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/
codegen_addlong(block, ram_offset);
} else {
fatal("host_x86_MOV8_REG_ABS - out of range\n");
codegen_alloc_bytes(block, 10);
codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/
codegen_addquad(block, (uintptr_t) p);
codegen_alloc_bytes(block, 3);
codegen_addbyte3(block, 0x41, 0x8a, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [R9]*/
}
}
void

View File

@@ -192,12 +192,6 @@ load_general(void)
else if (mouse_sensitivity > 2.0)
mouse_sensitivity = 2.0;
p = ini_section_get_string(cat, "iconset", NULL);
if (p != NULL)
strcpy(icon_set, p);
else
strcpy(icon_set, "");
enable_discord = !!ini_section_get_int(cat, "enable_discord", 0);
open_dir_usr_path = ini_section_get_int(cat, "open_dir_usr_path", 0);
@@ -2038,11 +2032,6 @@ save_general(void)
ini_section_set_string(cat, "language", buffer);
}
if (!strcmp(icon_set, ""))
ini_section_delete_var(cat, "iconset");
else
ini_section_set_string(cat, "iconset", icon_set);
if (enable_discord)
ini_section_set_int(cat, "enable_discord", enable_discord);
else

View File

@@ -1,290 +0,0 @@
/*
* 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.
*
* 8080 CPU emulation.
*
* Authors: Cacodemon345
*
* Copyright 2022 Cacodemon345
*/
#include <stdint.h>
#include <stdlib.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/i8080.h>
#include <86box/mem.h>
#include <86box/plat_unused.h>
static int completed = 1;
static int in_rep = 0;
static int repeating = 0;
static int rep_c_flag = 0;
static int oldc;
static int cycdiff;
#ifdef UNUSED_8080_VARS
static int prefetching = 1;
static int refresh = 0;
static int clear_lock = 0;
static uint32_t cpu_src = 0;
static uint32_t cpu_dest = 0;
static uint32_t cpu_data = 0;
#endif
static void
clock_start(void)
{
cycdiff = cycles;
}
static void
clock_end(void)
{
int diff = cycdiff - cycles;
/* On 808x systems, clock speed is usually crystal frequency divided by an integer. */
tsc += (uint64_t) diff * (xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc))
timer_process();
}
static void
i8080_wait(int c, int bus)
{
cycles -= c;
if (bus < 2) {
clock_end();
clock_start();
}
}
#ifdef UNUSED_8080_FUNCS
static uint8_t
readmemb(uint32_t a)
{
uint8_t ret;
i8080_wait(4, 1);
ret = read_mem_b(a);
return ret;
}
static uint8_t
ins_fetch(i8080 *cpu)
{
uint8_t ret = cpu->readmembyte(cpu->pmembase + cpu->pc);
cpu->pc++;
return ret;
}
#endif
void
transfer_from_808x(i8080 *cpu)
{
cpu->hl = BX;
cpu->bc = CX;
cpu->de = DX;
cpu->a = AL;
cpu->flags = cpu_state.flags & 0xFF;
cpu->sp = BP;
cpu->pc = cpu_state.pc;
cpu->oldpc = cpu_state.oldpc;
cpu->pmembase = cs;
cpu->dmembase = ds;
}
void
transfer_to_808x(i8080 *cpu)
{
BX = cpu->hl;
CX = cpu->bc;
DX = cpu->de;
AL = cpu->a;
cpu_state.flags &= 0xFF00;
cpu_state.flags |= cpu->flags & 0xFF;
BP = cpu->sp;
cpu_state.pc = cpu->pc;
}
uint8_t
getreg_i8080(i8080 *cpu, uint8_t reg)
{
uint8_t ret = 0xFF;
switch (reg) {
case 0x0:
ret = cpu->b;
break;
case 0x1:
ret = cpu->c;
break;
case 0x2:
ret = cpu->d;
break;
case 0x3:
ret = cpu->e;
break;
case 0x4:
ret = cpu->h;
break;
case 0x5:
ret = cpu->l;
break;
case 0x6:
ret = cpu->readmembyte(cpu->dmembase + cpu->sp);
break;
case 0x7:
ret = cpu->a;
break;
}
return ret;
}
uint8_t
getreg_i8080_emu(i8080 *cpu, uint8_t reg)
{
uint8_t ret = 0xFF;
switch (reg) {
case 0x0:
ret = CH;
break;
case 0x1:
ret = CL;
break;
case 0x2:
ret = DH;
break;
case 0x3:
ret = DL;
break;
case 0x4:
ret = BH;
break;
case 0x5:
ret = BL;
break;
case 0x6:
ret = cpu->readmembyte(cpu->dmembase + BP);
break;
case 0x7:
ret = AL;
break;
}
return ret;
}
void
setreg_i8080_emu(i8080 *cpu, uint8_t reg, uint8_t val)
{
switch (reg) {
case 0x0:
CH = val;
break;
case 0x1:
CL = val;
break;
case 0x2:
DH = val;
break;
case 0x3:
DL = val;
break;
case 0x4:
BH = val;
break;
case 0x5:
BL = val;
break;
case 0x6:
cpu->writemembyte(cpu->dmembase + BP, val);
break;
case 0x7:
AL = val;
break;
}
}
void
setreg_i8080(i8080 *cpu, uint8_t reg, uint8_t val)
{
switch (reg) {
case 0x0:
cpu->b = val;
break;
case 0x1:
cpu->c = val;
break;
case 0x2:
cpu->d = val;
break;
case 0x3:
cpu->e = val;
break;
case 0x4:
cpu->h = val;
break;
case 0x5:
cpu->l = val;
break;
case 0x6:
cpu->writemembyte(cpu->dmembase + cpu->sp, val);
break;
case 0x7:
cpu->a = val;
break;
}
}
void
interpret_exec8080(UNUSED(i8080 *cpu), uint8_t opcode)
{
switch (opcode) {
case 0x00:
{
break;
}
}
}
/* Actually implement i8080 emulation. */
void
exec8080(i8080 *cpu, int cycs)
{
#ifdef UNUSED_8080_VARS
uint8_t temp = 0, temp2;
uint8_t old_af;
uint8_t handled = 0;
uint16_t addr, tempw;
uint16_t new_ip;
int bits;
#endif
cycles += cycs;
while (cycles > 0) {
cpu->startclock();
if (!repeating) {
cpu->oldpc = cpu->pc;
opcode = cpu->fetchinstruction(cpu);
oldc = cpu->flags & C_FLAG_I8080;
i8080_wait(1, 0);
}
completed = 1;
if (completed) {
repeating = 0;
in_rep = 0;
rep_c_flag = 0;
cpu->endclock();
if (cpu->checkinterrupts)
cpu->checkinterrupts();
}
}
}

View File

@@ -18,10 +18,13 @@
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "i8080.h"
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
@@ -70,6 +73,9 @@ static int in_rep = 0, repeating = 0, rep_c_flag = 0;
static int oldc, clear_lock = 0;
static int refresh = 0, cycdiff;
static i8080 emulated_processor;
static bool cpu_md_write_disable = 1;
/* Various things needed for 8087. */
#define OP_TABLE(name) ops_##name
@@ -195,6 +201,56 @@ prefetch_queue_get_size(void)
{
return pfq_size;
}
static void set_if(int cond);
void
sync_from_i8080(void)
{
AL = emulated_processor.a;
BH = emulated_processor.h;
BL = emulated_processor.l;
CH = emulated_processor.b;
CL = emulated_processor.c;
DH = emulated_processor.d;
DL = emulated_processor.e;
BP = emulated_processor.sp;
cpu_state.pc = emulated_processor.pc;
cpu_state.flags &= 0xFF00;
cpu_state.flags |= emulated_processor.sf << 7;
cpu_state.flags |= emulated_processor.zf << 6;
cpu_state.flags |= emulated_processor.hf << 4;
cpu_state.flags |= emulated_processor.pf << 2;
cpu_state.flags |= 1 << 1;
cpu_state.flags |= emulated_processor.cf << 0;
set_if(emulated_processor.iff);
}
void
sync_to_i8080(void)
{
if (!is_nec)
return;
emulated_processor.a = AL;
emulated_processor.h = BH;
emulated_processor.l = BL;
emulated_processor.b = CH;
emulated_processor.c = CL;
emulated_processor.d = DH;
emulated_processor.e = DL;
emulated_processor.sp = BP;
emulated_processor.pc = cpu_state.pc;
emulated_processor.iff = !!(cpu_state.flags & I_FLAG);
emulated_processor.sf = (cpu_state.flags >> 7) & 1;
emulated_processor.zf = (cpu_state.flags >> 6) & 1;
emulated_processor.hf = (cpu_state.flags >> 4) & 1;
emulated_processor.pf = (cpu_state.flags >> 2) & 1;
emulated_processor.cf = (cpu_state.flags >> 0) & 1;
emulated_processor.interrupt_delay = noint;
}
uint16_t
get_last_addr(void)
@@ -582,6 +638,33 @@ load_seg(uint16_t seg, x86seg *s)
s->seg = seg & 0xffff;
}
uint8_t fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr)
{
return readmemb(cs + addr);
}
uint8_t fetch_i8080_data(UNUSED(void* priv), uint16_t addr)
{
return readmemb(ds + addr);
}
void put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val)
{
writememb(ds, addr, val);
}
static uint8_t i8080_port_in(UNUSED(void* priv), uint8_t port)
{
cpu_io(8, 0, port);
return AL;
}
static void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val)
{
AL = val;
cpu_io(8, 1, port);
}
void
reset_808x(int hard)
{
@@ -619,6 +702,14 @@ reset_808x(int hard)
use_custom_nmi_vector = 0x00;
custom_nmi_vector = 0x00000000;
cpu_md_write_disable = 1;
i8080_init(&emulated_processor);
emulated_processor.write_byte = put_i8080_data;
emulated_processor.read_byte = fetch_i8080_data;
emulated_processor.read_byte_seg = fetch_i8080_opcode;
emulated_processor.port_in = i8080_port_in;
emulated_processor.port_out = i8080_port_out;
}
static void
@@ -994,6 +1085,11 @@ interrupt(uint16_t addr)
uint16_t new_cs, new_ip;
uint16_t tempf;
if (!(cpu_state.flags & MD_FLAG) && is_nec) {
sync_from_i8080();
x808x_log("CALLN/INT#/NMI#\n");
}
addr <<= 2;
cpu_state.eaaddr = addr;
old_cs = CS;
@@ -1010,6 +1106,8 @@ interrupt(uint16_t addr)
tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
push(&tempf);
cpu_state.flags &= ~(I_FLAG | T_FLAG);
if (is_nec)
cpu_state.flags |= MD_FLAG;
access(40, 16);
push(&old_cs);
old_ip = cpu_state.pc;
@@ -1020,6 +1118,65 @@ interrupt(uint16_t addr)
push(&old_ip);
}
/* Ditto, but for breaking into emulation mode. */
static void
interrupt_brkem(uint16_t addr)
{
uint16_t old_cs, old_ip;
uint16_t new_cs, new_ip;
uint16_t tempf;
addr <<= 2;
cpu_state.eaaddr = addr;
old_cs = CS;
access(5, 16);
new_ip = readmemw(0, cpu_state.eaaddr);
wait(1, 0);
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
access(6, 16);
new_cs = readmemw(0, cpu_state.eaaddr);
prefetching = 0;
pfq_clear();
ovr_seg = NULL;
access(39, 16);
tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
push(&tempf);
cpu_state.flags &= ~(MD_FLAG);
cpu_md_write_disable = 0;
access(40, 16);
push(&old_cs);
old_ip = cpu_state.pc;
load_cs(new_cs);
access(68, 16);
set_ip(new_ip);
access(41, 16);
push(&old_ip);
sync_to_i8080();
x808x_log("BRKEM mode\n");
}
void
retem_i8080(void)
{
sync_from_i8080();
prefetching = 0;
pfq_clear();
set_ip(pop());
load_cs(pop());
cpu_state.flags = pop();
emulated_processor.iff = !!(cpu_state.flags & I_FLAG);
cpu_md_write_disable = 1;
noint = 1;
nmi_enable = 1;
x808x_log("RETEM mode\n");
}
void
interrupt_808x(uint16_t addr)
{
@@ -1033,6 +1190,11 @@ custom_nmi(void)
uint16_t new_cs, new_ip;
uint16_t tempf;
if (!(cpu_state.flags & MD_FLAG) && is_nec) {
sync_from_i8080();
pclog("NMI# (CUTSOM)\n");
}
cpu_state.eaaddr = 0x0002;
old_cs = CS;
access(5, 16);
@@ -1050,6 +1212,8 @@ custom_nmi(void)
tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
push(&tempf);
cpu_state.flags &= ~(I_FLAG | T_FLAG);
if (is_nec)
cpu_state.flags |= MD_FLAG;
access(40, 16);
push(&old_cs);
old_ip = cpu_state.pc;
@@ -1771,6 +1935,15 @@ execx86(int cycs)
while (cycles > 0) {
clock_start();
if (is_nec && !(cpu_state.flags & MD_FLAG)) {
i8080_step(&emulated_processor);
set_if(emulated_processor.iff);
cycles -= emulated_processor.cyc;
emulated_processor.cyc = 0;
completed = 1;
goto exec_completed;
}
if (!repeating) {
cpu_state.oldpc = cpu_state.pc;
opcode = pfq_fetchb();
@@ -2344,8 +2517,8 @@ execx86(int cycs)
break;
case 0xFF: /* BRKEM */
/* Unimplemented for now. */
fatal("808x: Unsupported 8080 emulation mode attempted to enter into!");
interrupt_brkem(pfq_fetchb());
handled = 1;
break;
default:
@@ -2857,11 +3030,12 @@ execx86(int cycs)
break;
case 0x9D: /*POPF*/
access(25, 16);
if (is_nec)
if (is_nec && cpu_md_write_disable)
cpu_state.flags = pop() | 0x8002;
else
cpu_state.flags = pop() | 0x0002;
wait(1, 0);
sync_to_i8080();
break;
case 0x9E: /*SAHF*/
wait(1, 0);
@@ -3127,13 +3301,15 @@ execx86(int cycs)
access(62, 8);
set_ip(new_ip);
access(45, 8);
if (is_nec)
if (is_nec && cpu_md_write_disable)
cpu_state.flags = pop() | 0x8002;
else
cpu_state.flags = pop() | 0x0002;
wait(5, 0);
noint = 1;
nmi_enable = 1;
if (is_nec && !(cpu_state.flags & MD_FLAG))
sync_to_i8080();
break;
case 0xD0:
@@ -3659,7 +3835,7 @@ execx86(int cycs)
break;
}
}
exec_completed:
if (completed) {
repeating = 0;
ovr_seg = NULL;

View File

@@ -29,7 +29,7 @@ add_library(cpu OBJECT
x86seg_2386.c
x87.c
x87_timings.c
8080.c
i8080.c
)
if(AMD_K5)

826
src/cpu/i8080.c Normal file
View File

@@ -0,0 +1,826 @@
/*
* 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.
*
* Intel 8080 CPU emulation
*
* Authors: Cacodemon345
* Nicolas Allemand
*
* Copyright (c) 2018 Nicolas Allemand
* Copyright (c) 2024 Cacodemon345
*
*/
#include "i8080.h"
#include <stdint.h>
// Changes from upstream:
// Add CALLN and RETEM instructions.
// Add code for instruction fetches.
// this array defines the number of cycles one opcode takes.
// note that there are some special cases: conditional RETs and CALLs
// add +6 cycles if the condition is met
// clang-format off
static const uint8_t OPCODES_CYCLES[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 0
4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 1
4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4, // 2
4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4, // 3
5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 4
5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 5
5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 6
7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, // 7
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B
5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // C
5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // D
5, 10, 10, 18, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11, // E
5, 10, 10, 4, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11 // F
};
// clang-format on
static const char* DISASSEMBLE_TABLE[] = {"nop", "lxi b,#", "stax b", "inx b",
"inr b", "dcr b", "mvi b,#", "rlc", "ill", "dad b", "ldax b", "dcx b",
"inr c", "dcr c", "mvi c,#", "rrc", "ill", "lxi d,#", "stax d", "inx d",
"inr d", "dcr d", "mvi d,#", "ral", "ill", "dad d", "ldax d", "dcx d",
"inr e", "dcr e", "mvi e,#", "rar", "ill", "lxi h,#", "shld", "inx h",
"inr h", "dcr h", "mvi h,#", "daa", "ill", "dad h", "lhld", "dcx h",
"inr l", "dcr l", "mvi l,#", "cma", "ill", "lxi sp,#", "sta $", "inx sp",
"inr M", "dcr M", "mvi M,#", "stc", "ill", "dad sp", "lda $", "dcx sp",
"inr a", "dcr a", "mvi a,#", "cmc", "mov b,b", "mov b,c", "mov b,d",
"mov b,e", "mov b,h", "mov b,l", "mov b,M", "mov b,a", "mov c,b", "mov c,c",
"mov c,d", "mov c,e", "mov c,h", "mov c,l", "mov c,M", "mov c,a", "mov d,b",
"mov d,c", "mov d,d", "mov d,e", "mov d,h", "mov d,l", "mov d,M", "mov d,a",
"mov e,b", "mov e,c", "mov e,d", "mov e,e", "mov e,h", "mov e,l", "mov e,M",
"mov e,a", "mov h,b", "mov h,c", "mov h,d", "mov h,e", "mov h,h", "mov h,l",
"mov h,M", "mov h,a", "mov l,b", "mov l,c", "mov l,d", "mov l,e", "mov l,h",
"mov l,l", "mov l,M", "mov l,a", "mov M,b", "mov M,c", "mov M,d", "mov M,e",
"mov M,h", "mov M,l", "hlt", "mov M,a", "mov a,b", "mov a,c", "mov a,d",
"mov a,e", "mov a,h", "mov a,l", "mov a,M", "mov a,a", "add b", "add c",
"add d", "add e", "add h", "add l", "add M", "add a", "adc b", "adc c",
"adc d", "adc e", "adc h", "adc l", "adc M", "adc a", "sub b", "sub c",
"sub d", "sub e", "sub h", "sub l", "sub M", "sub a", "sbb b", "sbb c",
"sbb d", "sbb e", "sbb h", "sbb l", "sbb M", "sbb a", "ana b", "ana c",
"ana d", "ana e", "ana h", "ana l", "ana M", "ana a", "xra b", "xra c",
"xra d", "xra e", "xra h", "xra l", "xra M", "xra a", "ora b", "ora c",
"ora d", "ora e", "ora h", "ora l", "ora M", "ora a", "cmp b", "cmp c",
"cmp d", "cmp e", "cmp h", "cmp l", "cmp M", "cmp a", "rnz", "pop b",
"jnz $", "jmp $", "cnz $", "push b", "adi #", "rst 0", "rz", "ret", "jz $",
"ill", "cz $", "call $", "aci #", "rst 1", "rnc", "pop d", "jnc $", "out p",
"cnc $", "push d", "sui #", "rst 2", "rc", "ill", "jc $", "in p", "cc $",
"ill", "sbi #", "rst 3", "rpo", "pop h", "jpo $", "xthl", "cpo $", "push h",
"ani #", "rst 4", "rpe", "pchl", "jpe $", "xchg", "cpe $", "ill", "xri #",
"rst 5", "rp", "pop psw", "jp $", "di", "cp $", "push psw", "ori #",
"rst 6", "rm", "sphl", "jm $", "ei", "cm $", "ill", "cpi #", "rst 7"};
#define SET_ZSP(c, val) \
do { \
c->zf = (val) == 0; \
c->sf = (val) >> 7; \
c->pf = parity(val); \
} while (0)
// memory helpers (the only four to use `read_byte` and `write_byte` function
// pointers)
// reads a byte from memory
static inline uint8_t i8080_rb(i8080* const c, uint16_t addr) {
return c->read_byte(c->userdata, addr);
}
// writes a byte to memory
static inline void i8080_wb(i8080* const c, uint16_t addr, uint8_t val) {
c->write_byte(c->userdata, addr, val);
}
// reads a word from memory
static inline uint16_t i8080_rw(i8080* const c, uint16_t addr) {
return c->read_byte(c->userdata, addr + 1) << 8 |
c->read_byte(c->userdata, addr);
}
// writes a word to memory
static inline void i8080_ww(i8080* const c, uint16_t addr, uint16_t val) {
c->write_byte(c->userdata, addr, val & 0xFF);
c->write_byte(c->userdata, addr + 1, val >> 8);
}
// returns the next byte in memory (and updates the program counter)
static inline uint8_t i8080_next_byte(i8080* const c) {
return c->read_byte_seg ? (c->read_byte_seg(c->userdata, c->pc++)) : i8080_rb(c, c->pc++);
}
// returns the next word in memory (and updates the program counter)
static inline uint16_t i8080_next_word(i8080* const c) {
uint16_t result = 0;
if (c->read_byte_seg)
result = c->read_byte_seg(c, c->pc) | (c->read_byte_seg(c, c->pc + 1) << 8);
else
result = i8080_rw(c, c->pc);
c->pc += 2;
return result;
}
// paired registers helpers (setters and getters)
static inline void i8080_set_bc(i8080* const c, uint16_t val) {
c->b = val >> 8;
c->c = val & 0xFF;
}
static inline void i8080_set_de(i8080* const c, uint16_t val) {
c->d = val >> 8;
c->e = val & 0xFF;
}
static inline void i8080_set_hl(i8080* const c, uint16_t val) {
c->h = val >> 8;
c->l = val & 0xFF;
}
static inline uint16_t i8080_get_bc(i8080* const c) {
return (c->b << 8) | c->c;
}
static inline uint16_t i8080_get_de(i8080* const c) {
return (c->d << 8) | c->e;
}
static inline uint16_t i8080_get_hl(i8080* const c) {
return (c->h << 8) | c->l;
}
// stack helpers
// pushes a value into the stack and updates the stack pointer
static inline void i8080_push_stack(i8080* const c, uint16_t val) {
c->sp -= 2;
i8080_ww(c, c->sp, val);
}
// pops a value from the stack and updates the stack pointer
static inline uint16_t i8080_pop_stack(i8080* const c) {
uint16_t val = i8080_rw(c, c->sp);
c->sp += 2;
return val;
}
// opcodes
// returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1
static inline bool parity(uint8_t val) {
uint8_t nb_one_bits = 0;
for (int i = 0; i < 8; i++) {
nb_one_bits += ((val >> i) & 1);
}
return (nb_one_bits & 1) == 0;
}
// returns if there was a carry between bit "bit_no" and "bit_no - 1" when
// executing "a + b + cy"
static inline bool carry(int bit_no, uint8_t a, uint8_t b, bool cy) {
int16_t result = a + b + cy;
int16_t carry = result ^ a ^ b;
return carry & (1 << bit_no);
}
// adds a value (+ an optional carry flag) to a register
static inline void i8080_add(
i8080* const c, uint8_t* const reg, uint8_t val, bool cy) {
uint8_t result = *reg + val + cy;
c->cf = carry(8, *reg, val, cy);
c->hf = carry(4, *reg, val, cy);
SET_ZSP(c, result);
*reg = result;
}
// substracts a byte (+ an optional carry flag) from a register
// see https://stackoverflow.com/a/8037485
static inline void i8080_sub(
i8080* const c, uint8_t* const reg, uint8_t val, bool cy) {
i8080_add(c, reg, ~val, !cy);
c->cf = !c->cf;
}
// adds a word to HL
static inline void i8080_dad(i8080* const c, uint16_t val) {
c->cf = ((i8080_get_hl(c) + val) >> 16) & 1;
i8080_set_hl(c, i8080_get_hl(c) + val);
}
// increments a byte
static inline uint8_t i8080_inr(i8080* const c, uint8_t val) {
uint8_t result = val + 1;
c->hf = (result & 0xF) == 0;
SET_ZSP(c, result);
return result;
}
// decrements a byte
static inline uint8_t i8080_dcr(i8080* const c, uint8_t val) {
uint8_t result = val - 1;
c->hf = !((result & 0xF) == 0xF);
SET_ZSP(c, result);
return result;
}
// executes a logic "and" between register A and a byte, then stores the
// result in register A
static inline void i8080_ana(i8080* const c, uint8_t val) {
uint8_t result = c->a & val;
c->cf = 0;
c->hf = ((c->a | val) & 0x08) != 0;
SET_ZSP(c, result);
c->a = result;
}
// executes a logic "xor" between register A and a byte, then stores the
// result in register A
static inline void i8080_xra(i8080* const c, uint8_t val) {
c->a ^= val;
c->cf = 0;
c->hf = 0;
SET_ZSP(c, c->a);
}
// executes a logic "or" between register A and a byte, then stores the
// result in register A
static inline void i8080_ora(i8080* const c, uint8_t val) {
c->a |= val;
c->cf = 0;
c->hf = 0;
SET_ZSP(c, c->a);
}
// compares the register A to another byte
static inline void i8080_cmp(i8080* const c, uint8_t val) {
int16_t result = c->a - val;
c->cf = result >> 8;
c->hf = ~(c->a ^ result ^ val) & 0x10;
SET_ZSP(c, result & 0xFF);
}
// sets the program counter to a given address
static inline void i8080_jmp(i8080* const c, uint16_t addr) {
c->pc = addr;
}
// jumps to next address pointed by the next word in memory if a condition
// is met
static inline void i8080_cond_jmp(i8080* const c, bool condition) {
uint16_t addr = i8080_next_word(c);
if (condition) {
c->pc = addr;
}
}
// pushes the current pc to the stack, then jumps to an address
static inline void i8080_call(i8080* const c, uint16_t addr) {
i8080_push_stack(c, c->pc);
i8080_jmp(c, addr);
}
// calls to next word in memory if a condition is met
static inline void i8080_cond_call(i8080* const c, bool condition) {
uint16_t addr = i8080_next_word(c);
if (condition) {
i8080_call(c, addr);
c->cyc += 6;
}
}
// returns from subroutine
static inline void i8080_ret(i8080* const c) {
c->pc = i8080_pop_stack(c);
}
// returns from subroutine if a condition is met
static inline void i8080_cond_ret(i8080* const c, bool condition) {
if (condition) {
i8080_ret(c);
c->cyc += 6;
}
}
// pushes register A and the flags into the stack
static inline void i8080_push_psw(i8080* const c) {
// note: bit 3 and 5 are always 0
uint8_t psw = 0;
psw |= c->sf << 7;
psw |= c->zf << 6;
psw |= c->hf << 4;
psw |= c->pf << 2;
psw |= 1 << 1; // bit 1 is always 1
psw |= c->cf << 0;
i8080_push_stack(c, c->a << 8 | psw);
}
// pops register A and the flags from the stack
static inline void i8080_pop_psw(i8080* const c) {
uint16_t af = i8080_pop_stack(c);
c->a = af >> 8;
uint8_t psw = af & 0xFF;
c->sf = (psw >> 7) & 1;
c->zf = (psw >> 6) & 1;
c->hf = (psw >> 4) & 1;
c->pf = (psw >> 2) & 1;
c->cf = (psw >> 0) & 1;
}
// rotate register A left
static inline void i8080_rlc(i8080* const c) {
c->cf = c->a >> 7;
c->a = (c->a << 1) | c->cf;
}
// rotate register A right
static inline void i8080_rrc(i8080* const c) {
c->cf = c->a & 1;
c->a = (c->a >> 1) | (c->cf << 7);
}
// rotate register A left with the carry flag
static inline void i8080_ral(i8080* const c) {
bool cy = c->cf;
c->cf = c->a >> 7;
c->a = (c->a << 1) | cy;
}
// rotate register A right with the carry flag
static inline void i8080_rar(i8080* const c) {
bool cy = c->cf;
c->cf = c->a & 1;
c->a = (c->a >> 1) | (cy << 7);
}
// Decimal Adjust Accumulator: the eight-bit number in register A is adjusted
// to form two four-bit binary-coded-decimal digits.
// For example, if A=$2B and DAA is executed, A becomes $31.
static inline void i8080_daa(i8080* const c) {
bool cy = c->cf;
uint8_t correction = 0;
uint8_t lsb = c->a & 0x0F;
uint8_t msb = c->a >> 4;
if (c->hf || lsb > 9) {
correction += 0x06;
}
if (c->cf || msb > 9 || (msb >= 9 && lsb > 9)) {
correction += 0x60;
cy = 1;
}
i8080_add(c, &c->a, correction, 0);
c->cf = cy;
}
// switches the value of registers DE and HL
static inline void i8080_xchg(i8080* const c) {
uint16_t de = i8080_get_de(c);
i8080_set_de(c, i8080_get_hl(c));
i8080_set_hl(c, de);
}
// switches the value of a word at (sp) and HL
static inline void i8080_xthl(i8080* const c) {
uint16_t val = i8080_rw(c, c->sp);
i8080_ww(c, c->sp, i8080_get_hl(c));
i8080_set_hl(c, val);
}
extern void interrupt_808x(uint16_t addr);
extern void retem_i8080(void);
// executes one opcode
static inline void i8080_execute(i8080* const c, uint8_t opcode) {
c->cyc += OPCODES_CYCLES[opcode];
// when DI is executed, interrupts won't be serviced
// until the end of next instruction:
if (c->interrupt_delay > 0) {
c->interrupt_delay -= 1;
}
switch (opcode) {
case 0x7F: c->a = c->a; break; // MOV A,A
case 0x78: c->a = c->b; break; // MOV A,B
case 0x79: c->a = c->c; break; // MOV A,C
case 0x7A: c->a = c->d; break; // MOV A,D
case 0x7B: c->a = c->e; break; // MOV A,E
case 0x7C: c->a = c->h; break; // MOV A,H
case 0x7D: c->a = c->l; break; // MOV A,L
case 0x7E: c->a = i8080_rb(c, i8080_get_hl(c)); break; // MOV A,M
case 0x0A: c->a = i8080_rb(c, i8080_get_bc(c)); break; // LDAX B
case 0x1A: c->a = i8080_rb(c, i8080_get_de(c)); break; // LDAX D
case 0x3A: c->a = i8080_rb(c, i8080_next_word(c)); break; // LDA word
case 0x47: c->b = c->a; break; // MOV B,A
case 0x40: c->b = c->b; break; // MOV B,B
case 0x41: c->b = c->c; break; // MOV B,C
case 0x42: c->b = c->d; break; // MOV B,D
case 0x43: c->b = c->e; break; // MOV B,E
case 0x44: c->b = c->h; break; // MOV B,H
case 0x45: c->b = c->l; break; // MOV B,L
case 0x46: c->b = i8080_rb(c, i8080_get_hl(c)); break; // MOV B,M
case 0x4F: c->c = c->a; break; // MOV C,A
case 0x48: c->c = c->b; break; // MOV C,B
case 0x49: c->c = c->c; break; // MOV C,C
case 0x4A: c->c = c->d; break; // MOV C,D
case 0x4B: c->c = c->e; break; // MOV C,E
case 0x4C: c->c = c->h; break; // MOV C,H
case 0x4D: c->c = c->l; break; // MOV C,L
case 0x4E: c->c = i8080_rb(c, i8080_get_hl(c)); break; // MOV C,M
case 0x57: c->d = c->a; break; // MOV D,A
case 0x50: c->d = c->b; break; // MOV D,B
case 0x51: c->d = c->c; break; // MOV D,C
case 0x52: c->d = c->d; break; // MOV D,D
case 0x53: c->d = c->e; break; // MOV D,E
case 0x54: c->d = c->h; break; // MOV D,H
case 0x55: c->d = c->l; break; // MOV D,L
case 0x56: c->d = i8080_rb(c, i8080_get_hl(c)); break; // MOV D,M
case 0x5F: c->e = c->a; break; // MOV E,A
case 0x58: c->e = c->b; break; // MOV E,B
case 0x59: c->e = c->c; break; // MOV E,C
case 0x5A: c->e = c->d; break; // MOV E,D
case 0x5B: c->e = c->e; break; // MOV E,E
case 0x5C: c->e = c->h; break; // MOV E,H
case 0x5D: c->e = c->l; break; // MOV E,L
case 0x5E: c->e = i8080_rb(c, i8080_get_hl(c)); break; // MOV E,M
case 0x67: c->h = c->a; break; // MOV H,A
case 0x60: c->h = c->b; break; // MOV H,B
case 0x61: c->h = c->c; break; // MOV H,C
case 0x62: c->h = c->d; break; // MOV H,D
case 0x63: c->h = c->e; break; // MOV H,E
case 0x64: c->h = c->h; break; // MOV H,H
case 0x65: c->h = c->l; break; // MOV H,L
case 0x66: c->h = i8080_rb(c, i8080_get_hl(c)); break; // MOV H,M
case 0x6F: c->l = c->a; break; // MOV L,A
case 0x68: c->l = c->b; break; // MOV L,B
case 0x69: c->l = c->c; break; // MOV L,C
case 0x6A: c->l = c->d; break; // MOV L,D
case 0x6B: c->l = c->e; break; // MOV L,E
case 0x6C: c->l = c->h; break; // MOV L,H
case 0x6D: c->l = c->l; break; // MOV L,L
case 0x6E: c->l = i8080_rb(c, i8080_get_hl(c)); break; // MOV L,M
case 0x77: i8080_wb(c, i8080_get_hl(c), c->a); break; // MOV M,A
case 0x70: i8080_wb(c, i8080_get_hl(c), c->b); break; // MOV M,B
case 0x71: i8080_wb(c, i8080_get_hl(c), c->c); break; // MOV M,C
case 0x72: i8080_wb(c, i8080_get_hl(c), c->d); break; // MOV M,D
case 0x73: i8080_wb(c, i8080_get_hl(c), c->e); break; // MOV M,E
case 0x74: i8080_wb(c, i8080_get_hl(c), c->h); break; // MOV M,H
case 0x75: i8080_wb(c, i8080_get_hl(c), c->l); break; // MOV M,L
case 0x3E: c->a = i8080_next_byte(c); break; // MVI A,byte
case 0x06: c->b = i8080_next_byte(c); break; // MVI B,byte
case 0x0E: c->c = i8080_next_byte(c); break; // MVI C,byte
case 0x16: c->d = i8080_next_byte(c); break; // MVI D,byte
case 0x1E: c->e = i8080_next_byte(c); break; // MVI E,byte
case 0x26: c->h = i8080_next_byte(c); break; // MVI H,byte
case 0x2E: c->l = i8080_next_byte(c); break; // MVI L,byte
case 0x36:
i8080_wb(c, i8080_get_hl(c), i8080_next_byte(c));
break; // MVI M,byte
case 0x02: i8080_wb(c, i8080_get_bc(c), c->a); break; // STAX B
case 0x12: i8080_wb(c, i8080_get_de(c), c->a); break; // STAX D
case 0x32: i8080_wb(c, i8080_next_word(c), c->a); break; // STA word
case 0x01: i8080_set_bc(c, i8080_next_word(c)); break; // LXI B,word
case 0x11: i8080_set_de(c, i8080_next_word(c)); break; // LXI D,word
case 0x21: i8080_set_hl(c, i8080_next_word(c)); break; // LXI H,word
case 0x31: c->sp = i8080_next_word(c); break; // LXI SP,word
case 0x2A: i8080_set_hl(c, i8080_rw(c, i8080_next_word(c))); break; // LHLD
case 0x22: i8080_ww(c, i8080_next_word(c), i8080_get_hl(c)); break; // SHLD
case 0xF9: c->sp = i8080_get_hl(c); break; // SPHL
case 0xEB: i8080_xchg(c); break; // XCHG
case 0xE3: i8080_xthl(c); break; // XTHL
case 0x87: i8080_add(c, &c->a, c->a, 0); break; // ADD A
case 0x80: i8080_add(c, &c->a, c->b, 0); break; // ADD B
case 0x81: i8080_add(c, &c->a, c->c, 0); break; // ADD C
case 0x82: i8080_add(c, &c->a, c->d, 0); break; // ADD D
case 0x83: i8080_add(c, &c->a, c->e, 0); break; // ADD E
case 0x84: i8080_add(c, &c->a, c->h, 0); break; // ADD H
case 0x85: i8080_add(c, &c->a, c->l, 0); break; // ADD L
case 0x86:
i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0);
break; // ADD M
case 0xC6: i8080_add(c, &c->a, i8080_next_byte(c), 0); break; // ADI byte
case 0x8F: i8080_add(c, &c->a, c->a, c->cf); break; // ADC A
case 0x88: i8080_add(c, &c->a, c->b, c->cf); break; // ADC B
case 0x89: i8080_add(c, &c->a, c->c, c->cf); break; // ADC C
case 0x8A: i8080_add(c, &c->a, c->d, c->cf); break; // ADC D
case 0x8B: i8080_add(c, &c->a, c->e, c->cf); break; // ADC E
case 0x8C: i8080_add(c, &c->a, c->h, c->cf); break; // ADC H
case 0x8D: i8080_add(c, &c->a, c->l, c->cf); break; // ADC L
case 0x8E:
i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf);
break; // ADC M
case 0xCE: i8080_add(c, &c->a, i8080_next_byte(c), c->cf); break; // ACI byte
case 0x97: i8080_sub(c, &c->a, c->a, 0); break; // SUB A
case 0x90: i8080_sub(c, &c->a, c->b, 0); break; // SUB B
case 0x91: i8080_sub(c, &c->a, c->c, 0); break; // SUB C
case 0x92: i8080_sub(c, &c->a, c->d, 0); break; // SUB D
case 0x93: i8080_sub(c, &c->a, c->e, 0); break; // SUB E
case 0x94: i8080_sub(c, &c->a, c->h, 0); break; // SUB H
case 0x95: i8080_sub(c, &c->a, c->l, 0); break; // SUB L
case 0x96:
i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0);
break; // SUB M
case 0xD6: i8080_sub(c, &c->a, i8080_next_byte(c), 0); break; // SUI byte
case 0x9F: i8080_sub(c, &c->a, c->a, c->cf); break; // SBB A
case 0x98: i8080_sub(c, &c->a, c->b, c->cf); break; // SBB B
case 0x99: i8080_sub(c, &c->a, c->c, c->cf); break; // SBB C
case 0x9A: i8080_sub(c, &c->a, c->d, c->cf); break; // SBB D
case 0x9B: i8080_sub(c, &c->a, c->e, c->cf); break; // SBB E
case 0x9C: i8080_sub(c, &c->a, c->h, c->cf); break; // SBB H
case 0x9D: i8080_sub(c, &c->a, c->l, c->cf); break; // SBB L
case 0x9E:
i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf);
break; // SBB M
case 0xDE: i8080_sub(c, &c->a, i8080_next_byte(c), c->cf); break; // SBI byte
case 0x09: i8080_dad(c, i8080_get_bc(c)); break; // DAD B
case 0x19: i8080_dad(c, i8080_get_de(c)); break; // DAD D
case 0x29: i8080_dad(c, i8080_get_hl(c)); break; // DAD H
case 0x39: i8080_dad(c, c->sp); break; // DAD SP
case 0xF3: c->iff = 0; break; // DI
case 0xFB:
c->iff = 1;
c->interrupt_delay = 1;
break; // EI
case 0x00: break; // NOP
case 0x76: c->halted = 1; break; // HLT
case 0x3C: c->a = i8080_inr(c, c->a); break; // INR A
case 0x04: c->b = i8080_inr(c, c->b); break; // INR B
case 0x0C: c->c = i8080_inr(c, c->c); break; // INR C
case 0x14: c->d = i8080_inr(c, c->d); break; // INR D
case 0x1C: c->e = i8080_inr(c, c->e); break; // INR E
case 0x24: c->h = i8080_inr(c, c->h); break; // INR H
case 0x2C: c->l = i8080_inr(c, c->l); break; // INR L
case 0x34:
i8080_wb(c, i8080_get_hl(c), i8080_inr(c, i8080_rb(c, i8080_get_hl(c))));
break; // INR M
case 0x3D: c->a = i8080_dcr(c, c->a); break; // DCR A
case 0x05: c->b = i8080_dcr(c, c->b); break; // DCR B
case 0x0D: c->c = i8080_dcr(c, c->c); break; // DCR C
case 0x15: c->d = i8080_dcr(c, c->d); break; // DCR D
case 0x1D: c->e = i8080_dcr(c, c->e); break; // DCR E
case 0x25: c->h = i8080_dcr(c, c->h); break; // DCR H
case 0x2D: c->l = i8080_dcr(c, c->l); break; // DCR L
case 0x35:
i8080_wb(c, i8080_get_hl(c), i8080_dcr(c, i8080_rb(c, i8080_get_hl(c))));
break; // DCR M
case 0x03: i8080_set_bc(c, i8080_get_bc(c) + 1); break; // INX B
case 0x13: i8080_set_de(c, i8080_get_de(c) + 1); break; // INX D
case 0x23: i8080_set_hl(c, i8080_get_hl(c) + 1); break; // INX H
case 0x33: c->sp += 1; break; // INX SP
case 0x0B: i8080_set_bc(c, i8080_get_bc(c) - 1); break; // DCX B
case 0x1B: i8080_set_de(c, i8080_get_de(c) - 1); break; // DCX D
case 0x2B: i8080_set_hl(c, i8080_get_hl(c) - 1); break; // DCX H
case 0x3B: c->sp -= 1; break; // DCX SP
case 0x27: i8080_daa(c); break; // DAA
case 0x2F: c->a = ~c->a; break; // CMA
case 0x37: c->cf = 1; break; // STC
case 0x3F: c->cf = !c->cf; break; // CMC
case 0x07: i8080_rlc(c); break; // RLC (rotate left)
case 0x0F: i8080_rrc(c); break; // RRC (rotate right)
case 0x17: i8080_ral(c); break; // RAL
case 0x1F: i8080_rar(c); break; // RAR
case 0xA7: i8080_ana(c, c->a); break; // ANA A
case 0xA0: i8080_ana(c, c->b); break; // ANA B
case 0xA1: i8080_ana(c, c->c); break; // ANA C
case 0xA2: i8080_ana(c, c->d); break; // ANA D
case 0xA3: i8080_ana(c, c->e); break; // ANA E
case 0xA4: i8080_ana(c, c->h); break; // ANA H
case 0xA5: i8080_ana(c, c->l); break; // ANA L
case 0xA6: i8080_ana(c, i8080_rb(c, i8080_get_hl(c))); break; // ANA M
case 0xE6: i8080_ana(c, i8080_next_byte(c)); break; // ANI byte
case 0xAF: i8080_xra(c, c->a); break; // XRA A
case 0xA8: i8080_xra(c, c->b); break; // XRA B
case 0xA9: i8080_xra(c, c->c); break; // XRA C
case 0xAA: i8080_xra(c, c->d); break; // XRA D
case 0xAB: i8080_xra(c, c->e); break; // XRA E
case 0xAC: i8080_xra(c, c->h); break; // XRA H
case 0xAD: i8080_xra(c, c->l); break; // XRA L
case 0xAE: i8080_xra(c, i8080_rb(c, i8080_get_hl(c))); break; // XRA M
case 0xEE: i8080_xra(c, i8080_next_byte(c)); break; // XRI byte
case 0xB7: i8080_ora(c, c->a); break; // ORA A
case 0xB0: i8080_ora(c, c->b); break; // ORA B
case 0xB1: i8080_ora(c, c->c); break; // ORA C
case 0xB2: i8080_ora(c, c->d); break; // ORA D
case 0xB3: i8080_ora(c, c->e); break; // ORA E
case 0xB4: i8080_ora(c, c->h); break; // ORA H
case 0xB5: i8080_ora(c, c->l); break; // ORA L
case 0xB6: i8080_ora(c, i8080_rb(c, i8080_get_hl(c))); break; // ORA M
case 0xF6: i8080_ora(c, i8080_next_byte(c)); break; // ORI byte
case 0xBF: i8080_cmp(c, c->a); break; // CMP A
case 0xB8: i8080_cmp(c, c->b); break; // CMP B
case 0xB9: i8080_cmp(c, c->c); break; // CMP C
case 0xBA: i8080_cmp(c, c->d); break; // CMP D
case 0xBB: i8080_cmp(c, c->e); break; // CMP E
case 0xBC: i8080_cmp(c, c->h); break; // CMP H
case 0xBD: i8080_cmp(c, c->l); break; // CMP L
case 0xBE: i8080_cmp(c, i8080_rb(c, i8080_get_hl(c))); break; // CMP M
case 0xFE: i8080_cmp(c, i8080_next_byte(c)); break; // CPI byte
case 0xC3: i8080_jmp(c, i8080_next_word(c)); break; // JMP
case 0xC2: i8080_cond_jmp(c, c->zf == 0); break; // JNZ
case 0xCA: i8080_cond_jmp(c, c->zf == 1); break; // JZ
case 0xD2: i8080_cond_jmp(c, c->cf == 0); break; // JNC
case 0xDA: i8080_cond_jmp(c, c->cf == 1); break; // JC
case 0xE2: i8080_cond_jmp(c, c->pf == 0); break; // JPO
case 0xEA: i8080_cond_jmp(c, c->pf == 1); break; // JPE
case 0xF2: i8080_cond_jmp(c, c->sf == 0); break; // JP
case 0xFA: i8080_cond_jmp(c, c->sf == 1); break; // JM
case 0xE9: c->pc = i8080_get_hl(c); break; // PCHL
case 0xCD: i8080_call(c, i8080_next_word(c)); break; // CALL
case 0xC4: i8080_cond_call(c, c->zf == 0); break; // CNZ
case 0xCC: i8080_cond_call(c, c->zf == 1); break; // CZ
case 0xD4: i8080_cond_call(c, c->cf == 0); break; // CNC
case 0xDC: i8080_cond_call(c, c->cf == 1); break; // CC
case 0xE4: i8080_cond_call(c, c->pf == 0); break; // CPO
case 0xEC: i8080_cond_call(c, c->pf == 1); break; // CPE
case 0xF4: i8080_cond_call(c, c->sf == 0); break; // CP
case 0xFC: i8080_cond_call(c, c->sf == 1); break; // CM
case 0xC9: i8080_ret(c); break; // RET
case 0xC0: i8080_cond_ret(c, c->zf == 0); break; // RNZ
case 0xC8: i8080_cond_ret(c, c->zf == 1); break; // RZ
case 0xD0: i8080_cond_ret(c, c->cf == 0); break; // RNC
case 0xD8: i8080_cond_ret(c, c->cf == 1); break; // RC
case 0xE0: i8080_cond_ret(c, c->pf == 0); break; // RPO
case 0xE8: i8080_cond_ret(c, c->pf == 1); break; // RPE
case 0xF0: i8080_cond_ret(c, c->sf == 0); break; // RP
case 0xF8: i8080_cond_ret(c, c->sf == 1); break; // RM
case 0xC7: i8080_call(c, 0x00); break; // RST 0
case 0xCF: i8080_call(c, 0x08); break; // RST 1
case 0xD7: i8080_call(c, 0x10); break; // RST 2
case 0xDF: i8080_call(c, 0x18); break; // RST 3
case 0xE7: i8080_call(c, 0x20); break; // RST 4
case 0xEF: i8080_call(c, 0x28); break; // RST 5
case 0xF7: i8080_call(c, 0x30); break; // RST 6
case 0xFF: i8080_call(c, 0x38); break; // RST 7
case 0xC5: i8080_push_stack(c, i8080_get_bc(c)); break; // PUSH B
case 0xD5: i8080_push_stack(c, i8080_get_de(c)); break; // PUSH D
case 0xE5: i8080_push_stack(c, i8080_get_hl(c)); break; // PUSH H
case 0xF5: i8080_push_psw(c); break; // PUSH PSW
case 0xC1: i8080_set_bc(c, i8080_pop_stack(c)); break; // POP B
case 0xD1: i8080_set_de(c, i8080_pop_stack(c)); break; // POP D
case 0xE1: i8080_set_hl(c, i8080_pop_stack(c)); break; // POP H
case 0xF1: i8080_pop_psw(c); break; // POP PSW
case 0xDB: c->a = c->port_in(c->userdata, i8080_next_byte(c)); break; // IN
case 0xD3: c->port_out(c->userdata, i8080_next_byte(c), c->a); break; // OUT
case 0x08:
case 0x10:
case 0x18:
case 0x20:
case 0x28:
case 0x30:
case 0x38: break; // undocumented NOPs
case 0xD9: i8080_ret(c); break; // undocumented RET
case 0xDD:
case 0xED:
{
if (opcode == 0xED) {
uint8_t data = i8080_next_byte(c);
if (data == 0xED) {
interrupt_808x(i8080_next_byte(c));
break;
} else if (data == 0xFD) {
retem_i8080();
break;
}
else {
i8080_call(c, (i8080_next_byte(c) << 8) | data); break;
}
}
}
case 0xFD: i8080_call(c, i8080_next_word(c)); break; // undocumented CALLs
case 0xCB: i8080_jmp(c, i8080_next_word(c)); break; // undocumented JMP
}
}
// initialises the emulator with default values
void i8080_init(i8080* const c) {
c->read_byte = NULL;
c->write_byte = NULL;
c->port_in = NULL;
c->port_out = NULL;
c->userdata = NULL;
c->cyc = 0;
c->pc = 0;
c->sp = 0;
c->a = 0;
c->b = 0;
c->c = 0;
c->d = 0;
c->e = 0;
c->h = 0;
c->l = 0;
c->sf = 0;
c->zf = 0;
c->hf = 0;
c->pf = 0;
c->cf = 0;
c->iff = 0;
c->halted = 0;
c->interrupt_pending = 0;
c->interrupt_vector = 0;
c->interrupt_delay = 0;
}
// executes one instruction
void i8080_step(i8080* const c) {
// interrupt processing: if an interrupt is pending and IFF is set,
// we execute the interrupt vector passed by the user.
if (c->interrupt_pending && c->iff && c->interrupt_delay == 0) {
c->interrupt_pending = 0;
c->iff = 0;
c->halted = 0;
i8080_execute(c, c->interrupt_vector);
} else if (!c->halted) {
i8080_execute(c, i8080_next_byte(c));
}
}
// asks for an interrupt to be serviced
void i8080_interrupt(i8080* const c, uint8_t opcode) {
c->interrupt_pending = 1;
c->interrupt_vector = opcode;
}
// outputs a debug trace of the emulator state to the standard output,
// including registers and flags
void i8080_debug_output(i8080* const c, bool print_disassembly) {
uint8_t f = 0;
f |= c->sf << 7;
f |= c->zf << 6;
f |= c->hf << 4;
f |= c->pf << 2;
f |= 1 << 1; // bit 1 is always 1
f |= c->cf << 0;
printf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, CYC: %lu",
c->pc, c->a << 8 | f, i8080_get_bc(c), i8080_get_de(c), i8080_get_hl(c),
c->sp, c->cyc);
printf("\t(%02X %02X %02X %02X)", i8080_rb(c, c->pc), i8080_rb(c, c->pc + 1),
i8080_rb(c, c->pc + 2), i8080_rb(c, c->pc + 3));
if (print_disassembly) {
printf(" - %s", DISASSEMBLE_TABLE[i8080_rb(c, c->pc)]);
}
printf("\n");
}
#undef SET_ZSP

35
src/cpu/i8080.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef I8080_I8080_H_
#define I8080_I8080_H_
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct i8080 {
// memory + io interface
uint8_t (*read_byte)(void*, uint16_t); // user function to read from memory
void (*write_byte)(void*, uint16_t, uint8_t); // same for writing to memory
uint8_t (*read_byte_seg)(void*, uint16_t); // user function to read from memory (Code segment)
uint8_t (*port_in)(void*, uint8_t); // user function to read from port
void (*port_out)(void*, uint8_t, uint8_t); // same for writing to port
void* userdata; // user custom pointer
unsigned long cyc; // cycle count
uint16_t pc, sp; // program counter, stack pointer
uint8_t a, b, c, d, e, h, l; // registers
// flags: sign, zero, half-carry, parity, carry, interrupt flip-flop
bool sf : 1, zf : 1, hf : 1, pf : 1, cf : 1, iff : 1;
bool halted : 1;
bool interrupt_pending : 1;
uint8_t interrupt_vector;
uint8_t interrupt_delay;
} i8080;
void i8080_init(i8080* const c);
void i8080_step(i8080* const c);
void i8080_interrupt(i8080* const c, uint8_t opcode);
void i8080_debug_output(i8080* const c, bool print_disassembly);
#endif // I8080_I8080_H_

View File

@@ -113,7 +113,17 @@ static scconvtbl scconv55_8a[18 + 1] =
void
keyboard_init(void)
{
num_lock = 0;
caps_lock = 0;
scroll_lock = 0;
shift = 0;
memset(recv_key, 0x00, sizeof(recv_key));
memset(recv_key_ui, 0x00, sizeof(recv_key));
memset(oldkey, 0x00, sizeof(recv_key));
#if 0
memset(key_delay, 0x00, sizeof(recv_key));
#endif
keyboard_scan = 1;
scan_table = NULL;

View File

@@ -999,7 +999,8 @@ void
serial_standalone_init(void)
{
while (next_inst < SERIAL_MAX)
device_add_inst(&ns8250_device, next_inst + 1);
device_add_inst(!strcmp(machine_get_internal_name(), "if386sx") ? &ns16450_device :
&ns8250_device, next_inst + 1);
};
const device_t ns8250_device = {

View File

@@ -88,18 +88,20 @@ static const joystick_if_t joystick_none = {
static const struct {
const joystick_if_t *joystick;
} joysticks[] = {
{ &joystick_none },
{ &joystick_2axis_2button },
{ &joystick_2axis_4button },
{ &joystick_2axis_6button },
{ &joystick_2axis_8button },
{ &joystick_3axis_2button },
{ &joystick_3axis_4button },
{ &joystick_4axis_4button },
{ &joystick_ch_flightstick_pro },
{ &joystick_sw_pad },
{ &joystick_tm_fcs },
{ NULL }
{ &joystick_none },
{ &joystick_2axis_2button },
{ &joystick_2axis_4button },
{ &joystick_2axis_6button },
{ &joystick_2axis_8button },
{ &joystick_3axis_2button },
{ &joystick_3axis_4button },
{ &joystick_4axis_4button },
{ &joystick_ch_flightstick_pro },
{ &joystick_ch_flightstick_pro_ch_pedals },
{ &joystick_sw_pad },
{ &joystick_tm_fcs },
{ &joystick_tm_fcs_rcs },
{ NULL }
};
static joystick_instance_t *joystick_instance[GAMEPORT_MAX] = { NULL, NULL };

View File

@@ -112,6 +112,26 @@ ch_flightstick_pro_read_axis(UNUSED(void *priv), int axis)
}
}
static int
ch_flightstick_pro_ch_pedals_read_axis(UNUSED(void *priv), int axis)
{
if (!JOYSTICK_PRESENT(0, 0))
return AXIS_NOT_PRESENT;
switch (axis) {
case 0:
return joystick_state[0][0].axis[0];
case 1:
return joystick_state[0][0].axis[1];
case 2:
return joystick_state[0][0].axis[3];
case 3:
return joystick_state[0][0].axis[2];
default:
return 0;
}
}
static void
ch_flightstick_pro_a0_over(UNUSED(void *priv))
{
@@ -135,3 +155,21 @@ const joystick_if_t joystick_ch_flightstick_pro = {
.button_names = { "Button 1", "Button 2", "Button 3", "Button 4" },
.pov_names = { "POV" }
};
const joystick_if_t joystick_ch_flightstick_pro_ch_pedals = {
.name = "CH Flightstick Pro + CH Pedals",
.internal_name = "ch_flightstick_pro_ch_pedals",
.init = ch_flightstick_pro_init,
.close = ch_flightstick_pro_close,
.read = ch_flightstick_pro_read,
.write = ch_flightstick_pro_write,
.read_axis = ch_flightstick_pro_ch_pedals_read_axis,
.a0_over = ch_flightstick_pro_a0_over,
.axis_count = 4,
.button_count = 4,
.pov_count = 1,
.max_joysticks = 1,
.axis_names = { "X axis", "Y axis", "Throttle", "Rudder" },
.button_names = { "Button 1", "Button 2", "Button 3", "Button 4" },
.pov_names = { "POV" }
};

View File

@@ -112,6 +112,36 @@ tm_fcs_read_axis(UNUSED(void *priv), int axis)
}
}
static int
tm_fcs_rcs_read_axis(UNUSED(void *priv), int axis)
{
if (!JOYSTICK_PRESENT(0, 0))
return AXIS_NOT_PRESENT;
switch (axis) {
case 0:
return joystick_state[0][0].axis[0];
case 1:
return joystick_state[0][0].axis[1];
case 2:
return joystick_state[0][0].axis[2];
case 3:
if (joystick_state[0][0].pov[0] == -1)
return 32767;
if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45)
return -32768;
if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135)
return -16384;
if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225)
return 0;
if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315)
return 16384;
return 0;
default:
return 0;
}
}
static void
tm_fcs_a0_over(UNUSED(void *priv))
{
@@ -135,3 +165,21 @@ const joystick_if_t joystick_tm_fcs = {
.button_names = { "Button 1", "Button 2", "Button 3", "Button 4" },
.pov_names = { "POV" }
};
const joystick_if_t joystick_tm_fcs_rcs = {
.name = "Thrustmaster FCS + Rudder Control System",
.internal_name = "thrustmaster_fcs_rcs",
.init = tm_fcs_init,
.close = tm_fcs_close,
.read = tm_fcs_read,
.write = tm_fcs_write,
.read_axis = tm_fcs_rcs_read_axis,
.a0_over = tm_fcs_a0_over,
.axis_count = 3,
.button_count = 4,
.pov_count = 1,
.max_joysticks = 1,
.axis_names = { "X axis", "Y axis", "Rudder" },
.button_names = { "Button 1", "Button 2", "Button 3", "Button 4" },
.pov_names = { "POV" }
};

View File

@@ -118,7 +118,6 @@ extern int vid_resize; /* (C) allow resizing */
extern int invert_display; /* (C) invert the display */
extern int suppress_overscan; /* (C) suppress overscans */
extern uint32_t lang_id; /* (C) language code identifier */
extern char icon_set[256]; /* (C) iconset identifier */
extern int scale; /* (C) screen scale factor */
extern int dpi_scale; /* (C) DPI scaling of the emulated screen */
extern int vid_api; /* (C) video renderer */

View File

@@ -179,10 +179,12 @@ extern const joystick_if_t joystick_2axis_6button;
extern const joystick_if_t joystick_2axis_8button;
extern const joystick_if_t joystick_ch_flightstick_pro;
extern const joystick_if_t joystick_ch_flightstick_pro_ch_pedals;
extern const joystick_if_t joystick_sw_pad;
extern const joystick_if_t joystick_tm_fcs;
extern const joystick_if_t joystick_tm_fcs_rcs;
extern int gameport_available(int);
extern int gameport_has_config(int);

View File

@@ -1,69 +0,0 @@
/*
* 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.
*
* 8080 CPU emulation (header).
*
*
*
* Authors: Cacodemon345
*
* Copyright 2022 Cacodemon345
*/
#include <stdint.h>
typedef struct i8080 {
union {
uint16_t af; /* Intended in case we also go for μPD9002 emulation, which also has a Z80 emulation mode. */
struct {
uint8_t a;
uint8_t flags;
};
};
union {
uint16_t bc;
struct {
uint8_t b;
uint8_t c;
};
};
union {
uint16_t de;
struct {
uint8_t d;
uint8_t e;
};
};
union {
uint16_t hl;
struct {
uint8_t h;
uint8_t l;
};
};
uint16_t pc;
uint16_t sp;
uint16_t oldpc;
uint16_t ei;
uint32_t pmembase;
uint32_t dmembase; /* Base from where i8080 starts. */
uint8_t emulated; /* 0 = not emulated, use separate registers, 1 = emulated, use x86 registers. */
uint16_t *cpu_flags;
void (*writemembyte)(uint32_t, uint8_t);
uint8_t (*readmembyte)(uint32_t);
void (*startclock)(void);
void (*endclock)(void);
void (*checkinterrupts)(void);
uint8_t (*fetchinstruction)(void *);
} i8080;
#define C_FLAG_I8080 (1 << 0)
#define P_FLAG_I8080 (1 << 2)
#define AC_FLAG_I8080 (1 << 4)
#define Z_FLAG_I8080 (1 << 6)
#define S_FLAG_I8080 (1 << 7)

View File

@@ -18,6 +18,12 @@
#ifndef VIDEO_8514A_H
#define VIDEO_8514A_H
#define INT_VSY (1 << 0)
#define INT_GE_BSY (1 << 1)
#define INT_FIFO_OVR (1 << 2)
#define INT_FIFO_EMP (1 << 3)
#define INT_MASK 0xf
typedef struct hwcursor8514_t {
int ena;
int x;
@@ -61,6 +67,7 @@ typedef struct ibm8514_t {
uint32_t vram_mask;
uint32_t pallook[512];
uint32_t bios_addr;
uint32_t ma_latch;
PALETTE vgapal;
uint8_t hwcursor_oddeven;
@@ -85,8 +92,8 @@ typedef struct ibm8514_t {
uint16_t advfunc_cntl;
uint16_t cur_y;
uint16_t cur_x;
int16_t destx;
int16_t desty;
uint16_t destx;
uint16_t desty;
int16_t desty_axstp;
int16_t destx_distp;
int16_t err_term;
@@ -117,6 +124,8 @@ typedef struct ibm8514_t {
int y1;
int y2;
int temp_cnt;
int16_t dx_ibm;
int16_t dy_ibm;
int16_t cx;
int16_t cx_back;
int16_t cy;
@@ -216,10 +225,9 @@ typedef struct ibm8514_t {
uint16_t subsys_cntl;
uint8_t subsys_stat;
atomic_int fifo_idx;
atomic_int ext_fifo_idx;
atomic_int force_busy;
atomic_int force_busy2;
atomic_int fifo_idx;
int blitter_busy;
uint64_t blitter_time;
@@ -235,6 +243,11 @@ typedef struct ibm8514_t {
PALETTE _8514pal;
latch8514_t latch;
void (*vblank_start)(void *priv);
void (*accel_out_fifo)(void *priv, uint16_t port, uint16_t val, int len);
void (*update_irqs)(void *priv);
} ibm8514_t;
#endif /*VIDEO_8514A_H*/

View File

@@ -25,6 +25,7 @@ typedef struct mach_t {
rom_t bios_rom;
rom_t bios_rom2;
mem_mapping_t mmio_linear_mapping;
mem_mapping_t banked_mapping;
int mca_bus;
int pci_bus;
@@ -71,7 +72,12 @@ typedef struct mach_t {
uint8_t bank_r;
uint16_t shadow_set;
uint16_t shadow_cntl;
int override_resolution;
uint8_t overscan_col_8;
uint8_t overscan_b_col_24;
uint8_t overscan_g_col_24;
uint8_t overscan_r_col_24;
uint16_t fifo_test_data[17];
int resolution_crt;
struct {
uint8_t line_idx;
@@ -79,9 +85,9 @@ typedef struct mach_t {
uint8_t patt_idx;
uint8_t patt_len;
uint8_t pix_trans[2];
uint8_t eeprom_control;
uint8_t alu_bg_fn;
uint8_t alu_fg_fn;
uint16_t eeprom_control;
uint16_t clip_left;
uint16_t clip_right;
uint16_t clip_top;
@@ -92,6 +98,7 @@ typedef struct mach_t {
uint16_t src_x_end;
uint16_t src_x_start;
uint16_t src_x;
uint16_t r_src_x;
uint16_t src_y;
int16_t bres_count;
uint16_t clock_sel;
@@ -100,6 +107,8 @@ typedef struct mach_t {
uint16_t dest_cmp_fn;
uint16_t dp_config;
uint16_t ext_ge_config;
uint16_t crt_offset_lo;
uint16_t crt_offset_hi;
uint16_t ge_offset_lo;
uint16_t ge_offset_hi;
uint16_t linedraw_opt;
@@ -159,6 +168,7 @@ typedef struct mach_t {
} accel;
atomic_int force_busy;
atomic_int fifo_test_idx;
} mach_t;
#endif /*VIDEO_ATI_MACH8_H*/

View File

@@ -144,10 +144,10 @@ typedef struct ega_t {
uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr);
void (*render)(struct ega_t *svga);
/*If set then another device is driving the monitor output and the EGA
card should not attempt to display anything */
void (*render_override)(void *priv);
void *priv_parent;
/* If set then another device is driving the monitor output and the EGA
card should not attempt to display anything. */
void (*render_override)(void *priv);
void * priv_parent;
} ega_t;
#endif
@@ -159,6 +159,7 @@ extern const device_t atiega800p_device;
extern const device_t iskra_ega_device;
extern const device_t et2000_device;
extern const device_t jega_device;
extern const device_t jvga_device;
#endif
extern int update_overscan;

View File

@@ -310,6 +310,11 @@ typedef struct svga_t {
void * ext8514;
void * clock_gen8514;
void * xga;
/* If set then another device is driving the monitor output and the EGA
card should not attempt to display anything. */
void (*render_override)(void *priv);
void * priv_parent;
} svga_t;
extern void ibm8514_set_poll(svga_t *svga);

View File

@@ -25,14 +25,19 @@
typedef struct vga_t {
svga_t svga;
rom_t bios_rom;
rom_t bios_rom;
} vga_t;
extern void vga_out(uint16_t addr, uint8_t val, void *priv);
extern void vga_out(uint16_t addr, uint8_t val, void *priv);
extern uint8_t vga_in(uint16_t addr, void *priv);
void vga_disable(void* p);
void vga_enable(void* p);
int vga_isenabled(void* p);
extern void vga_init(const device_t *info, vga_t *vga, int enabled);
extern void vga_disable(void* p);
extern void vga_enable(void* p);
extern int vga_isenabled(void* p);
extern video_timings_t timing_vga;
#endif /*VIDEO_VGA_H*/

View File

@@ -6981,46 +6981,6 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* has a Phoenix PLCC Multikey copyrighted 1993, version unknown. */
{
.name = "[OPTi 895] Packard Bell PB450",
.internal_name = "pb450",
.type = MACHINE_TYPE_486_S3_PCI,
.chipset = MACHINE_CHIPSET_OPTI_895_802G,
.init = machine_at_pb450_init,
.p1_handler = NULL,
.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_PCI,
.flags = MACHINE_SUPER_IO | MACHINE_IDE_DUAL | MACHINE_VIDEO,
.ram = {
.min = 1024,
.max = 65536,
.step = 1024
},
.nvrmask = 255,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = &pb450_device,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &gd5428_vlb_onboard_device,
.snd_device = NULL,
.net_device = NULL
},
/* Uses an NEC 90M002A (UPD82C42C, 8042 clone) with unknown firmware. */
{
.name = "[SiS 461] Acer V10",
@@ -7915,6 +7875,46 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* has a Phoenix PLCC Multikey copyrighted 1993, version unknown. */
{
.name = "[OPTi 895] Packard Bell PB450",
.internal_name = "pb450",
.type = MACHINE_TYPE_486_S3_PCI,
.chipset = MACHINE_CHIPSET_OPTI_895_802G,
.init = machine_at_pb450_init,
.p1_handler = NULL,
.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_PCI,
.flags = MACHINE_SUPER_IO | MACHINE_IDE_DUAL | MACHINE_VIDEO,
.ram = {
.min = 1024,
.max = 65536,
.step = 1024
},
.nvrmask = 255,
.kbc_device = NULL,
.kbc_p1 = 0xff,
.gpio = 0xffffffff,
.gpio_acpi = 0xffffffff,
.device = &pb450_device,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &gd5428_vlb_onboard_device,
.snd_device = NULL,
.net_device = NULL
},
/* This has an AMIKey-2, which is an updated version of type 'H'. */
{
.name = "[i420EX] ASUS PVI-486AP4",
@@ -8902,7 +8902,7 @@ const machine_t machines[] = {
.min_multi = 0,
.max_multi = 0
},
.bus_flags = MACHINE_PCI,
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_SOUND | MACHINE_APM,
.ram = {
.min = 1024,
@@ -9358,7 +9358,7 @@ const machine_t machines[] = {
.min_multi = MACHINE_MULTIPLIER_FIXED,
.max_multi = MACHINE_MULTIPLIER_FIXED
},
.bus_flags = MACHINE_PCI,
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE | MACHINE_APM,
.ram = {
.min = 2048,

View File

@@ -194,6 +194,9 @@ add_library(ui STATIC
qt_openglshaderconfig.hpp
qt_openglshaderconfig.cpp
qt_openglshaderconfig.ui
qt_iconindicators.hpp
qt_iconindicators.cpp
)
if(RTMIDI)

BIN
src/qt/icons/active.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

BIN
src/qt/icons/disabled.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -35,8 +35,6 @@ qt_nvr_save(void)
return nvr_save();
}
char icon_set[256] = ""; /* name of the iconset to be used */
int
plat_vidapi(const char *api)
{

View File

@@ -0,0 +1,33 @@
#include <QSize>
#include <QPainter>
#include "qt_iconindicators.hpp"
QIcon
getIndicatorIcon(IconIndicator indicator)
{
switch (indicator) {
case Active:
return QIcon(":/settings/qt/icons/active.ico");
case Disabled:
return QIcon(":/settings/qt/icons/disabled.ico");
default:
return QIcon();
}
}
QPixmap
getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator)
{
auto iconPixmap = icon.pixmap(size, iconMode);
if (indicator == None)
return iconPixmap;
auto painter = QPainter(&iconPixmap);
auto indicatorPixmap = getIndicatorIcon(indicator).pixmap(size);
painter.drawPixmap(0, 0, indicatorPixmap);
painter.end();
return iconPixmap;
}

View File

@@ -0,0 +1,15 @@
#ifndef QT_ICONINDICATORS_HPP
# define QT_INDICATORS_HPP
#include <QPixmap>
#include <QIcon>
enum IconIndicator {
None,
Active,
Disabled,
};
QPixmap getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator);
#endif

View File

@@ -54,6 +54,7 @@ extern "C" {
#include "qt_mainwindow.hpp"
#include "qt_soundgain.hpp"
#include "qt_progsettings.hpp"
#include "qt_iconindicators.hpp"
#include <array>
@@ -65,19 +66,24 @@ namespace {
struct PixmapSetActive {
QPixmap normal;
QPixmap active;
void load(const QString &basePath);
void load(const QIcon &icon);
};
struct PixmapSetDisabled {
QPixmap normal;
QPixmap disabled;
void load(const QIcon &icon);
};
struct PixmapSetEmpty {
QPixmap normal;
QPixmap empty;
void load(const QString &basePath);
void load(const QIcon &icon);
};
struct PixmapSetEmptyActive {
QPixmap normal;
QPixmap active;
QPixmap empty;
QPixmap empty_active;
void load(QString basePath);
void load(const QIcon &icon);
};
struct Pixmaps {
PixmapSetEmpty cartridge;
@@ -90,7 +96,7 @@ struct Pixmaps {
PixmapSetEmptyActive mo;
PixmapSetActive hd;
PixmapSetEmptyActive net;
QPixmap sound, soundMuted;
PixmapSetDisabled sound;
};
struct StateActive {
@@ -170,30 +176,35 @@ struct StateEmptyActive {
};
static QSize pixmap_size(16, 16);
static const QString pixmap_empty = QStringLiteral("_empty");
static const QString pixmap_active = QStringLiteral("_active");
static const QString pixmap_empty_active = QStringLiteral("_empty_active");
void
PixmapSetEmpty::load(const QString &basePath)
PixmapSetEmpty::load(const QIcon &icon)
{
normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size);
empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size);
normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None);
empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None);
}
void
PixmapSetActive::load(const QString &basePath)
PixmapSetActive::load(const QIcon &icon)
{
normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size);
active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size);
normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None);
active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active);
}
void
PixmapSetEmptyActive::load(QString basePath)
PixmapSetDisabled::load(const QIcon &icon)
{
normal = ProgSettings::loadIcon(basePath.arg(QStringLiteral(""))).pixmap(pixmap_size);
active = ProgSettings::loadIcon(basePath.arg(pixmap_active)).pixmap(pixmap_size);
empty = ProgSettings::loadIcon(basePath.arg(pixmap_empty)).pixmap(pixmap_size);
empty_active = ProgSettings::loadIcon(basePath.arg(pixmap_empty_active)).pixmap(pixmap_size);
normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None);
disabled = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Disabled);
}
void
PixmapSetEmptyActive::load(const QIcon &icon)
{
normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None);
active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active);
empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None);
empty_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Active);
}
}
@@ -202,21 +213,20 @@ struct MachineStatus::States {
States(QObject *parent)
{
pixmaps.cartridge.load("/cartridge%1.ico");
pixmaps.cassette.load("/cassette%1.ico");
pixmaps.floppy_disabled.normal = ProgSettings::loadIcon(QStringLiteral("/floppy_disabled.ico")).pixmap(pixmap_size);
pixmaps.cartridge.load(QIcon(":/settings/qt/icons/cartridge.ico"));
pixmaps.cassette.load(QIcon(":/settings/qt/icons/cassette.ico"));
pixmaps.floppy_disabled.normal = QIcon(":/settings/qt/icons/floppy_disabled.ico").pixmap(pixmap_size);
pixmaps.floppy_disabled.active = pixmaps.floppy_disabled.normal;
pixmaps.floppy_disabled.empty = pixmaps.floppy_disabled.normal;
pixmaps.floppy_disabled.empty_active = pixmaps.floppy_disabled.normal;
pixmaps.floppy_525.load("/floppy_525%1.ico");
pixmaps.floppy_35.load("/floppy_35%1.ico");
pixmaps.cdrom.load("/cdrom%1.ico");
pixmaps.zip.load("/zip%1.ico");
pixmaps.mo.load("/mo%1.ico");
pixmaps.hd.load("/hard_disk%1.ico");
pixmaps.net.load("/network%1.ico");
pixmaps.sound = ProgSettings::loadIcon("/sound.ico").pixmap(pixmap_size);
pixmaps.soundMuted = ProgSettings::loadIcon("/sound_mute.ico").pixmap(pixmap_size);
pixmaps.floppy_525.load(QIcon(":/settings/qt/icons/floppy_525.ico"));
pixmaps.floppy_35.load(QIcon(":/settings/qt/icons/floppy_35.ico"));
pixmaps.cdrom.load(QIcon(":/settings/qt/icons/cdrom.ico"));
pixmaps.zip.load(QIcon(":/settings/qt/icons/zip.ico"));
pixmaps.mo.load(QIcon(":/settings/qt/icons/mo.ico"));
pixmaps.hd.load(QIcon(":/settings/qt/icons/hard_disk.ico"));
pixmaps.net.load(QIcon(":/settings/qt/icons/network.ico"));
pixmaps.sound.load(QIcon(":/settings/qt/icons/sound.ico"));
cartridge[0].pixmaps = &pixmaps.cartridge;
cartridge[1].pixmaps = &pixmaps.cartridge;
@@ -510,8 +520,8 @@ MachineStatus::refresh(QStatusBar *sbar)
sound_muted ^= 1;
config_save();
if (d->sound)
d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound);
d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal);
muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute"));
});
}
@@ -694,10 +704,10 @@ MachineStatus::refresh(QStatusBar *sbar)
}
d->sound = std::make_unique<ClickableLabel>();
d->sound->setPixmap(sound_muted ? d->pixmaps.soundMuted : d->pixmaps.sound);
d->sound->setPixmap(sound_muted ? d->pixmaps.sound.disabled : d->pixmaps.sound.normal);
if (muteUnmuteAction)
muteUnmuteAction->setText(sound_muted ? tr("&Unmute") : tr("&Mute"));
connect(d->sound.get(), &ClickableLabel::clicked, this, [this](QPoint pos) {
this->soundMenu->popup(pos - QPoint(0, this->soundMenu->sizeHint().height()));
});

View File

@@ -94,6 +94,8 @@ extern int qt_nvr_save(void);
bool cpu_thread_running = false;
}
#include <locale.h>
void qt_set_sequence_auto_mnemonic(bool b);
#ifdef Q_OS_WINDOWS
@@ -525,6 +527,7 @@ main(int argc, char *argv[])
QApplication app(argc, argv);
QLocale::setDefault(QLocale::C);
setlocale(LC_NUMERIC, "C");
#ifdef Q_OS_WINDOWS
Q_INIT_RESOURCE(darkstyle);

View File

@@ -154,10 +154,10 @@ MediaMenu::refresh(QMenu *parentMenu)
MachineStatus::iterateCDROM([this, parentMenu](int i) {
auto *menu = parentMenu->addMenu("");
cdromMutePos = menu->children().count();
menu->addAction(ProgSettings::loadIcon("/cdrom_mute.ico"), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true);
menu->addAction(QIcon(":/settings/qt/icons/cdrom_mute.ico"), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true);
menu->addSeparator();
menu->addAction(ProgSettings::loadIcon("/cdrom_image.ico"), tr("&Image..."), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false);
menu->addAction(ProgSettings::loadIcon("/cdrom_folder.ico"), tr("&Folder..."), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false);
menu->addAction(QIcon(":/settings/qt/icons/cdrom_image.ico"), tr("&Image..."), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false);
menu->addAction(QIcon(":/settings/qt/icons/cdrom_folder.ico"), tr("&Folder..."), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false);
menu->addSeparator();
for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) {
cdromImageHistoryPos[slot] = menu->children().count();
@@ -170,7 +170,7 @@ MediaMenu::refresh(QMenu *parentMenu)
for (const auto &letter : driveLetters) {
auto drive = QString("%1:\\").arg(letter);
if (GetDriveType(drive.toUtf8().constData()) == DRIVE_CDROM)
menu->addAction(ProgSettings::loadIcon("/cdrom_host.ico"), tr("Host CD/DVD Drive (%1:)").arg(letter), [this, i, letter] { cdromMount(i, 2, QString(R"(\\.\%1:)").arg(letter)); })->setCheckable(false);
menu->addAction(QIcon(":/settings/qt/icons/cdrom_host.ico"), tr("Host CD/DVD Drive (%1:)").arg(letter), [this, i, letter] { cdromMount(i, 2, QString(R"(\\.\%1:)").arg(letter)); })->setCheckable(false);
}
menu->addSeparator();
#endif // Q_OS_WINDOWS
@@ -666,7 +666,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type)
children = menu->children();
imageHistoryUpdatePos = dynamic_cast<QAction *>(children[cdromImageHistoryPos[slot]]);
if (fn.left(8) == "ioctl://") {
menu_icon = ProgSettings::loadIcon("/cdrom_host.ico");
menu_icon = QIcon(":/settings/qt/icons/cdrom_host.ico");
#ifdef Q_OS_WINDOWS
menu_item_name = tr("Host CD/DVD Drive (%1)").arg(fn.right(2)).toUtf8().constData();
#else
@@ -674,7 +674,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type)
#endif
} else {
fi.setFile(fn);
menu_icon = fi.isDir() ? ProgSettings::loadIcon("/cdrom_folder.ico") : ProgSettings::loadIcon("/cdrom_image.ico");
menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico");
menu_item_name = fn.isEmpty() ? tr("previous image").toUtf8().constData() : fn.toUtf8().constData();
}
imageHistoryUpdatePos->setIcon(menu_icon);
@@ -727,7 +727,7 @@ MediaMenu::cdromUpdateMenu(int i)
auto childs = menu->children();
auto *muteMenu = dynamic_cast<QAction *>(childs[cdromMutePos]);
muteMenu->setIcon(ProgSettings::loadIcon((cdrom[i].sound_on == 0) ? "/cdrom_unmute.ico" : "/cdrom_mute.ico"));
muteMenu->setIcon(QIcon((cdrom[i].sound_on == 0) ? ":/settings/qt/icons/cdrom_unmute.ico" : ":/settings/qt/icons/cdrom_mute.ico"));
muteMenu->setText((cdrom[i].sound_on == 0) ? tr("&Unmute") : tr("&Mute"));
auto *imageMenu = dynamic_cast<QAction *>(childs[cdromImagePos]);
@@ -740,13 +740,13 @@ MediaMenu::cdromUpdateMenu(int i)
menu_item_name = tr("Host CD/DVD Drive (%1)").arg(name.right(name.length() - 8));
#endif
name2 = menu_item_name;
menu_icon = ProgSettings::loadIcon("/cdrom_host.ico");
menu_icon = QIcon(":/settings/qt/icons/cdrom_host.ico");
} else {
QFileInfo fi(cdrom[i].image_path);
menu_item_name = name.isEmpty() ? QString().toUtf8().constData() : name.toUtf8().constData();
name2 = name;
menu_icon = fi.isDir() ? ProgSettings::loadIcon("/cdrom_folder.ico") : ProgSettings::loadIcon("/cdrom_image.ico");
menu_icon = fi.isDir() ? QIcon(":/settings/qt/icons/cdrom_folder.ico") : QIcon(":/settings/qt/icons/cdrom_image.ico");
}
imageMenu->setIcon(menu_icon);
imageMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), menu_item_name.toUtf8().constData()));

View File

@@ -36,71 +36,16 @@ extern "C" {
#include <86box/rom.h>
}
static QMap<QString, QString> iconset_to_qt;
extern MainWindow *main_window;
ProgSettings::CustomTranslator *ProgSettings::translator = nullptr;
QTranslator *ProgSettings::qtTranslator = nullptr;
QString
ProgSettings::getIconSetPath()
{
if (iconset_to_qt.isEmpty()) {
// Always include default bundled icons
iconset_to_qt.insert("", ":/settings/qt/icons");
// Walk rom_paths to get the candidates
for (rom_path_t *emu_rom_path = &rom_paths; emu_rom_path != nullptr; emu_rom_path = emu_rom_path->next) {
// Check for icons subdir in each candidate
QDir roms_icons_dir(QString(emu_rom_path->path) + "/icons");
if (roms_icons_dir.isReadable()) {
auto dirList = roms_icons_dir.entryList(QDir::AllDirs | QDir::Executable | QDir::Readable);
for (auto &curIconSet : dirList) {
if (curIconSet == "." || curIconSet == "..") {
continue;
}
iconset_to_qt.insert(curIconSet, (roms_icons_dir.canonicalPath() + '/') + curIconSet);
}
}
}
}
return iconset_to_qt[icon_set];
}
QIcon
ProgSettings::loadIcon(QString file)
{
(void) getIconSetPath();
if (!QFile::exists(iconset_to_qt[icon_set] + file))
return QIcon(iconset_to_qt[""] + file);
return QIcon(iconset_to_qt[icon_set] + file);
}
ProgSettings::ProgSettings(QWidget *parent)
: QDialog(parent)
, ui(new Ui::ProgSettings)
{
ui->setupUi(this);
(void) getIconSetPath();
ui->comboBox->setItemData(0, "");
ui->comboBox->setCurrentIndex(0);
for (auto i = iconset_to_qt.begin(); i != iconset_to_qt.end(); i++) {
if (i.key() == "")
continue;
QFile iconfile(i.value() + "/iconinfo.txt");
iconfile.open(QFile::ReadOnly);
QString friendlyName;
QString iconsetinfo(iconfile.readAll());
iconfile.close();
if (iconsetinfo.isEmpty())
friendlyName = i.key();
else
friendlyName = iconsetinfo.split('\n')[0];
ui->comboBox->addItem(friendlyName, i.key());
if (strcmp(icon_set, i.key().toUtf8().data()) == 0) {
ui->comboBox->setCurrentIndex(ui->comboBox->findData(i.key()));
}
}
ui->comboBox->setItemData(0, '(' + tr("Default") + ')', Qt::DisplayRole);
ui->comboBoxLanguage->setItemData(0, 0xFFFF);
for (auto i = lcid_langcode.begin(); i != lcid_langcode.end(); i++) {
if (i.key() == 0xFFFF)
@@ -129,7 +74,6 @@ ProgSettings::ProgSettings(QWidget *parent)
void
ProgSettings::accept()
{
strcpy(icon_set, ui->comboBox->currentData().toString().toUtf8().data());
lang_id = ui->comboBoxLanguage->currentData().toUInt();
open_dir_usr_path = ui->openDirUsrPath->isChecked() ? 1 : 0;
confirm_exit = ui->checkBoxConfirmExit->isChecked() ? 1 : 0;
@@ -161,12 +105,6 @@ ProgSettings::~ProgSettings()
delete ui;
}
void
ProgSettings::on_pushButton_released()
{
ui->comboBox->setCurrentIndex(0);
}
#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. */

View File

@@ -14,8 +14,6 @@ class ProgSettings : public QDialog {
public:
explicit ProgSettings(QWidget *parent = nullptr);
~ProgSettings();
static QString getIconSetPath();
static QIcon loadIcon(QString file);
#ifdef Q_OS_WINDOWS
static QString getFontName(uint32_t lcid);
#endif
@@ -56,7 +54,6 @@ public:
protected slots:
void accept() override;
private slots:
void on_pushButton_released();
void on_pushButtonLanguage_released();
void on_horizontalSlider_valueChanged(int value);

View File

@@ -29,21 +29,14 @@
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetFixedSize</enum>
</property>
<item row="5" column="1">
<item row="2" column="1">
<widget class="QPushButton" name="pushButtonLanguage">
<property name="text">
<string>Default</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Icon set:</string>
</property>
</widget>
</item>
<item row="8" column="0">
<item row="5" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
@@ -56,7 +49,7 @@
</property>
</spacer>
</item>
<item row="4" column="0" colspan="2">
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="comboBoxLanguage">
<property name="maxVisibleItems">
<number>30</number>
@@ -68,7 +61,7 @@
</item>
</widget>
</item>
<item row="9" column="0">
<item row="6" column="0">
<widget class="QCheckBox" name="openDirUsrPath">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@@ -78,14 +71,7 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Default</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="2" column="0">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
@@ -98,14 +84,14 @@
</property>
</spacer>
</item>
<item row="8" column="1">
<item row="5" column="1">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Default</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<item row="4" column="0" colspan="3">
<widget class="QSlider" name="horizontalSlider">
<property name="minimum">
<number>10</number>
@@ -127,21 +113,21 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Language:</string>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="8" column="0">
<widget class="QCheckBox" name="checkBoxConfirmSave">
<property name="text">
<string>Ask for confirmation before saving settings</string>
</property>
</widget>
</item>
<item row="16" column="0" colspan="2">
<item row="13" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
@@ -151,63 +137,35 @@
</property>
</widget>
</item>
<item row="10" column="0">
<item row="7" column="0">
<widget class="QCheckBox" name="checkBoxMultimediaKeys">
<property name="text">
<string>Inhibit multimedia keys on Windows</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="comboBox">
<property name="editable">
<bool>false</bool>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
<item>
<property name="text">
<string>(Default)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Mouse sensitivity:</string>
</property>
</widget>
</item>
<item row="13" column="0">
<item row="10" column="0">
<widget class="QCheckBox" name="checkBoxConfirmHardReset">
<property name="text">
<string>Ask for confirmation before hard resetting</string>
</property>
</widget>
</item>
<item row="12" column="0">
<item row="9" column="0">
<widget class="QCheckBox" name="checkBoxConfirmExit">
<property name="text">
<string>Ask for confirmation before quitting</string>
</property>
</widget>
</item>
<item row="14" column="0">
<item row="11" column="0">
<widget class="QCheckBox" name="checkBoxFullscreenFirst">
<property name="text">
<string>Display hotkey message when entering full-screen mode</string>

View File

@@ -95,7 +95,7 @@ SettingsModel::data(const QModelIndex &index, int role) const
case Qt::DisplayRole:
return tr(pages.at(index.row()).toUtf8().data());
case Qt::DecorationRole:
return QIcon(QString("%1/%2.ico").arg(ProgSettings::getIconSetPath(), page_icons[index.row()]));
return QIcon(QString(":/settings/qt/icons/%1.ico").arg(page_icons[index.row()]));
case Qt::SizeHintRole:
return QSize(-1, fontHeight * 2);
default:

View File

@@ -46,11 +46,11 @@ setFloppyType(QAbstractItemModel *model, const QModelIndex &idx, int type)
{
QIcon icon;
if (type == 0)
icon = ProgSettings::loadIcon("/floppy_disabled.ico");
icon = QIcon(":/settings/qt/icons/floppy_disabled.ico");
else if (type >= 1 && type <= 6)
icon = ProgSettings::loadIcon("/floppy_525.ico");
icon = QIcon(":/settings/qt/icons/floppy_525.ico");
else
icon = ProgSettings::loadIcon("/floppy_35.ico");
icon = QIcon(":/settings/qt/icons/floppy_35.ico");
model->setData(idx, QObject::tr(fdd_getname(type)));
model->setData(idx, type, Qt::UserRole);
@@ -64,12 +64,12 @@ setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint
switch (bus) {
case CDROM_BUS_DISABLED:
icon = ProgSettings::loadIcon("/cdrom_disabled.ico");
icon = QIcon(":/settings/qt/icons/cdrom_disabled.ico");
break;
case CDROM_BUS_ATAPI:
case CDROM_BUS_SCSI:
case CDROM_BUS_MITSUMI:
icon = ProgSettings::loadIcon("/cdrom.ico");
icon = QIcon(":/settings/qt/icons/cdrom.ico");
break;
}

View File

@@ -81,7 +81,7 @@ addRow(QAbstractItemModel *model, hard_disk_t *hd)
QString busName = Harddrives::BusChannelName(hd->bus_type, hd->channel);
model->setData(model->index(row, ColumnBus), busName);
model->setData(model->index(row, ColumnBus), ProgSettings::loadIcon("/hard_disk.ico"), Qt::DecorationRole);
model->setData(model->index(row, ColumnBus), QIcon(":/settings/qt/icons/hard_disk.ico"), Qt::DecorationRole);
model->setData(model->index(row, ColumnBus), hd->bus_type, DataBus);
model->setData(model->index(row, ColumnBus), hd->bus_type, DataBusPrevious);
model->setData(model->index(row, ColumnBus), hd->channel, DataBusChannel);

View File

@@ -88,20 +88,31 @@ SettingsMachine::SettingsMachine(QWidget *parent)
ui->comboBoxPitMode->setCurrentIndex(-1);
ui->comboBoxPitMode->setCurrentIndex(pit_mode + 1);
int selectedMachineType = 0;
auto *machineTypesModel = ui->comboBoxMachineType->model();
for (int i = 1; i < MACHINE_TYPE_MAX; ++i) {
int j = 0;
while (machine_get_internal_name_ex(j) != nullptr) {
if (machine_available(j) && (machine_get_type(j) == i)) {
int selectedMachineType = 0;
auto * machineTypesModel = ui->comboBoxMachineType->model();
int i = -1;
int j = 0;
int cur_j = 0;
const void *miname;
do {
miname = machine_get_internal_name_ex(j);
if ((miname == nullptr) || (machine_get_type(j) != i)) {
if ((i != -1) && (cur_j != 0)) {
int row = Models::AddEntry(machineTypesModel, machine_types[i].name, machine_types[i].id);
if (machine_types[i].id == machine_get_type(machine))
selectedMachineType = row;
break;
}
j++;
i = machine_get_type(j);
cur_j = 0;
}
}
if (machine_available(j))
cur_j++;
j++;
} while (miname != nullptr);
ui->comboBoxMachineType->setCurrentIndex(-1);
ui->comboBoxMachineType->setCurrentIndex(selectedMachineType);

View File

@@ -35,25 +35,58 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
for (int i = 0; i < NET_CARD_MAX; ++i) {
auto *nic_cbox = findChild<QComboBox *>(QString("comboBoxNIC%1").arg(i + 1));
auto *net_type_cbox = findChild<QComboBox *>(QString("comboBoxNet%1").arg(i + 1));
auto *intf_label = findChild<QLabel *>(QString("interfaceLabel%1").arg(i + 1));
auto *intf_cbox = findChild<QComboBox *>(QString("comboBoxIntf%1").arg(i + 1));
auto *conf_btn = findChild<QPushButton *>(QString("pushButtonConf%1").arg(i + 1));
// auto *net_type_conf_btn = findChild<QPushButton *>(QString("pushButtonNetTypeConf%1").arg(i + 1));
auto *vde_socket_label = findChild<QLabel *>(QString("socketVDELabel%1").arg(i + 1));
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
int netType = net_type_cbox->currentData().toInt();
bool adaptersEnabled = netType == NET_TYPE_NONE
|| netType == NET_TYPE_SLIRP
|| netType == NET_TYPE_VDE
|| (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0);
auto *option_list_label = findChild<QLabel *>(QString("optionListLabel%1").arg(i + 1));
auto *option_list_line = findChild<QWidget *>(QString("optionListLine%1").arg(i + 1));
intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP);
nic_cbox->setEnabled(adaptersEnabled);
int netCard = nic_cbox->currentData().toInt();
if ((i == 0) && (netCard == NET_INTERNAL))
conf_btn->setEnabled(adaptersEnabled && machine_has_flags(machineId, MACHINE_NIC) &&
device_has_config(machine_get_net_device(machineId)));
else
conf_btn->setEnabled(adaptersEnabled && network_card_has_config(nic_cbox->currentData().toInt()));
socket_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_VDE);
conf_btn->setEnabled(network_card_has_config(nic_cbox->currentData().toInt()));
// net_type_conf_btn->setEnabled(network_type_has_config(netType));
// Option list label and line
option_list_label->setVisible(false);
option_list_line->setVisible(false);
// VDE
vde_socket_label->setVisible(false);
socket_line->setVisible(false);
// PCAP
intf_cbox->setVisible(false);
intf_label->setVisible(false);
// Don't enable anything unless there's a nic selected
if(nic_cbox->currentData().toInt() != 0) {
// Then only enable as needed based on network type
switch (net_type_cbox->currentData().toInt()) {
case NET_TYPE_VDE:
// option_list_label->setText("VDE Options");
option_list_label->setVisible(true);
option_list_line->setVisible(true);
vde_socket_label->setVisible(true);
socket_line->setVisible(true);
break;
case NET_TYPE_PCAP:
// option_list_label->setText("PCAP Options");
option_list_label->setVisible(true);
option_list_line->setVisible(true);
intf_cbox->setVisible(true);
intf_label->setVisible(true);
break;
}
}
}
}
@@ -154,7 +187,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
}
model->removeRows(0, removeRows);
cbox->setCurrentIndex(net_cards_conf[i].net_type);
cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type));
selectedRow = 0;

View File

@@ -36,20 +36,7 @@
<string>Network Card #1</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxNet1">
<property name="maxVisibleItems">
<number>30</number>
@@ -63,32 +50,6 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxIntf1">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@@ -101,23 +62,40 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxNIC1">
<property name="maxVisibleItems">
<number>30</number>
<item row="6" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
<property name="text">
<string>Mode</string>
</property>
</widget>
</item>
<item row="2" column="2">
<item row="2" column="1" colspan="2">
<widget class="Line" name="optionListLine1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConf1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -130,21 +108,74 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="optionListLabel1">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="interfaceLabel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="socketVDELabel1">
<property name="text">
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxNIC1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="socketVDENIC1">
<property name="maxLength">
<number>127</number>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxIntf1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Network Card #2</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -157,13 +188,26 @@
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Network Card #2</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="interfaceLabel2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="optionListLabel2">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
@@ -177,7 +221,7 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxNet2">
<property name="maxVisibleItems">
<number>30</number>
@@ -190,33 +234,21 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item row="5" column="0">
<widget class="QLabel" name="socketVDELabel2">
<property name="text">
<string>Interface</string>
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxIntf2">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="2" column="1" colspan="2">
<widget class="Line" name="optionListLine2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@@ -229,7 +261,20 @@
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConf2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxNIC2">
<property name="maxVisibleItems">
<number>30</number>
@@ -245,40 +290,19 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonConf2">
<property name="text">
<string>Configure</string>
<item row="5" column="1">
<widget class="QLineEdit" name="socketVDENIC2"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxIntf2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLineEdit" name="socketVDENIC2">
<property name="maxLength">
<number>127</number>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
@@ -286,6 +310,69 @@
<string>Network Card #3</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxNet3">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="socketVDELabel3">
<property name="text">
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="optionListLabel3">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxNIC3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="interfaceLabel3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="Line" name="optionListLine3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
@@ -299,75 +386,7 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxNet3">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxIntf3">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adapter</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxNIC3">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConf3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -380,21 +399,33 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>VDE Socket</string>
<string>Adapter</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLineEdit" name="socketVDENIC3">
<property name="maxLength">
<number>127</number>
<item row="5" column="1">
<widget class="QLineEdit" name="socketVDENIC3"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxIntf3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -414,6 +445,13 @@
<string>Network Card #4</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="0">
<widget class="QLabel" name="optionListLabel4">
<property name="text">
<string>Options</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="sizePolicy">
@@ -427,102 +465,7 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxNet4">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="comboBoxIntf4">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_16">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adapter</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxNIC4">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonConf4">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLineEdit" name="socketVDENIC4">
<property name="maxLength">
<number>127</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -535,6 +478,101 @@
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="socketVDELabel4">
<property name="text">
<string>VDE Socket</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_16">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Adapter</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="Line" name="optionListLine4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="interfaceLabel4">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxNIC4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxNet4">
<property name="maxVisibleItems">
<number>30</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConf4">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="socketVDENIC4"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxIntf4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@@ -46,11 +46,11 @@ setMOBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_t
QIcon icon;
switch (bus) {
case MO_BUS_DISABLED:
icon = ProgSettings::loadIcon("/mo_disabled.ico");
icon = QIcon(":/settings/qt/icons/mo_disabled.ico");
break;
case MO_BUS_ATAPI:
case MO_BUS_SCSI:
icon = ProgSettings::loadIcon("/mo.ico");
icon = QIcon(":/settings/qt/icons/mo.ico");
break;
default:
@@ -81,11 +81,11 @@ setZIPBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint8_
QIcon icon;
switch (bus) {
case ZIP_BUS_DISABLED:
icon = ProgSettings::loadIcon("/zip_disabled.ico");
icon = QIcon(":/settings/qt/icons/zip_disabled.ico");
break;
case ZIP_BUS_ATAPI:
case ZIP_BUS_SCSI:
icon = ProgSettings::loadIcon("/zip.ico");
icon = QIcon(":/settings/qt/icons/zip.ico");
break;
default:

View File

@@ -18,6 +18,9 @@
#include <QComboBox>
#include <QAbstractItemView>
#include <QPixmap>
#include <QIcon>
#include <QStyleOption>
#ifdef Q_OS_WINDOWS
#include <dwmapi.h>
@@ -66,3 +69,40 @@ StyleOverride::polish(QWidget *widget)
qobject_cast<QComboBox *>(widget)->view()->setMinimumWidth(widget->minimumSizeHint().width());
}
}
QPixmap
StyleOverride::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const
{
if (iconMode != QIcon::Disabled) {
return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option);
}
auto image = pixmap.toImage();
for (int y = 0; y < image.height(); y++) {
for (int x = 0; x < image.width(); x++) {
// checkerboard transparency
if (((x ^ y) & 1) == 0) {
image.setPixelColor(x, y, Qt::transparent);
continue;
}
auto color = image.pixelColor(x, y);
// convert to grayscale using the NTSC formula
auto avg = 0.0;
avg += color.blueF() * 0.114;
avg += color.greenF() * 0.587;
avg += color.redF() * 0.299;
color.setRedF(avg);
color.setGreenF(avg);
color.setBlueF(avg);
image.setPixelColor(x, y, color);
}
}
return QPixmap::fromImage(image);
}

View File

@@ -4,6 +4,9 @@
#include <QProxyStyle>
#include <QWidget>
#include <QLayout>
#include <QPixmap>
#include <QIcon>
#include <QStyleOption>
class StyleOverride : public QProxyStyle {
public:
@@ -14,6 +17,7 @@ public:
QStyleHintReturn *returnData = nullptr) const override;
void polish(QWidget *widget) override;
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const override;
};
#endif

View File

@@ -1,16 +1,9 @@
<RCC>
<qresource prefix="/settings">
<file>qt/icons/cartridge.ico</file>
<file>qt/icons/cartridge_empty.ico</file>
<file>qt/icons/cassette.ico</file>
<file>qt/icons/cassette_active.ico</file>
<file>qt/icons/cassette_empty.ico</file>
<file>qt/icons/cassette_empty_active.ico</file>
<file>qt/icons/cdrom.ico</file>
<file>qt/icons/cdrom_active.ico</file>
<file>qt/icons/cdrom_disabled.ico</file>
<file>qt/icons/cdrom_empty.ico</file>
<file>qt/icons/cdrom_empty_active.ico</file>
<file>qt/icons/cdrom_mute.ico</file>
<file>qt/icons/cdrom_unmute.ico</file>
<file>qt/icons/cdrom_image.ico</file>
@@ -18,38 +11,24 @@
<file>qt/icons/cdrom_host.ico</file>
<file>qt/icons/display.ico</file>
<file>qt/icons/floppy_35.ico</file>
<file>qt/icons/floppy_35_active.ico</file>
<file>qt/icons/floppy_35_empty.ico</file>
<file>qt/icons/floppy_35_empty_active.ico</file>
<file>qt/icons/floppy_525.ico</file>
<file>qt/icons/floppy_525_active.ico</file>
<file>qt/icons/floppy_525_empty.ico</file>
<file>qt/icons/floppy_525_empty_active.ico</file>
<file>qt/icons/floppy_and_cdrom_drives.ico</file>
<file>qt/icons/floppy_disabled.ico</file>
<file>qt/icons/hard_disk.ico</file>
<file>qt/icons/hard_disk_active.ico</file>
<file>qt/icons/input_devices.ico</file>
<file>qt/icons/machine.ico</file>
<file>qt/icons/mo.ico</file>
<file>qt/icons/mo_active.ico</file>
<file>qt/icons/mo_disabled.ico</file>
<file>qt/icons/mo_empty.ico</file>
<file>qt/icons/mo_empty_active.ico</file>
<file>qt/icons/network.ico</file>
<file>qt/icons/network_active.ico</file>
<file>qt/icons/network_empty.ico</file>
<file>qt/icons/other_peripherals.ico</file>
<file>qt/icons/other_removable_devices.ico</file>
<file>qt/icons/ports.ico</file>
<file>qt/icons/sound.ico</file>
<file>qt/icons/sound_mute.ico</file>
<file>qt/icons/storage_controllers.ico</file>
<file>qt/icons/zip.ico</file>
<file>qt/icons/zip_active.ico</file>
<file>qt/icons/zip_disabled.ico</file>
<file>qt/icons/zip_empty.ico</file>
<file>qt/icons/zip_empty_active.ico</file>
<file>qt/icons/active.ico</file>
<file>qt/icons/disabled.ico</file>
<file>qt/icons/86Box-gray.ico</file>
<file>qt/icons/86Box-green.ico</file>
<file>qt/icons/86Box-red.ico</file>

View File

@@ -95,9 +95,6 @@ ncr5380_reset(ncr_t *ncr)
ncr->timer(ncr->priv, 0.0);
for (int i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[ncr->bus][i]);
scsi_bus->state = STATE_IDLE;
scsi_bus->clear_req = 0;
scsi_bus->wait_complete = 0;

View File

@@ -29,11 +29,11 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/pic.h>
#include <86box/mca.h>
#include <86box/mem.h>
#include <86box/timer.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/nvr.h>
@@ -41,6 +41,7 @@
#include <86box/scsi.h>
#include <86box/scsi_device.h>
#include <86box/scsi_ncr5380.h>
#include "cpu.h"
#define LCS6821N_ROM "roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin"
#define COREL_LS2000_ROM "roms/scsi/ncr5380/Corel LS2000 - BIOS ROM - Ver 1.65.bin"
@@ -80,6 +81,7 @@ typedef struct ncr53c400_t {
int buffer_host_pos;
int busy;
int reset;
uint8_t pos_regs[8];
pc_timer_t timer;
@@ -126,6 +128,9 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
addr &= 0x3fff;
if (addr >= 0x3880)
ncr53c400_log("%04X:%08X: memio_write(%04x)=%02x\n", CS, cpu_state.pc, addr, val);
if (addr >= 0x3a00)
ncr400->ext_ram[addr - 0x3a00] = val;
else {
@@ -147,6 +152,8 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
ncr400->busy = 1;
if (ncr400->type != ROM_T130B)
timer_on_auto(&ncr400->timer, 1.0);
}
} else
ncr53c400_log("No Write.\n");
@@ -155,6 +162,19 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
case 0x3980:
switch (addr) {
case 0x3980: /* Control */
/*Parity bits*/
/*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/
/*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/
/*Required by RTASPI10.SYS otherwise it won't initialize.*/
if (val & 0x80) {
if (ncr->mode & 0x30) {
if (!(ncr->mode & MODE_DMA)) {
ncr->mode = 0x00;
ncr400->reset = 1;
}
}
}
ncr53c400_log("NCR 53c400 control=%02x, mode=%02x.\n", val, ncr->mode);
if ((val & CTRL_DATA_DIR) && !(ncr400->status_ctrl & CTRL_DATA_DIR)) {
ncr400->buffer_host_pos = MIN(128, dev->buffer_length);
@@ -180,10 +200,7 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
}
if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) {
memset(ncr400->buffer, 0, MIN(128, dev->buffer_length));
if (ncr400->type == ROM_T130B)
timer_on_auto(&ncr400->timer, 10.0);
else
timer_on_auto(&ncr400->timer, scsi_bus->period);
timer_on_auto(&ncr400->timer, 10.0);
ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, p=%lf enabled=%d.\n",
ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, scsi_bus->wait_data, scsi_bus->wait_complete, scsi_bus->clear_req, scsi_bus->period, timer_is_enabled(&ncr400->timer));
} else
@@ -241,6 +258,20 @@ ncr53c400_read(uint32_t addr, void *priv)
if (ncr400->buffer_host_pos == MIN(128, dev->buffer_length)) {
ncr400->status_ctrl |= STATUS_BUFFER_NOT_READY;
if (ncr400->type != ROM_T130B) {
if (!ncr400->block_count_loaded) {
scsi_bus->tx_mode = PIO_TX_BUS;
ncr53c400_log("IO End of read transfer\n");
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR read irq\n");
ncr5380_irq(ncr, 1);
}
} else if (!timer_is_enabled(&ncr400->timer)) {
ncr53c400_log("Timer re-enabled.\n");
timer_on_auto(&ncr400->timer, 1.0);
}
}
}
}
break;
@@ -252,11 +283,10 @@ ncr53c400_read(uint32_t addr, void *priv)
ncr53c400_log("NCR status ctrl read=%02x.\n", ncr400->status_ctrl & STATUS_BUFFER_NOT_READY);
if (!ncr400->busy)
ret |= STATUS_5380_ACCESSIBLE;
if (ncr->mode & 0x30) { /*Parity bits*/
if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/
ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/
ncr->mode = 0x00; /*Required by RTASPI10.SYS otherwise it won't initialize.*/
}
if (ncr400->reset) {
ncr400->reset = 0;
ret |= 0x01;
}
ncr53c400_log("NCR 53c400 status=%02x.\n", ret);
break;
@@ -267,7 +297,10 @@ ncr53c400_read(uint32_t addr, void *priv)
break;
case 0x3982: /* switch register read */
ret = 0xff;
if (ncr->irq != -1) {
ret = 0xf8;
ret += ncr->irq;
}
ncr53c400_log("Switches read=%02x.\n", ret);
break;
@@ -282,7 +315,7 @@ ncr53c400_read(uint32_t addr, void *priv)
}
if (addr >= 0x3880)
ncr53c400_log("memio_read(%08x)=%02x\n", addr, ret);
ncr53c400_log("%04X:%08X: memio_read(%04x)=%02x\n", CS, cpu_state.pc, addr, ret);
return ret;
}
@@ -424,11 +457,8 @@ ncr53c400_callback(void *priv)
uint8_t status;
if (scsi_bus->tx_mode != PIO_TX_BUS) {
if (ncr400->type == ROM_T130B) {
ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0);
timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0);
} else
timer_on_auto(&ncr400->timer, 1.0);
ncr53c400_log("PERIOD T130B DMA=%lf.\n", scsi_bus->period / 225.0);
timer_on_auto(&ncr400->timer, scsi_bus->period / 225.0);
}
if (scsi_bus->data_wait & 1) {
@@ -538,14 +568,17 @@ ncr53c400_callback(void *priv)
ncr400->block_count = (ncr400->block_count - 1) & 0xff;
ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count);
if (!ncr400->block_count) {
scsi_bus->tx_mode = PIO_TX_BUS;
ncr400->block_count_loaded = 0;
ncr53c400_log("IO End of read transfer\n");
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR read irq\n");
ncr5380_irq(ncr, 1);
}
if (ncr400->type == ROM_T130B) {
scsi_bus->tx_mode = PIO_TX_BUS;
ncr53c400_log("IO End of read transfer\n");
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR read irq\n");
ncr5380_irq(ncr, 1);
}
} else
timer_on_auto(&ncr400->timer, 1.0);
}
break;
}
@@ -732,8 +765,17 @@ ncr53c400_init(const device_t *info)
scsi_bus_set_speed(ncr->bus, 5000000.0);
scsi_bus->speed = 0.2;
scsi_bus->divider = 2.0;
scsi_bus->multi = 1.750;
if (ncr400->type == ROM_T130B) {
scsi_bus->divider = 2.0;
scsi_bus->multi = 1.750;
} else {
scsi_bus->divider = 1.0;
scsi_bus->multi = 1.0;
}
for (int i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[ncr->bus][i]);
return ncr400;
}

View File

@@ -95,9 +95,10 @@ t128_write(uint32_t addr, uint8_t val, void *priv)
t128->status, scsi_bus->period, timer_is_enabled(&t128->timer), t128->block_loaded);
t128->status &= ~0x04;
timer_on_auto(&t128->timer, 10.0);
timer_on_auto(&t128->timer, 1.0);
}
}
} else
t128_log("Write not allowed.\n");
}
}
@@ -136,20 +137,18 @@ t128_read(uint32_t addr, void *priv)
t128_log("T128 Transfer busy read, status=%02x, period=%lf, enabled=%d.\n",
t128->status, scsi_bus->period, timer_is_enabled(&t128->timer));
t128->status &= ~0x04;
if (!t128->block_loaded) {
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
t128_log("T128 read irq\n");
ncr5380_irq(ncr, 1);
}
t128->status &= ~0x04;
scsi_bus->bus_out |= BUS_CD;
scsi_bus->tx_mode = PIO_TX_BUS;
timer_stop(&t128->timer);
} else if (!timer_is_enabled(&t128->timer))
timer_on_auto(&t128->timer, 10.0);
else
t128->status &= ~0x04;
timer_on_auto(&t128->timer, 1.0);
}
} else {
/*According to the WinNT DDK sources, just get the status timeout bit from here.*/
@@ -522,6 +521,10 @@ t128_init(const device_t *info)
scsi_bus->speed = 0.2;
scsi_bus->divider = 1.0;
scsi_bus->multi = 1.0;
for (int i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[ncr->bus][i]);
return t128;
}

View File

@@ -73,7 +73,6 @@ static int exit_event = 0;
static int fullscreen_pending = 0;
uint32_t lang_id = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US
uint32_t lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US
char icon_set[256] = ""; /* name of the iconset to be used */
static const uint16_t sdl_to_xt[0x200] = {
[SDL_SCANCODE_ESCAPE] = 0x01,

View File

@@ -756,8 +756,9 @@ double
ini_section_get_double(ini_section_t self, const char *name, double def)
{
section_t *section = (section_t *) self;
const entry_t *entry;
double value = 0;
entry_t *entry;
double value = 0;
int res = 0;
if (section == NULL)
return def;
@@ -766,7 +767,17 @@ ini_section_get_double(ini_section_t self, const char *name, double def)
if (entry == NULL)
return def;
sscanf(entry->data, "%lg", &value);
res = sscanf(entry->data, "%lg", &value);
if (res == EOF || res <= 0) {
int i = 0;
for (i = 0; i < strlen(entry->data); i++) {
if (entry->data[i] == ',') {
entry->data[i] = '.';
entry->wdata[i] = L'.';
}
}
(void)sscanf(entry->data, "%lg", &value);
}
return value;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -112,10 +112,13 @@ ega_out(uint16_t addr, uint8_t val, void *priv)
ega->fullchange = changeframecount;
if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) {
for (uint8_t c = 0; c < 16; c++) {
if (ega->attrregs[0x10] & 0x80)
ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4);
else
ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4);
if (ega->chipset) {
if (ega->attrregs[0x10] & 0x80)
ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4);
else
ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4);
} else
ega->egapal[c] = ega->attrregs[c] & 0x3f;
}
ega->fullchange = changeframecount;
}
@@ -780,7 +783,7 @@ ega_poll(void *priv)
ega->y_add *= ega->vres + 1;
for (y = 0; y <= ega->vres; y++) {
/* Render scanline */
if(ega->render_override)
if (ega->render_override)
ega->render_override(ega->priv_parent);
else
ega->render(ega);

View File

@@ -172,15 +172,20 @@ ega_render_text(ega_t *ega)
uint32_t dat = ega->vram[charaddr + (ega->sc << 2)];
dat <<= 1;
if ((chr & ~0x1F) == 0xC0 && attrlinechars)
if (((chr & ~0x1f) == 0xc0) && attrlinechars)
dat |= (dat >> 1) & 1;
for (int xx = 0; xx < charwidth; xx++) {
if (monoattrs) {
int bit = (dat & (0x100 >> (xx >> dwshift))) ? 1 : 0;
int blink = (!drawcursor && (attr & 0x80) && attrblink && blinked);
if ((ega->sc == ega->crtc[0x14]) && ((attr & 7) == 1))
p[xx] = ega->mdacols[attr][attrblink][1];
p[xx] = ega->mdacols[attr][blink][1];
else
p[xx] = ega->mdacols[attr][attrblink][dat & (0x100 >> (xx >> dwshift))];
p[xx] = ega->mdacols[attr][blink][bit];
if (drawcursor)
p[xx] ^= ega->mdacols[attr][0][1];
p[xx] = ega->pallook[ega->egapal[p[xx] & 0x0f]];
} else
p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg;
}
@@ -189,9 +194,6 @@ ega_render_text(ega_t *ega)
p += charwidth;
}
ega->ma &= 0x3ffff;
if (monoattrs)
video_process_8(ega->hdisp + ega->scrollcache, ega->displine);
}
}

View File

@@ -29,11 +29,14 @@
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/plat.h>
#include <86box/plat_fallthrough.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/video.h>
#include <86box/vid_ega.h>
#include <86box/vid_svga.h>
#include <86box/vid_vga.h>
/* JEGA internal registers */
#define RPESL 0x09 /* End Scan Line */
@@ -63,6 +66,8 @@
#define JEGA_PATH_BIOS "roms/video/jega/JEGABIOS.BIN"
#define JEGA_PATH_FONTDBCS "roms/video/jega/JPNZN16X.FNT"
#define IF386_PATH_VBIOS "roms/machines/if386sx/OKI_IF386SX_VBIOS.bin"
#define JVGA_PATH_BIOS "roms/video/jega/OKI_JVGT(AXVGAH)_BIOS_011993.BIN"
#define JVGA_PATH_FONTDBCS "roms/video/jega/JWPCE.FNT"
#define SBCS19_FILESIZE (256 * 19 * 2) /* 8 x 19 x 256 chr x 2 pages */
#define DBCS16_CHARS 0x2c10
#define DBCS16_FILESIZE (DBCS16_CHARS * 16 * 2)
@@ -96,29 +101,31 @@ jega_log(const char *fmt, ...)
static video_timings_t timing_ega = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 };
typedef struct jega_t {
rom_t bios_rom;
ega_t ega;
uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */
uint8_t regs[0x31];
uint8_t egapal[16];
uint8_t attrregs[32];
uint8_t attraddr;
uint8_t attrff;
uint8_t attr_palette_enable;
rom_t bios_rom;
ega_t ega;
vga_t vga;
uint8_t regs_index; /* 3D4/3D5 index B9-BF, D9-DF */
uint8_t regs[0x31];
uint8_t egapal[16];
uint8_t attrregs[32];
uint8_t attraddr;
uint8_t attrff;
uint8_t attr_palette_enable;
uint32_t *pallook;
int con;
int cursoron;
int cursorblink_disable;
int ca;
int font_index;
int sbcsbank_inv;
int attr3_sbcsbank;
int start_scan_lower;
int start_scan_upper;
int start_scan_count;
uint8_t *vram;
uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */
uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */
int is_vga;
int con;
int cursoron;
int cursorblink_disable;
int ca;
int font_index;
int sbcsbank_inv;
int attr3_sbcsbank;
int start_scan_lower;
int start_scan_upper;
int start_scan_count;
uint8_t * vram;
uint8_t jfont_sbcs_19[SBCS19_FILESIZE]; /* 8 x 19 font */
uint8_t jfont_dbcs_16[DBCS16_FILESIZE]; /* 16 x 16 font. Use dbcs_read/write to access it. */
} jega_t;
static void jega_recalctimings(void *priv);
@@ -127,16 +134,16 @@ static void jega_recalctimings(void *priv);
#define FONTX_LEN_FN 8
typedef struct {
char id[FONTX_LEN_ID];
char name[FONTX_LEN_FN];
unsigned char width;
unsigned char height;
unsigned char type;
char id[FONTX_LEN_ID];
char name[FONTX_LEN_FN];
uint8_t width;
uint8_t height;
uint8_t type;
} fontx_h;
typedef struct {
uint16_t start;
uint16_t end;
uint16_t start;
uint16_t end;
} fontx_tbl;
extern uint32_t pallook16[256];
@@ -147,22 +154,32 @@ static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr
static uint16_t
SJIS_to_SEQ(uint16_t sjis)
{
uint32_t chr1 = (sjis >> 8) & 0xff;
uint32_t chr2 = sjis & 0xff;
if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2)) return INVALIDACCESS16;
chr1 -= 0x81;
if (chr1 > 0x5E) chr1 -= 0x40;
chr2 -= 0x40;
if (chr2 > 0x3F) chr2--;
chr1 *= 0xBC;
return (chr1 + chr2);
uint32_t chr1 = (sjis >> 8) & 0xff;
uint32_t chr2 = sjis & 0xff;
if (!is_SJIS_1(chr1) || !is_SJIS_2(chr2))
return INVALIDACCESS16;
chr1 -= 0x81;
if (chr1 > 0x5e)
chr1 -= 0x40;
chr2 -= 0x40;
if (chr2 > 0x3f)
chr2--;
chr1 *= 0xbc;
return (chr1 + chr2);
}
static uint8_t
dbcs_read(uint16_t sjis, int index, void *priv) {
jega_t *jega = (jega_t *) priv;
int seq = SJIS_to_SEQ(sjis);
if (seq >= DBCS16_CHARS || index >= 32)
if ((seq >= DBCS16_CHARS) || (index >= 32))
return INVALIDACCESS8;
return jega->jfont_dbcs_16[seq * 32 + index];
}
@@ -171,7 +188,7 @@ static void
dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) {
jega_t *jega = (jega_t *) priv;
int seq = SJIS_to_SEQ(sjis);
if (seq >= DBCS16_CHARS || index >= 32)
if ((seq >= DBCS16_CHARS) || (index >= 32))
return;
jega->jfont_dbcs_16[seq * 32 + index] = val;
}
@@ -180,38 +197,81 @@ dbcs_write(uint16_t sjis, int index, uint8_t val, void *priv) {
void
jega_render_text(void *priv)
{
jega_t *jega = (jega_t *) priv;
if (jega->ega.firstline_draw == 2000)
jega->ega.firstline_draw = jega->ega.displine;
jega->ega.lastline_draw = jega->ega.displine;
jega_t * jega = (jega_t *) priv;
#ifdef USE_DOUBLE_WIDTH_AND_LINE_CHARS
uint8_t * seqregs = jega->is_vga ? jega->vga.svga.seqregs :
jega->ega.seqregs;
uint8_t * attrregs = jega->is_vga ? jega->vga.svga.attrregs :
jega->ega.attrregs;
#endif
uint8_t * crtc = jega->is_vga ? jega->vga.svga.crtc :
jega->ega.crtc;
uint8_t * vram = jega->is_vga ? jega->vga.svga.vram :
jega->ega.vram;
int * firstline_draw = jega->is_vga ? &jega->vga.svga.firstline_draw :
&jega->ega.firstline_draw;
int * lastline_draw = jega->is_vga ? &jega->vga.svga.lastline_draw :
&jega->ega.lastline_draw;
int * displine = jega->is_vga ? &jega->vga.svga.displine :
&jega->ega.displine;
int * fullchange = jega->is_vga ? &jega->vga.svga.fullchange :
&jega->ega.fullchange;
int * blink = jega->is_vga ? &jega->vga.svga.blink :
&jega->ega.blink;
int * x_add = jega->is_vga ? &jega->vga.svga.x_add :
&jega->ega.x_add;
int * y_add = jega->is_vga ? &jega->vga.svga.y_add :
&jega->ega.y_add;
int * sc = jega->is_vga ? &jega->vga.svga.sc :
&jega->ega.sc;
int * hdisp = jega->is_vga ? &jega->vga.svga.hdisp :
&jega->ega.hdisp;
int * scrollcache = jega->is_vga ? &jega->vga.svga.scrollcache :
&jega->ega.scrollcache;
uint32_t *ma = jega->is_vga ? &jega->vga.svga.ma :
&jega->ega.ma;
uint8_t mask = jega->is_vga ? jega->vga.svga.dac_mask : 0xff;
if (jega->ega.fullchange) {
// const bool doublewidth = ((jega->ega.seqregs[1] & 8) != 0);
const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */
// const bool attrlinechars = (jega->ega.attrregs[0x10] & 4);
const bool crtcreset = ((jega->ega.crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0);
const int charwidth = 8;
const bool blinked = jega->ega.blink & 0x10;
uint32_t *p = &buffer32->line[jega->ega.displine + jega->ega.y_add][jega->ega.x_add];
bool chr_wide = false;
int sc_wide = jega->ega.sc - jega->start_scan_count;
const bool cursoron = (blinked || jega->cursorblink_disable)
&& (jega->ega.sc >= jega->regs[RCCSL]) && (jega->ega.sc <= jega->regs[RCCEL]);
uint32_t chr_first;
uint32_t attr_basic;
int fg;
int bg;
if (*firstline_draw == 2000)
*firstline_draw = *displine;
*lastline_draw = *displine;
for (int x = 0; x < (jega->ega.hdisp + jega->ega.scrollcache); x += charwidth) {
uint32_t addr = jega->ega.remap_func(&jega->ega, jega->ega.ma) & jega->ega.vrammask;
if (*fullchange) {
#ifdef USE_DOUBLE_WIDTH_AND_LINE_CHARS
const bool doublewidth = ((seqregs[1] & 8) != 0);
const bool attrlinechars = (attrregs[0x10] & 4);
#endif
const bool attrblink = ((jega->regs[RMOD2] & 0x20) == 0); /* JEGA specific */
const bool crtcreset = ((crtc[0x17] & 0x80) == 0) || ((jega->regs[RMOD1] & 0x80) == 0);
const int charwidth = 8;
const bool blinked = *blink & 0x10;
uint32_t *p = &buffer32->line[*displine + *y_add][*x_add];
bool chr_wide = false;
int sc_wide = *sc - jega->start_scan_count;
const bool cursoron = (blinked || jega->cursorblink_disable) &&
(*sc >= jega->regs[RCCSL]) && (*sc <= jega->regs[RCCEL]);
uint32_t attr_basic = 0;
uint32_t chr_first;
int fg = 0;
int bg;
int drawcursor = ((jega->ega.ma == jega->ca) && cursoron);
for (int x = 0; x < (*hdisp + *scrollcache); x += charwidth) {
uint32_t addr = 0;
if (jega->is_vga) {
if (!jega->vga.svga.force_old_addr)
addr = jega->vga.svga.remap_func(&jega->vga.svga, jega->vga.svga.ma) &
jega->vga.svga.vram_display_mask;
} else
addr = jega->ega.remap_func(&jega->ega, *ma) & jega->ega.vrammask;
int drawcursor = ((*ma == jega->ca) && cursoron);
uint32_t chr;
uint32_t attr;
if (!crtcreset) {
chr = jega->ega.vram[addr];
attr = jega->ega.vram[addr + 1];
chr = vram[addr];
attr = vram[addr + 1];
} else
chr = attr = 0;
if (chr_wide) {
@@ -222,13 +282,13 @@ jega_render_text(void *priv)
/* Bold | 2x width | 2x height | U/L select | R/L select | - | - | - */
attr_ext = attr;
if ((attr_ext & 0x30) == 0x30)
sc_wide = jega->ega.sc - jega->start_scan_lower; /* Set top padding of lower 2x character */
sc_wide = *sc - jega->start_scan_lower; /* Set top padding of lower 2x character */
else if ((attr_ext & 0x30) == 0x20)
sc_wide = jega->ega.sc - jega->start_scan_upper; /* Set top padding of upper 2x character */
sc_wide = *sc - jega->start_scan_upper; /* Set top padding of upper 2x character */
else
sc_wide = jega->ega.sc - jega->start_scan_count;
sc_wide = *sc - jega->start_scan_count;
}
if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && jega->ega.sc <= jega->regs[RPESL]) {
if (is_SJIS_2(chr) && sc_wide >= 0 && sc_wide < 16 && *sc <= jega->regs[RPESL]) {
chr_first <<= 8;
chr |= chr_first;
/* Vertical wide font (Extended Attribute) */
@@ -269,7 +329,7 @@ jega_render_text(void *priv)
if (attr_basic & 0x20) { /* vertical line */
p[0] = fg;
}
if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */
if ((*sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */
for (int xx = 0; xx < charwidth * 2; xx++)
p[xx] = fg;
}
@@ -298,13 +358,13 @@ jega_render_text(void *priv)
/* Parse attribute as EGA */
/* BInt/Blink | BR | BG | BB | Int/Group | R | G | B */
if (drawcursor) {
bg = jega->pallook[jega->egapal[attr & 0x0f]];
fg = jega->pallook[jega->egapal[attr >> 4]];
bg = jega->pallook[jega->egapal[attr & 0x0f] & mask];
fg = jega->pallook[jega->egapal[attr >> 4] & mask];
} else {
fg = jega->pallook[jega->egapal[attr & 0x0f]];
bg = jega->pallook[jega->egapal[attr >> 4]];
fg = jega->pallook[jega->egapal[attr & 0x0f] & mask];
bg = jega->pallook[jega->egapal[attr >> 4] & mask];
if ((attr & 0x80) && attrblink) {
bg = jega->pallook[jega->egapal[(attr >> 4) & 7]];
bg = jega->pallook[jega->egapal[(attr >> 4) & 7] & mask];
if (blinked)
fg = bg;
}
@@ -325,32 +385,35 @@ jega_render_text(void *priv)
// charaddr ^= 0x100;
charaddr *= 19;
uint32_t dat = jega->jfont_sbcs_19[charaddr + jega->ega.sc];
uint32_t dat = jega->jfont_sbcs_19[charaddr + *sc];
for (int xx = 0; xx < charwidth; xx++)
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
if (attr_basic & 0x20) { /* vertical line */
p[0] = fg;
}
if ((jega->ega.sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */
if ((*sc == jega->regs[RPULP]) && (attr_basic & 0x10)) { /* underline */
for (int xx = 0; xx < charwidth; xx++)
p[xx] = fg;
}
p += charwidth;
}
}
jega->ega.ma += 4;
*ma += 4;
}
jega->ega.ma &= 0x3ffff;
*ma &= 0x3ffff;
}
}
static void
jega_out(uint16_t addr, uint8_t val, void *priv)
{
jega_t *jega = (jega_t *) priv;
uint16_t chr;
jega_t *jega = (jega_t *) priv;
uint8_t pal4to16[16] = { 0, 7, 0x38, 0x3f, 0, 3, 4, 0x3f, 0, 2, 4, 0x3e, 0, 3, 5, 0x3f };
uint16_t chr;
// jega_log("JEGA Out %04X %02X(%d) %04X:%04X\n", addr, val, val, cs >> 4, cpu_state.pc);
switch (addr) {
case 0x3c0:
case 0x3c1:
@@ -367,9 +430,20 @@ jega_out(uint16_t addr, uint8_t val, void *priv)
jega->attrregs[jega->attraddr & 31] = val;
if (jega->attraddr < 0x10) {
for (uint8_t c = 0; c < 16; c++) {
if (jega->is_vga) {
if (jega->attrregs[0x10] & 0x80)
jega->egapal[c] = (jega->attrregs[c] & 0xf) | ((jega->attrregs[0x14] & 0xf) << 4);
else if (jega->vga.svga.ati_4color)
jega->egapal[c] = pal4to16[(c & 0x03) | ((val >> 2) & 0xc)];
else
jega->egapal[c] = (jega->attrregs[c] & 0x3f) | ((jega->attrregs[0x14] & 0xc) << 4);
} else
jega->egapal[c] = jega->attrregs[c] & 0x3f;
}
jega->ega.fullchange = changeframecount;
if (jega->is_vga)
jega->vga.svga.fullchange = changeframecount;
else
jega->ega.fullchange = changeframecount;
}
}
jega->attrff ^= 1;
@@ -395,12 +469,17 @@ jega_out(uint16_t addr, uint8_t val, void *priv)
switch (jega->regs_index) {
case RMOD1:
/* if the value is changed */
// if (jega->regs[jega->regs_index] != val) {
if (val & 0x40)
jega->ega.render_override = NULL;
else
jega->ega.render_override = jega_render_text;
// }
if (jega->is_vga) {
if (val & 0x40)
jega->vga.svga.render_override = NULL;
else
jega->vga.svga.render_override = jega_render_text;
} else {
if (val & 0x40)
jega->ega.render_override = NULL;
else
jega->ega.render_override = jega_render_text;
}
break;
case RDAGS:
switch (val & 0x03) {
@@ -470,8 +549,14 @@ jega_out(uint16_t addr, uint8_t val, void *priv)
default:
break;
}
if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */
ega_out(addr, val, &jega->ega);
/* Accessing to Slave EGA is redirected to Master in AX-1. */
if (jega->regs[RMOD1] & 0x0c) {
if (jega->is_vga)
vga_out(addr, val, &jega->vga);
else
ega_out(addr, val, &jega->ega);
}
}
static uint8_t
@@ -480,6 +565,7 @@ jega_in(uint16_t addr, void *priv)
jega_t *jega = (jega_t *) priv;
uint8_t ret = INVALIDACCESS8;
uint16_t chr;
switch (addr) {
case 0x3b5:
case 0x3d5:
@@ -508,15 +594,26 @@ jega_in(uint16_t addr, void *priv)
break;
}
jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc);
} else if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave EGA is redirected to Master in AX-1. */
ret = ega_in(addr, &jega->ega);
} else if (jega->regs[RMOD1] & 0x0c) {
/* Accessing to Slave EGA is redirected to Master in AX-1. */
if (jega->is_vga)
ret = vga_in(addr, &jega->vga);
else
ret = ega_in(addr, &jega->ega);
}
break;
case 0x3ba:
case 0x3da:
jega->attrff = 0;
fallthrough;
default:
if (jega->regs[RMOD1] & 0x0C) /* Accessing to Slave is redirected to Master in AX-1. */
ret = ega_in(addr, &jega->ega);
/* Accessing to Slave is redirected to Master in AX-1. */
if (jega->regs[RMOD1] & 0x0c) {
if (jega->is_vga)
ret = vga_in(addr, &jega->vga);
else
ret = ega_in(addr, &jega->ega);
}
break;
}
// jega_log("JEGA In %04X(%02X) %02X %04X:%04X\n", addr, jega->regs_index, ret, cs >> 4, cpu_state.pc);
@@ -619,19 +716,29 @@ LoadFontxFile(const char *fn, void *priv)
}
static void
jega_commoninit(void *priv)
jega_commoninit(const device_t *info, void *priv, int vga)
{
jega_t *jega = (jega_t *) priv;
for (int c = 0; c < 256; c++) {
pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55);
jega->is_vga = vga;
if (vga) {
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga);
vga_init(info, &jega->vga, 1);
jega->vga.svga.priv_parent = jega;
jega->pallook = jega->vga.svga.pallook;
} else {
for (int c = 0; c < 256; c++) {
pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa);
pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55);
}
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega);
jega->pallook = pallook64;
ega_init(&jega->ega, 9, 0);
ega_set_type(&jega->ega, EGA_SUPEREGA);
jega->ega.priv_parent = jega;
mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000,
ega_read, NULL, NULL, ega_write, NULL, NULL,
NULL, MEM_MAPPING_EXTERNAL, &jega->ega);
}
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ega);
jega->pallook = pallook64;
ega_init(&jega->ega, 9, 0);
ega_set_type(&jega->ega, EGA_SUPEREGA);
jega->ega.priv_parent = jega;
mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega);
/* I/O 3DD and 3DE are used by Oki if386 */
io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega);
jega->regs[RMOD1] = 0x48;
@@ -646,7 +753,21 @@ jega_standalone_init(const device_t *info)
memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE);
LoadFontxFile(JEGA_PATH_FONTDBCS, jega);
jega_commoninit(jega);
jega_commoninit(info, jega, 0);
return jega;
}
static void *
jvga_standalone_init(const device_t *info)
{
jega_t *jega = calloc(1, sizeof(jega_t));
rom_init(&jega->bios_rom, JVGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0);
memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE);
LoadFontxFile(JVGA_PATH_FONTDBCS, jega);
jega_commoninit(info, jega, 1);
return jega;
}
@@ -693,9 +814,15 @@ jega_close(void *priv)
}
pclog("jeclosed %04X:%04X DS %04X\n", cs >> 4, cpu_state.pc, DS);
#endif
if (jega->ega.eeprom)
free(jega->ega.eeprom);
free(jega->ega.vram);
if (jega->is_vga)
svga_close(&jega->vga.svga);
else {
if (jega->ega.eeprom)
free(jega->ega.eeprom);
free(jega->ega.vram);
}
free(jega);
}
@@ -703,8 +830,13 @@ static void
jega_recalctimings(void *priv)
{
jega_t *jega = (jega_t *) priv;
ega_recalctimings(&jega->ega);
if (jega->is_vga)
svga_recalctimings(&jega->vga.svga);
else
ega_recalctimings(&jega->ega);
}
static void
jega_speed_changed(void *priv)
{
@@ -733,6 +865,20 @@ const device_t jega_device = {
.config = NULL
};
const device_t jvga_device = {
.name = "OKIVGA/H-2 (JVGA/H)",
.internal_name = "jvga",
.flags = DEVICE_ISA,
.local = 0,
.init = jvga_standalone_init,
.close = jega_close,
.reset = NULL,
.available = jega_standalone_available,
.speed_changed = jega_speed_changed,
.force_redraw = NULL,
.config = NULL
};
static uint8_t p65idx = 0;
// static uint8_t p3de_idx = 0;
static uint8_t p65[6];
@@ -770,6 +916,8 @@ if386_p6x_read(uint16_t port, void *priv)
Bit 4: Shutdown? (caused by POST rebooting and POWER OFF command in DOS 3.21)
Bit 3: ?
*/
static uint32_t lcd_cols[8] = { 0x001024, 0x747d8a, 0x8c96a4, 0xa0abbb,
0xb1bece, 0xc0cee0, 0xceddf0, 0xdbebff };
static void
if386_p6x_write(uint16_t port, uint8_t val, void *priv)
{
@@ -793,19 +941,31 @@ if386_p6x_write(uint16_t port, uint8_t val, void *priv)
} else { /* Monochrome LCD */
for (int c = 0; c < 256; c++) {
int cval = 0;
#ifdef SIMPLE_BW
if (c & 0x0f)
cval = ((c & 0x0e) * 0x10) + 0x1f;
pallook64[c] = makecol32(cval, cval, cval);
pallook16[c] = makecol32(cval, cval, cval);
#else
if (c & 0x3f) {
cval = (c & 0x10) >> 2;
cval |= (c & 0x06) >> 1;
}
pallook64[c] = lcd_cols[cval];
cval = 0;
if (c & 0x0f)
cval = (c & 0x0e) >> 1;
pallook16[c] = lcd_cols[cval];
#endif
}
}
jega_recalctimings(jega);
} else if (p65idx == 0x05) {
if (val & 0x10)
if (val & 0x10) {
/* Power off (instead this call hardware reset here) */
device_reset_all(DEVICE_ALL);
resetx86();
/* Actually, power off - we have a function for that! */
// plat_power_off();
}
}
}
return;
@@ -820,7 +980,7 @@ if386jega_init(const device_t *info)
memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE);
LoadFontxFile(JEGA_PATH_FONTDBCS, jega);
jega_commoninit(jega);
jega_commoninit(info, jega, 0);
io_sethandler(0x0063, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega);
io_sethandler(0x0065, 1, if386_p6x_read, NULL, NULL, if386_p6x_write, NULL, NULL, jega);

View File

@@ -11,7 +11,6 @@
* Notes: There are some known issues that should be corrected.
* - Incorrect foreground text color appears on an active window in OS/2 J1.3.
* - Glitches some part of graphics on the Control Panel in OS/2 J2.1 beta.
* - The screen resolution and blanking interval time maybe not correct.
*
* The code should be tested with following cases.
* - Execute MODE 0, 1, 3 and 4 commands in DOS K3.3 to test various video modes.
@@ -30,7 +29,6 @@
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdatomic.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
@@ -41,7 +39,6 @@
#include <86box/mca.h>
#include <86box/rom.h>
#include <86box/plat.h>
#include <86box/thread.h>
#include <86box/video.h>
#include <86box/vid_ps55da2.h>
#include <86box/vid_svga.h>
@@ -257,8 +254,9 @@
#endif
#ifdef ENABLE_DA2_LOG
// # define ENABLE_DA2_DEBUGIO 1
// # define ENABLE_DA2_DEBUGBLT 1
# define ENABLE_DA2_DEBUGVRAM 1
// # define ENABLE_DA2_DEBUGVRAM 1
// # define ENABLE_DA2_DEBUGFULLSCREEN 1
// # define ENABLE_DA2_DEBUGMONWAIT 1
int da2_do_log = ENABLE_DA2_LOG;
@@ -277,6 +275,11 @@ da2_log(const char *fmt, ...)
#else
# define da2_log(fmt, ...)
#endif
#ifdef ENABLE_DA2_DEBUGIO
# define da2_iolog da2_log
#else
# define da2_iolog(fmt, ...)
#endif
#ifdef ENABLE_DA2_DEBUGBLT
# define da2_bltlog da2_log
#else
@@ -284,10 +287,8 @@ da2_log(const char *fmt, ...)
#endif
typedef struct da2_t {
// mem_mapping_t vmapping;
mem_mapping_t cmapping;
// uint8_t crtcreg;
uint8_t ioctl[16];
uint8_t fctl[32];
uint16_t crtc[128];
@@ -297,7 +298,6 @@ typedef struct da2_t {
uint8_t attrc[0x40];
int attraddr, attrff;
int attr_palette_enable;
// uint8_t seqregs[64];
int outflipflop;
int inflipflop;
int iolatch;
@@ -306,13 +306,9 @@ typedef struct da2_t {
int fctladdr;
int crtcaddr;
uint32_t decode_mask;
uint32_t vram_max;
uint32_t gdcla[8];
uint32_t gdcinput[8];
uint32_t gdcsrc[8];
uint32_t debug_vramold[8];
uint8_t dac_mask, dac_status;
int dac_read, dac_write, dac_pos;
@@ -322,20 +318,15 @@ typedef struct da2_t {
uint8_t plane_mask;
int fb_only;
int fast;
uint8_t colourcompare, colournocare;
int readmode, writemode, readplane;
int writemode, readplane;
uint8_t planemask;
uint32_t charseta, charsetb;
uint8_t egapal[16];
uint32_t pallook[512];
PALETTE vgapal;
int vtotal, dispend, vsyncstart, split, vblankstart;
int hdisp, hdisp_old, htotal, hdisp_time, rowoffset;
int hdisp, htotal, hdisp_time, rowoffset;
int lowres, interlace;
int rowcount;
double clock;
@@ -362,13 +353,9 @@ typedef struct da2_t {
/* Attribute Buffer E0000-E0FFFh (4 KB) */
uint8_t *cram;
/* (cram size - 1) >> 3 = 0xFFF */
// uint32_t cram_display_mask;
/* APA Buffer A0000-BFFFFh (128 KB) */
uint8_t *vram;
/* xxh */
uint8_t *changedvram;
/* (vram size - 1) >> 3 = 0x1FFFF */
uint32_t vram_display_mask;
int fullchange;
@@ -379,7 +366,6 @@ typedef struct da2_t {
card should not attempt to display anything */
int override;
/* end VGA compatible regs*/
struct
{
int enable;
@@ -436,13 +422,13 @@ typedef struct da2_t {
int old_pos2;
} da2_t;
void da2_recalctimings(da2_t *da2);
static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p);
void da2_bitblt_exec(void *p);
void da2_updatevidselector(da2_t *da2);
void da2_reset_ioctl(da2_t *da2);
static void da2_reset(void *priv);
uint16_t rightRotate(uint16_t data, uint8_t count);
static void da2_recalctimings(da2_t *da2);
static void da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p);
static void da2_bitblt_exec(void *p);
static void da2_updatevidselector(da2_t *da2);
static void da2_reset_ioctl(da2_t *da2);
static void da2_reset(void *priv);
static uint16_t rightRotate(uint16_t data, uint8_t count);
typedef union {
uint32_t d;
@@ -454,7 +440,7 @@ typedef struct {
} pixel32;
/* safety read for internal functions */
uint32_t
static uint32_t
DA2_vram_r(uint32_t addr, da2_t *da2)
{
if (addr & ~DA2_MASK_VRAM)
@@ -462,7 +448,7 @@ DA2_vram_r(uint32_t addr, da2_t *da2)
return da2->vram[addr];
}
/* safety write for internal functions */
void
static void
DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2)
{
if (addr & ~DA2_MASK_VRAM)
@@ -471,7 +457,7 @@ DA2_vram_w(uint32_t addr, uint8_t val, da2_t *da2)
return;
}
/* write pixel data with rop (Note: bitmask must be in big endian) */
void
static void
DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *srcpx, da2_t *da2)
{
uint32_t writepx[8];
@@ -521,7 +507,7 @@ DA2_WritePlaneDataWithBitmask(uint32_t destaddr, const uint16_t mask, pixel32 *s
}
}
void
static void
DA2_DrawColorWithBitmask(uint32_t destaddr, uint8_t color, uint16_t mask, da2_t *da2)
{
pixel32 srcpx;
@@ -559,7 +545,7 @@ Param Desc
33 Size W
35 Size H
*/
void
static void
DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2)
{
pixel32 srcpx;
@@ -573,7 +559,7 @@ DA2_CopyPlaneDataWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask,
DA2_WritePlaneDataWithBitmask(destaddr, mask, &srcpx, da2);
}
void
static void
DA2_PutcharWithBitmask(uint32_t srcaddr, uint32_t destaddr, uint16_t mask, da2_t *da2)
{
pixel32 srcpx;
@@ -660,7 +646,7 @@ IBMJtoSJIS(uint16_t knj)
return knj;
}
#endif
void
static void
da2_bitblt_load(da2_t *da2)
{
uint32_t value32;
@@ -897,7 +883,7 @@ da2_bitblt_load(da2_t *da2)
}
}
}
void
static void
da2_bitblt_exec(void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -1104,7 +1090,7 @@ da2_bitblt_exec(void *p)
break;
}
}
void
static void
da2_bitblt_dopayload(void *priv)
{
da2_t *da2 = (da2_t *) priv;
@@ -1121,7 +1107,7 @@ da2_bitblt_dopayload(void *priv)
}
}
void
static void
da2_out(uint16_t addr, uint16_t val, void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -1147,7 +1133,7 @@ da2_out(uint16_t addr, uint16_t val, void *p)
da2->dac_pos = 0;
break;
case 0x3C9: /* Data */
// da2_log("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI);
// da2_iolog("DA2 Out addr %03X idx %d:%d val %02X %04X:%04X esdi %04X:%04X\n", addr, da2->dac_write, da2->dac_pos, val, cs >> 4, cpu_state.pc, ES, DI);
da2->dac_status = 0;
da2->fullchange = changeframecount;
switch (da2->dac_pos) {
@@ -1176,11 +1162,11 @@ da2_out(uint16_t addr, uint16_t val, void *p)
da2->ioctladdr = val;
break;
case LS_DATA:
// da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->ioctladdr, val, cs >> 4, cpu_state.pc);
if (da2->ioctladdr > 0xf)
return;
if (da2->ioctl[da2->ioctladdr & 15] != val)
da2_log("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc);
da2_iolog("ioctl changed %x: %x -> %x %04X:%04X\n", da2->ioctladdr & 15, da2->ioctl[da2->ioctladdr & 15], val, cs >> 4, cpu_state.pc);
oldval = da2->ioctl[da2->ioctladdr];
da2->ioctl[da2->ioctladdr] = val;
if (oldval != val) {
@@ -1197,15 +1183,15 @@ da2_out(uint16_t addr, uint16_t val, void *p)
da2->fctladdr = val;
break;
case LF_DATA:
// da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc);
if (da2->fctladdr > 0x1f)
return;
if (da2->fctl[da2->fctladdr & 0x1f] != val)
da2_log("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc);
da2_iolog("fctl changed %x: %x -> %x %04X:%04X\n", da2->fctladdr & 0x1f, da2->fctl[da2->fctladdr & 0x1f], val, cs >> 4, cpu_state.pc);
oldval = da2->fctl[da2->fctladdr];
da2->fctl[da2->fctladdr] = val;
if (da2->fctladdr == 0 && oldval != val) {
da2_log("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc);
da2_iolog("DA2 Out FCTL addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->fctladdr, val, cs >> 4, cpu_state.pc);
}
break;
case LC_INDEX:
@@ -1215,7 +1201,7 @@ da2_out(uint16_t addr, uint16_t val, void *p)
if (da2->crtcaddr > 0x1f)
return;
if (!(da2->crtcaddr == LC_CURSOR_LOC_HIGH || da2->crtcaddr == LC_CURSOR_LOC_LOWJ))
da2_log("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc);
da2_iolog("DA2 Out addr %03X idx %02X val %02X %04X:%04X\n", addr, da2->crtcaddr, val, cs >> 4, cpu_state.pc);
if (!(da2->crtc[da2->crtcaddr] ^ val))
return;
switch (da2->crtcaddr) {
@@ -1256,7 +1242,8 @@ da2_out(uint16_t addr, uint16_t val, void *p)
case LC_VERTICAL_SYNC_START:
case LC_V_DISPLAY_ENABLE_END:
case LC_START_VERTICAL_BLANK:
case LC_END_VERTICAL_BLANK:
case LC_START_H_DISPLAY_ENAB:
case LC_START_V_DISPLAY_ENAB:
case LC_VIEWPORT_PRIORITY:
da2->fullchange = changeframecount;
da2_recalctimings(da2);
@@ -1266,7 +1253,7 @@ da2_out(uint16_t addr, uint16_t val, void *p)
}
break;
case LV_PORT:
// da2_log("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc);
// da2_iolog("DA2 Out addr %03X val %02X ff %d %04X:%04X\n", addr, val, da2->attrff,cs >> 4, cpu_state.pc);
if (!da2->attrff) {
// da2->attraddr = val & 31;
da2->attraddr = val & 0x3f;
@@ -1275,14 +1262,14 @@ da2_out(uint16_t addr, uint16_t val, void *p)
da2->attr_palette_enable = val & 0x20;
da2_recalctimings(da2);
}
// da2_log("set attraddr: %X\n", da2->attraddr);
// da2_iolog("set attraddr: %X\n", da2->attraddr);
} else {
if ((da2->attraddr == LV_PANNING) && (da2->attrc[LV_PANNING] != val))
da2->fullchange = changeframecount;
if (da2->attrc[da2->attraddr & 0x3f] != val)
da2_log("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val);
da2_iolog("attr changed %x: %x -> %x\n", da2->attraddr & 0x3f, da2->attrc[da2->attraddr & 0x3f], val);
da2->attrc[da2->attraddr & 0x3f] = val;
// da2_log("set attrc %x: %x\n", da2->attraddr & 31, val);
// da2_iolog("set attrc %x: %x\n", da2->attraddr & 31, val);
if (da2->attraddr < 16)
da2->fullchange = changeframecount;
if (da2->attraddr == LV_MODE_CONTROL || da2->attraddr < 0x10) {
@@ -1330,12 +1317,12 @@ da2_out(uint16_t addr, uint16_t val, void *p)
da2->attrc[da2->attraddr & 0x3f] = val;
break;
case LG_INDEX:
da2_log("DA2 Out addr %03X val %02X\n", addr, val);
da2_iolog("DA2 Out addr %03X val %02X\n", addr, val);
da2->gdcaddr = val;
break;
case LG_DATA:
// if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_log("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI);
da2_log("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val);
// if(da2->gdcaddr != 8 && da2->gdcaddr != 9) da2_iolog("DA2 GCOut idx %X val %02X %04X:%04X esdi %04X:%04X\n", da2->gdcaddr, val, cs >> 4, cpu_state.pc, ES, DI);
da2_iolog("DA2 Out addr %03X idx %02X val %02X\n", addr, da2->gdcaddr, val);
da2->gdcreg[da2->gdcaddr & 0x0f] = val & 0xff;
switch (da2->gdcaddr & 0x1f) {
case LG_READ_MAP_SELECT:
@@ -1355,7 +1342,7 @@ da2_out(uint16_t addr, uint16_t val, void *p)
case LG_COMMAND:
break;
case LG_SET_RESET_2:
da2_log("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val);
da2_iolog("!!!DA2 GC Out addr %03X idx 10 val %02X\n", addr, val);
return;
}
break;
@@ -1363,12 +1350,12 @@ da2_out(uint16_t addr, uint16_t val, void *p)
// da2->gdcreg[5] = val & 0xff;
// break;
default:
da2_log("DA2? Out addr %03X val %02X\n", addr, val);
da2_iolog("DA2? Out addr %03X val %02X\n", addr, val);
break;
}
}
uint16_t
static uint16_t
da2_in(uint16_t addr, void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -1436,17 +1423,17 @@ da2_in(uint16_t addr, void *p)
// if (da2->bitblt.indata) /* for OS/2 J1.3 command prompt scrolling */
// da2_bitblt_dopayload(da2);
if (da2->bitblt.exec != DA2_BLT_CIDLE) {
// da2_log("exec:%x\n", da2->bitblt.exec);
// da2_iolog("exec:%x\n", da2->bitblt.exec);
temp |= 0x01; /* wait (bit 3 + bit 0) ? need verify */
// if (!da2->bitblt.timer.enabled)
//{
// da2_log("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc);
// da2_iolog("bitblt timer restarted!! %04X:%04X\n", cs >> 4, cpu_state.pc);
// timer_advance_u64(&da2->bitblt.timer, da2->bitblt.timerspeed);
// }
}
if (da2->bitblt.indata) temp |= 0x08;
#ifdef ENABLE_DA2_DEBUGMONWAIT
da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc);
da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->ioctladdr, temp, cs >> 4, cpu_state.pc);
#endif
}
break;
@@ -1479,7 +1466,7 @@ da2_in(uint16_t addr, void *p)
temp = da2->cgastat;
} else
temp = da2->attrc[da2->attraddr];
// da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->attraddr, temp, cs >> 4, cpu_state.pc);
da2->attrff = 0; /* reset flipflop (VGA does not reset flipflop) */
break;
case LG_INDEX:
@@ -1487,10 +1474,10 @@ da2_in(uint16_t addr, void *p)
break;
case LG_DATA:
temp = da2->gdcreg[da2->gdcaddr & 0x1f];
// da2_log("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 In %04X(%02X) %04X %04X:%04X\n", addr, da2->gdcaddr, temp, cs >> 4, cpu_state.pc);
break;
}
// da2_log("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
return temp;
}
/*
@@ -1504,11 +1491,11 @@ da2_in(uint16_t addr, void *p)
* out b(idx), in b, in b(data)
* out b(idx), in w(data)
*/
void
static void
da2_outb(uint16_t addr, uint8_t val, void *p)
{
da2_t *da2 = (da2_t *) p;
// da2_log("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI);
// da2_iolog("DA2 Outb addr %03X val %02X %04X:%04X es:di=%x:%x ds:si=%x:%x\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI);
da2->inflipflop = 0;
switch (addr) {
case LS_DATA:
@@ -1538,7 +1525,7 @@ da2_outb(uint16_t addr, uint8_t val, void *p)
void
da2_outw(uint16_t addr, uint16_t val, void *p)
{
da2_log("DA2 Outw addr %03X val %04X\n", addr, val);
da2_iolog("DA2 Outw addr %03X val %04X\n", addr, val);
da2_t *da2 = (da2_t *) p;
da2->inflipflop = 0;
switch (addr) {
@@ -1558,8 +1545,8 @@ da2_outw(uint16_t addr, uint16_t val, void *p)
da2->outflipflop = 0;
break;
case 0x3EC:
// da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
da2_log(" ");
// da2_iolog("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
da2_iolog(" ");
// val = rightRotate(val, 8);
// da2_out(LG_DATA, val, da2);
da2_out(LG_DATA, val >> 8, da2);
@@ -1585,12 +1572,12 @@ da2_outw(uint16_t addr, uint16_t val, void *p)
break;
case AC_REG:
/* no register is revealed */
da2_log("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
da2_iolog("DA2 Outw addr %03X val %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
da2->reg3ee[val & 0x0f] = val >> 8;
break;
}
}
uint8_t
static uint8_t
da2_inb(uint16_t addr, void *p)
{
uint8_t temp;
@@ -1620,10 +1607,10 @@ da2_inb(uint16_t addr, void *p)
da2->inflipflop = 0;
break;
}
// da2_log("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
// da2_iolog("DA2 Inb %04X %02X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
return temp;
}
uint16_t
static uint16_t
da2_inw(uint16_t addr, void *p)
{
uint16_t temp;
@@ -1631,11 +1618,11 @@ da2_inw(uint16_t addr, void *p)
da2->inflipflop = 0;
da2->outflipflop = 0;
temp = da2_in(addr, da2);
da2_log("DA2 Inw addr %03X val %04X\n", addr, temp);
da2_iolog("DA2 Inw addr %03X val %04X\n", addr, temp);
return temp;
}
/* IO 03DAh : Input Status Register 2 for DOSSHELL used by DOS J4.0 */
uint8_t
static uint8_t
da2_in_ISR(uint16_t addr, void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -1647,15 +1634,15 @@ da2_in_ISR(uint16_t addr, void *p)
da2->cgastat ^= 0x30;
temp = da2->cgastat;
}
// da2_log("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
// da2_iolog("DA2D In %04X %04X %04X:%04X\n", addr, temp, cs >> 4, cpu_state.pc);
return temp;
}
void
static void
da2_out_ISR(uint16_t addr, uint8_t val, void *p)
{
// da2_t* da2 = (da2_t*)p;
da2_log("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
da2_iolog("DA2D Out %04X %04X %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc);
}
/*
@@ -1759,7 +1746,7 @@ The Font ROM can be accessed via 128 KB memory window located at A0000-BFFFFh.
*/
/* Get character line pattern from jfont rom or gaiji volatile memory */
uint32_t
static uint32_t
getfont_ps55dbcs(int32_t code, int32_t line, void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -1797,14 +1784,14 @@ getfont_ps55dbcs(int32_t code, int32_t line, void *p)
}
/* Reverse the bit order of attribute code IRGB to BGRI(used in Mode 3 and Cursor Color) */
uint8_t
static int8_t
IRGBtoBGRI(uint8_t attr)
{
attr = ((attr & 0x01) << 7) | ((attr & 0x02) << 5) | ((attr & 0x04) << 3) | ((attr & 0x08) << 1);
return attr >>= 4;
}
/* Get the foreground color from the attribute byte */
uint8_t
static uint8_t
getPS55ForeColor(uint8_t attr, da2_t *da2)
{
uint8_t foreground = ~attr & 0x08; /* 0000 1000 */
@@ -1816,7 +1803,7 @@ getPS55ForeColor(uint8_t attr, da2_t *da2)
return foreground;
}
void
static void
da2_render_blank(da2_t *da2)
{
int x, xx;
@@ -1850,12 +1837,13 @@ da2_render_text(da2_t *da2)
int fg, bg;
uint32_t chr_dbcs;
int chr_wide = 0;
int colormode = ((da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) == 0x80);
// da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc);
for (x = 0; x < da2->hdisp; x += 13) {
chr = da2->cram[(da2->ma) & DA2_MASK_CRAM];
attr = da2->cram[(da2->ma + 1) & DA2_MASK_CRAM];
// if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr);
if (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) /* IO 3E8h, Index 1Dh */
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, da2);
@@ -1932,24 +1920,24 @@ da2_render_text(da2_t *da2)
chr_wide = 0;
}
/* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */
if (da2->sc == 27 && attr & 0x40 && ~da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) { /* Underscore only in monochrome mode */
if (da2->sc == da2->crtc[LC_UNDERLINE_LOCATION] && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */
for (uint32_t n = 0; n < 13; n++)
p[n] = da2->pallook[da2->egapal[fg]]; /* under line (white) */
}
/* Column 1 (Vertical Line) */
if (attr & 0x10) {
p[0] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */
p[0] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */
}
if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) { /* HGrid */
for (uint32_t n = 0; n < 13; n++)
p[n] = da2->pallook[da2->egapal[(da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */
p[n] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */
}
/* Drawing text cursor */
drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron);
if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) {
int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13);
int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */
fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2);
int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */
fg = (colormode) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2);
bg = 0;
if (attr & 0x04) { /* Color 0 if reverse */
bg = fg;
@@ -2048,8 +2036,8 @@ da2_render_textm3(da2_t *da2)
drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron);
if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) {
// int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13);
// int cursorcolor = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */
// fg = (da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2;
// int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */
// fg = (colormode) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2;
// bg = 0;
// if (attr & 0x04) {/* Color 0 if reverse */
// bg = fg;
@@ -2066,7 +2054,7 @@ da2_render_textm3(da2_t *da2)
}
}
void
static void
da2_render_color_4bpp(da2_t *da2)
{
int changed_offset = da2->ma >> 9;
@@ -2115,7 +2103,7 @@ da2_render_color_4bpp(da2_t *da2)
}
}
void
static void
da2_render_color_8bpp(da2_t *da2)
{
int changed_offset = da2->ma >> 9;
@@ -2164,23 +2152,25 @@ da2_render_color_8bpp(da2_t *da2)
}
}
void
static void
da2_updatevidselector_tick(void *priv)
{
da2_t *da2 = (da2_t *) priv;
if (da2->ioctl[LS_MODE] & 0x02) {
/* VGA passthrough mode */
da2->override = 1;
timer_disable(&da2->timer);
svga_set_override(da2->mb_vga, 0);
da2_log("DA2 selector: VGA\n");
} else {
svga_set_override(da2->mb_vga, 1);
timer_enable(&da2->timer);
da2->override = 0;
da2_log("DA2 selector: DA2\n");
}
}
void
static void
da2_updatevidselector(da2_t *da2)
{
timer_set_delay_u64(&da2->timer_vidupd, 100000ull * TIMER_USEC);
@@ -2189,15 +2179,16 @@ da2_updatevidselector(da2_t *da2)
/*
INT 10h video modes supported in DOS J4.0 (The DA-2 doesn't have a video BIOS on its card.)
Mode Type Colors Text Base Address PELs Render
3 A/N/K 16 80 x 25 B0000h/B8000h 1040 x 725 textm3
3 A/N/K 16 80 x 25 B0000h/B8000h 1040 x 754 textm3
8 A/N/K 2 80 x 25 E0000h 1040 x 725 text
Ah APA 1 78 x 25 A0000h 1024 x 768 color_4bpp
Dh APA 16 78 x 25 A0000h 1024 x 768 color_4bpp
Eh A/N/K 16 80 x 25 E0000h 1040 x 725 text
Fh APA 256 NA A0000h 1024 x 768 color_8bpp
45h(undoc) APA 16 NA A0000h 1040 x 768 color_4bpp
46h(undoc) APA 16 ? A0000h 1040 x 768 color_4bpp
*/
void
static void
da2_recalctimings(da2_t *da2)
{
double crtcconst;
@@ -2217,10 +2208,10 @@ da2_recalctimings(da2_t *da2)
da2->vblankstart = da2->crtc[LC_START_VERTICAL_BLANK] & 0xfff;
da2->hdisp = da2->crtc[LC_H_DISPLAY_ENABLE_END];
if (da2->crtc[LC_START_H_DISPLAY_ENAB] & 1) {
da2->hdisp--;
da2->dispend -= 29;
}
/* In the video mode 3, you'll see a blank below the screen. It's NOT a bug. */
da2->hdisp -= da2->crtc[LC_START_H_DISPLAY_ENAB];
da2->dispend -= da2->crtc[LC_START_V_DISPLAY_ENAB];
da2->dispend += 1;
da2->htotal = da2->crtc[LC_HORIZONTAL_TOTAL];
da2->htotal += 1;
@@ -2246,15 +2237,14 @@ da2_recalctimings(da2_t *da2)
if (!(da2->ioctl[LS_MODE] & 0x01)) {
da2->hdisp *= 16;
da2->char_width = 13;
da2->hdisp_old = da2->hdisp;
if (da2->crtc[LC_VIEWPORT_PRIORITY] & 0x80) {
da2_log("Set videomode to PS/55 8 bpp graphics.\n");
da2->render = da2_render_color_8bpp;
da2->vram_display_mask = DA2_MASK_A000;
} else { /* PS/55 8-color */
da2_log("Set videomode to PS/55 4 bpp graphics.\n");
da2->vram_display_mask = DA2_MASK_A000;
da2->render = da2_render_color_4bpp;
da2->vram_display_mask = DA2_MASK_A000;
}
} else {
/* text mode */
@@ -2268,7 +2258,6 @@ da2_recalctimings(da2_t *da2)
da2->vram_display_mask = DA2_MASK_CRAM;
}
da2->hdisp *= 13;
da2->hdisp_old = da2->hdisp;
da2->char_width = 13;
}
// if (!da2->scrblank && da2->attr_palette_enable)
@@ -2303,8 +2292,7 @@ da2_recalctimings(da2_t *da2)
da2->dispofftime = TIMER_USEC;
da2_log("da2 horiz total %i display end %i vidclock %f\n", da2->crtc[0], da2->crtc[1], da2->clock);
da2_log("da2 vert total %i display end %i max row %i vsync %i\n",da2->vtotal,da2->dispend,(da2->crtc[9]&31)+1,da2->vsyncstart);
da2_log("total %f on %i cycles off %i cycles frame %i sec %i\n",disptime*crtcconst,da2->dispontime,da2->dispofftime,(da2->dispontime+da2->dispofftime)*da2->vtotal,(da2->dispontime+da2->dispofftime)*da2->vtotal*70);
da2_log("da2 dispon %lu dispoff %lu on(us) %f off(us) %f\n",da2->dispontime, da2->dispofftime, (double)da2->dispontime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0, (double)da2->dispofftime / (double)cpuclock / (double) (1ULL << 32) * 1000000.0);
// da2_log("da2->render %08X\n", da2->render);
}
@@ -2325,12 +2313,10 @@ da2_mapping_update(da2_t *da2)
io_sethandler(0x03d0, 0x000b, da2_in_ISR, NULL, NULL, da2_out_ISR, NULL, NULL, da2);
mem_mapping_enable(&da2->cmapping);
mem_mapping_enable(&da2->mmio.mapping);
timer_enable(&da2->timer);
timer_enable(&da2->bitblt.timer);
} else {
da2_log("DA2 disable registers\n");
timer_disable(&da2->bitblt.timer);
timer_disable(&da2->timer);
mem_mapping_disable(&da2->cmapping);
mem_mapping_disable(&da2->mmio.mapping);
io_removehandler(0x03c0, 0x000a, da2_inb, da2_inw, NULL, da2_outb, da2_outw, NULL, da2);
@@ -2339,14 +2325,14 @@ da2_mapping_update(da2_t *da2)
}
}
uint8_t
static uint8_t
da2_mca_read(int port, void *p)
{
da2_t *da2 = (da2_t *) p;
return da2->pos_regs[port & 7];
}
void
static void
da2_mca_write(int port, uint8_t val, void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -2642,9 +2628,7 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p)
da2->mmdbg_vidaddr = addr;
//}
#endif
cycles -= video_timing_write_b;
da2->changedvram[addr >> 9] = changeframecount;/* 0x1FFFF -> 0x1F */
addr <<= 3;
@@ -2685,27 +2669,13 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p)
da2->gdcinput[i] = (da2->gdcreg[LG_SET_RESETJ] & (1 << i)) ? 0xff : 0;
else
da2->gdcinput[i] = val;
// for (int i = 0; i < 8; i++)
// da2->debug_vramold[i] = da2->vram[addr | i]; /* use latch */
da2_gdcropB(addr, bitmask, da2);
// for (int i = 0; i < 8; i++)
// da2_log("\tsrc %02x in %02x bitm %02x mod %x rop %x: %02x -> %02x\n", da2->gdcsrc[i], da2->gdcinput[i], bitmask, da2->gdcreg[5],da2->gdcreg[LG_COMMAND], da2->debug_vramold[i], da2->vram[addr | i]);//use latch
////da2_log("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr);
}
break;
case 1:/* equiv to vga write mode 2 */
// if (!(da2->gdcreg[LG_COMMAND] & 0x03) && (!da2->gdcreg[LG_ENABLE_SRJ])) {
// for (int i = 0; i < 8; i++)
// if (da2->planemask & (1 << i))
// DA2_vram_w(addr | i, (((val & (1 << i)) ? 0xff : 0) & bitmask) | (da2->gdcsrc[i] & ~bitmask), da2);
// //fprintf(da2->mmdbg_fp, "m1-1");
// } else {
for (int i = 0; i < 8; i++)
da2->gdcinput[i] = ((val & (1 << i)) ? 0xff : 0);
da2_gdcropB(addr, bitmask, da2);
//fprintf(da2->mmdbg_fp, "m1-2");
// }
break;
case 3:/* equiv to vga write mode 3 */
if (da2->gdcreg[LG_DATA_ROTATION] & 7)
@@ -2717,14 +2687,13 @@ da2_mmio_write(uint32_t addr, uint8_t val, void *p)
da2_gdcropB(addr, bitmask, da2);
break;
}
// da2_log("%02x%02x%02x%02x\n", da2->vram[addr + 0], da2->vram[addr + 1], da2->vram[addr + 2], da2->vram[addr + 3]);
} else { /* mode 3h text */
cycles -= video_timing_write_b;
DA2_vram_w(addr, val, da2);
da2->fullchange = 2;
}
}
uint16_t
static uint16_t
rightRotate(uint16_t data, uint8_t count)
{
return (data >> count) | (data << (sizeof(data) * 8 - count));
@@ -2741,8 +2710,7 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p)
#ifdef ENABLE_DA2_DEBUGVRAM
da2_log("da2_wW %x %d %d %02x\n", addr,
addr % (da2->rowoffset * 2) * 8, addr / (da2->rowoffset * 2), val);
// if (!(da2->gdcreg[LG_COMMAND] & 0x08))
//{
if (((int) addr - (int) da2->mmdbg_vidaddr) > 2 || (((int) da2->mmdbg_vidaddr - (int) addr) > 2) || da2->mmdbg_vidaddr == addr) {
fprintf(da2->mmdbg_fp, "\nW %x %x ", addr, val);
for (int i = 0; i <= 0xb; i++)
@@ -2755,7 +2723,6 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p)
fprintf(da2->mmdbg_fp, "%X", pixeldata);
}
da2->mmdbg_vidaddr = addr;
//}
#endif
cycles -= video_timing_write_w;
@@ -2763,7 +2730,6 @@ da2_mmio_gc_writeW(uint32_t addr, uint16_t val, void *p)
// da2_log("da2_gcW %05X %02X %04X:%04X esdi %04X:%04X dssi %04X:%04X\n", addr, val, cs >> 4, cpu_state.pc, ES, DI, DS, SI);
da2->changedvram[addr >> 9] = changeframecount;
// da2->changedvram[(addr + 1) >> 12] = changeframecount;
addr <<= 3;
for (int i = 0; i < 8; i++)
@@ -2900,7 +2866,7 @@ da2_code_readw(uint32_t addr, void *p)
return da2_code_read(addr, da2) | (da2_code_read(addr + 1, da2) << 8);
}
void
static void
da2_doblit(int y1, int y2, int wx, int wy, da2_t *da2)
{
if (wx != xsize || wy != ysize) {
@@ -2919,7 +2885,7 @@ da2_doblit(int y1, int y2, int wx, int wy, da2_t *da2)
video_bpp = 8;
}
void
static void
da2_poll(void *priv)
{
da2_t *da2 = (da2_t *) priv;
@@ -3024,9 +2990,6 @@ da2_poll(void *priv)
da2->cgastat |= 8;
x = da2->hdisp;
// if (da2->interlace && !da2->oddeven) da2->lastline++;
// if (da2->interlace && da2->oddeven) da2->firstline--;
wx = x;
wy = da2->lastline - da2->firstline;
@@ -3043,17 +3006,9 @@ da2_poll(void *priv)
changeframecount = da2->interlace ? 3 : 2;
da2->vslines = 0;
// if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch + (da2->rowoffset << 1) + ((da2->crtc[5] & 0x60) >> 5);
// else da2->ma = da2->maback = da2->ma_latch + ((da2->crtc[5] & 0x60) >> 5);
// da2->ca = ((da2->crtc[0xe] << 8) | da2->crtc[0xf]) + ((da2->crtc[0xb] & 0x60) >> 5) + da2->ca_adj;
/* if (da2->interlace && da2->oddeven) da2->ma = da2->maback = da2->ma_latch;
else*/
da2->ma
= da2->maback = da2->ma_latch;
da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj;
// da2->ma <<= 1;
// da2->maback <<= 1;
da2->ca <<= 1;
// da2_log("Addr %08X vson %03X vsoff %01X\n",da2->ma,da2->vsyncstart,da2->crtc[0x11]&0xF);
@@ -3070,9 +3025,6 @@ da2_poll(void *priv)
if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31))
da2->con = 1;
}
// printf("2 %i\n",da2_vsyncstart);
// da2_log("da2_poll %i %i %i %i %i %i %i\n", ins, da2->dispofftime, da2->dispontime, da2->vidtime, cyc_total, da2->linepos, da2->vc);
// da2_log("r");
}
static void
@@ -3129,7 +3081,7 @@ static uint8_t ps55_palette_color[64][3] = {
{ 0x3F, 0x15, 0x15 }, { 0x3F, 0x15, 0x3F }, { 0x3F, 0x3F, 0x15 }, { 0x3F, 0x3F, 0x3F }
};
void
static void
da2_reset_ioctl(da2_t *da2)
{
da2->ioctl[LS_RESET] = 0x00; /* Bit 0: Reset sequencer */
@@ -3243,7 +3195,7 @@ da2_available(void)
return (rom_present(DA2_FONTROM_PATH_HANT) || rom_present(DA2_FONTROM_PATH_JPAN));
}
void
static void
da2_close(void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -3331,7 +3283,7 @@ da2_close(void *p)
free(da2);
}
void
static void
da2_speed_changed(void *p)
{
da2_t *da2 = (da2_t *) p;
@@ -3339,7 +3291,7 @@ da2_speed_changed(void *p)
da2_recalctimings(da2);
}
void
static void
da2_force_redraw(void *p)
{
da2_t *da2 = (da2_t *) p;

View File

@@ -3519,34 +3519,6 @@ s3_recalctimings(svga_t *svga)
}
}
#ifdef OLD_CODE_REFERENCE
if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_MIROCRYSTAL8S_805 || s3->card_type == S3_NUMBER9_9FX_531 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) {
if (!(svga->crtc[0x5e] & 0x04))
svga->vblankstart = svga->dispend;
if (svga->bpp != 32) {
if (svga->crtc[0x31] & 2)
s3->width = 2048;
else {
if (s3->card_type == S3_MIROCRYSTAL10SD_805) {
if (svga->hdisp == 1280 && s3->width == 1024) {
s3->width = 1280;
}
}
}
} else {
if (s3->card_type == S3_NUMBER9_9FX_531) {
if ((svga->hdisp == 1600) && (s3->width == 1600))
s3->width = 800;
}
}
} else if (s3->chip == S3_86C928) {
if (svga->bpp == 15) {
if (s3->width == 800)
s3->width = 1024;
}
}
#endif
if ((svga->crtc[0x3a] & 0x10) && !svga->lowres) {
s3_log("BPP=%d, pitch=%d, width=%02x, double?=%x, 16bit?=%d, highres?=%d, "
"attr=%02x, hdisp=%d.\n", svga->bpp, s3->width, svga->crtc[0x50],
@@ -3665,29 +3637,6 @@ s3_recalctimings(svga_t *svga)
default:
break;
}
#ifdef OLD_CODE_REFERENCE
if (s3->chip != S3_VISION868) {
if (s3->chip == S3_86C928) {
if (s3->width == 2048 || s3->width == 1280 || s3->width == 1600) {
if ((s3->width != 1600) && (svga->dispend == 1024) && (svga->hdisp != 1280))
svga->hdisp <<= 2;
else
svga->hdisp <<= 1;
}
} else if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968)) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
} else if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
} else if (s3->card_type == S3_SPEA_MERCURY_P64V) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
}
} else if (s3->card_type == S3_NUMBER9_9FX_771)
svga->hdisp <<= 1;
}
#endif
break;
case 15:
svga->render = svga_render_15bpp_highres;
@@ -3856,29 +3805,6 @@ s3_recalctimings(svga_t *svga)
default:
break;
}
#ifdef OLD_CODE_REFERENCE
if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && (s3->card_type != S3_SPEA_MIRAGE_86C805)) {
if (s3->chip == S3_86C928)
svga->hdisp <<= 1;
else if (s3->chip != S3_VISION968)
svga->hdisp >>= 1;
}
if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
else if (s3->card_type == S3_NUMBER9_9FX_771)
svga->hdisp <<= 1;
}
if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) {
if (svga->hdisp == (1408 * 2))
svga->hdisp >>= 1;
else
svga->hdisp = s3->width;
}
if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI)
svga->hdisp = s3->width;
#endif
break;
case 16:
svga->render = svga_render_16bpp_highres;
@@ -4044,35 +3970,6 @@ s3_recalctimings(svga_t *svga)
default:
break;
}
#ifdef OLD_CODE_REFERENCE
if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
}
if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && (s3->card_type != S3_SPEA_MIRAGE_86C805)) {
if (s3->chip == S3_86C928)
svga->hdisp <<= 1;
else if (s3->chip != S3_VISION968)
svga->hdisp >>= 1;
} else if ((s3->card_type == S3_SPEA_MIRAGE_86C801) || (s3->card_type == S3_SPEA_MIRAGE_86C805))
svga->hdisp >>= 1;
if ((s3->chip != S3_VISION868) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) {
if (s3->width == 1280 || s3->width == 1600)
svga->hdisp <<= 1;
else if (s3->card_type == S3_NUMBER9_9FX_771)
svga->hdisp <<= 1;
}
if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) {
if (svga->hdisp == (1408 << 1))
svga->hdisp >>= 1;
else
svga->hdisp = s3->width;
}
if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI)
svga->hdisp = s3->width;
#endif
break;
case 24:
svga->render = svga_render_24bpp_highres;
@@ -4150,34 +4047,6 @@ s3_recalctimings(svga_t *svga)
default:
break;
}
#ifdef OLD_CODE_REFERENCE
if (s3->chip != S3_VISION968) {
if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805)
svga->hdisp /= 3;
else
svga->hdisp = (svga->hdisp * 2) / 3;
if (s3->card_type == S3_SPEA_MERCURY_LITE_PCI) {
if (s3->width == 2048) {
switch (svga->dispend) {
case 480:
svga->hdisp = 640;
break;
default:
break;
}
}
} else if (s3->chip == S3_86C924) {
if (svga->dispend == 480)
svga->hdisp = 640;
}
} else {
if ((s3->card_type == S3_MIROVIDEO40SV_ERGO_968) ||
(s3->card_type == S3_PHOENIX_VISION968) || (s3->card_type == S3_SPEA_MERCURY_P64V))
svga->hdisp = s3->width;
}
#endif
break;
case 32:
svga->render = svga_render_32bpp_highres;
@@ -4262,48 +4131,6 @@ s3_recalctimings(svga_t *svga)
default:
break;
}
#ifdef OLD_CODE_REFERENCE
if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968) && (s3->chip != S3_86C928)) {
if (s3->chip == S3_VISION868)
svga->hdisp >>= 1;
else
svga->hdisp >>= 2;
}
if (s3->width == 1280 || s3->width == 1600 || (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_NUMBER9_9FX_771))
svga->hdisp <<= 1;
if (s3->card_type == S3_NUMBER9_9FX_771) {
if (svga->hdisp == 832)
svga->hdisp -= 32;
}
if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) {
svga->hdisp = s3->width;
if (s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964) {
if (s3->width == 800 || s3->width == 1024 || s3->width == 1600) {
switch (svga->dispend) {
case 400:
case 480:
svga->hdisp = 640;
break;
case 576:
if (s3->width == 1600)
s3->width = 800;
svga->hdisp = 768;
break;
case 600:
if (s3->width == 1600)
s3->width = 800;
svga->hdisp = 800;
break;
default:
break;
}
}
}
}
#endif
break;
default:
@@ -4362,7 +4189,7 @@ s3_trio64v_recalctimings(svga_t *svga)
svga->htotal |= 0x100;
if (svga->crtc[0x5d] & 0x02) {
svga->hdisp_time |= 0x100;
svga->hdisp |= 0x100 * svga->dots_per_clock;
svga->hdisp |= (0x100 * svga->dots_per_clock);
}
if (svga->crtc[0x5e] & 0x01)
svga->vtotal |= 0x400;
@@ -4681,6 +4508,7 @@ s3_trio64_getclock(int clock, void *priv)
return 25175000.0;
if (clock == 1)
return 28322000.0;
m = svga->seqregs[0x13] + 2;
n1 = (svga->seqregs[0x12] & 0x1f) + 2;
n2 = ((svga->seqregs[0x12] >> 5) & 0x07);
@@ -9523,7 +9351,6 @@ s3_disable_handlers(s3_t *s3)
reset_state->bios_rom.mapping = s3->bios_rom.mapping;
reset_state->svga.timer = s3->svga.timer;
reset_state->svga.timer8514 = s3->svga.timer8514;
memset(s3->svga.vram, 0x00, s3->svga.vram_max + 8);
memset(s3->svga.changedvram, 0x00, (s3->svga.vram_max >> 12) + 1);

View File

@@ -739,7 +739,8 @@ svga_recalctimings(svga_t *svga)
svga->vblankstart++;
svga->hdisp = svga->crtc[1];
svga->hdisp++;
if (svga->crtc[1] & 1)
svga->hdisp++;
svga->htotal = svga->crtc[0];
/* +5 has been verified by Sergi to be correct - +6 must have been an off by one error. */
@@ -944,7 +945,7 @@ svga_recalctimings(svga_t *svga)
if (dev->on) {
uint32_t dot8514 = dev->h_blankstart;
uint32_t adj_dot8514 = dev->h_blankstart;
uint32_t eff_mask8514 = 0x0000003f;
uint32_t eff_mask8514 = 0x0000001f;
dev->hblank_sub = 0;
while (adj_dot8514 < (dev->h_total << 1)) {
@@ -1029,8 +1030,9 @@ svga_recalctimings(svga_t *svga)
if (ibm8514_active && (svga->dev8514 != NULL)) {
if (dev->on) {
disptime8514 = dev->h_total ? dev->h_total : TIMER_USEC;
_dispontime8514 = dev->hdisped;
disptime8514 = dev->h_total;
_dispontime8514 = (dev->hdisped + 1) * 8;
svga_log("HDISPED 8514=%d, htotal=%02x.\n", (dev->hdisped + 1) << 3, dev->h_total);
}
}
@@ -1174,7 +1176,10 @@ svga_do_render(svga_t *svga)
}
if (!svga->override) {
svga->render(svga);
if (svga->render_override)
svga->render_override(svga->priv_parent);
else
svga->render(svga);
svga->x_add = (svga->monitor->mon_overscan_x >> 1);
svga_render_overscan_left(svga);

View File

@@ -96,6 +96,7 @@ video_cards[] = {
{ .device = &genius_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &nga_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &ogc_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &jvga_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &oti037c_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &oti067_device, .flags = VIDEO_FLAG_TYPE_NONE },
{ .device = &oti077_device, .flags = VIDEO_FLAG_TYPE_NONE },

View File

@@ -31,7 +31,8 @@
#include <86box/vid_svga.h>
#include <86box/vid_vga.h>
static video_timings_t timing_vga = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 };
video_timings_t timing_vga = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 };
static video_timings_t timing_ps1_svga_isa = { .type = VIDEO_ISA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 };
static video_timings_t timing_ps1_svga_mca = { .type = VIDEO_MCA, .write_b = 6, .write_w = 8, .write_l = 16, .read_b = 6, .read_w = 8, .read_l = 16 };
@@ -135,27 +136,34 @@ int vga_isenabled(void* p)
return svga->vga_enabled;
}
static void *
vga_init(const device_t *info)
void
vga_init(const device_t *info, vga_t *vga, int enabled)
{
vga_t *vga = malloc(sizeof(vga_t));
memset(vga, 0, sizeof(vga_t));
rom_init(&vga->bios_rom, "roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL);
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga);
svga_init(info, &vga->svga, vga, 1 << 18, /*256kb*/
NULL,
vga_in, vga_out,
NULL,
NULL);
io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
vga->svga.bpp = 8;
vga->svga.miscout = 1;
vga->svga.vga_enabled = enabled;
}
static void *
vga_standalone_init(const device_t *info)
{
vga_t *vga = calloc(1, sizeof(vga_t));
rom_init(&vga->bios_rom, "roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL);
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga);
vga_init(info, vga, 0);
io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
return vga;
}
@@ -163,26 +171,17 @@ vga_init(const device_t *info)
void *
ps1vga_init(const device_t *info)
{
vga_t *vga = malloc(sizeof(vga_t));
memset(vga, 0, sizeof(vga_t));
vga_t *vga = calloc(1, sizeof(vga_t));
if (info->flags & DEVICE_MCA)
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_mca);
else
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ps1_svga_isa);
svga_init(info, &vga->svga, vga, 1 << 18, /*256kb*/
NULL,
vga_in, vga_out,
NULL,
NULL);
vga_init(info, vga, 1);
io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga);
vga->svga.bpp = 8;
vga->svga.miscout = 1;
vga->svga.vga_enabled = 1;
return vga;
}
@@ -223,7 +222,7 @@ const device_t vga_device = {
.internal_name = "vga",
.flags = DEVICE_ISA,
.local = 0,
.init = vga_init,
.init = vga_standalone_init,
.close = vga_close,
.reset = NULL,
.available = vga_available,