User Tools

Site Tools


blog:pushbx:2024:0701_support_of_segment_overrides_for_xlatb

Support of segment overrides for XLATB

Copied from a mail sent to freedos-devel:

On at 2024-06-30 23:04 +0200, Bernd Böckmann via Freedos-devel wrote:

Hello,

I have a question our assembly people: I stumbled upon an unusual instruction in the EDR-DOS source [1]. In RASM86 this is expressed as

XLAT CS:AL

which gets encoded as 2E D7.

So this is a CS segment override prefix for an otherwise usual XLAT instruction. I found no way to reproduce this instruction in JWasm other than doing the following:

DB 2eh
XLAT

The Intel documentation for XLAT explains that the value to be added to AL is fetched from DS:BX, so probably the DS gets replaced by the CS override. But is the override prefix valid at this point, and does this work on all common CPUs? Intel documentation is silent about this.

Thanks,
Bernd

[1] https://github.com/SvarDOS/edrdos/blob/d579db43a97554dcac35becf510d7be8f5a85aae/drdos/header.a86#L1250

Hello Bernd,

A simple web search for "segment override xlatb" without the quote marks does find some relevant results, in particular this retrocomputing stackexchange thread. Quoting part of the question:

XLAT with a segment override prefix: Manuals for 8086 and 80286 only mention that it uses the DS register. It was first mentioned in the 80386 manual that it accepts segment prefixes.

One of the answers has this to say:

XLAT with segment override - works the same as 8088, segment override for base address can be CS:[BX] or ES:[BX]. … segment overrides for XLAT on a V20 do seem to work consistent with the 808x.

I just fired up my HP 95LX which runs a NEC V20 as well. I can confirm that cs xlatb, es xlatb, and ss xlatb all work as expected.

Another answer claims that MAME does not support XLATB with a segment override:

MAME's 8086/88/186/188/286 emulator here, V20/V30/V33/V33A emulator here, and V30MZ emulator here all support 83/1, 83/4, and 83/6, and they all don't support a segment override for XLAT (the prefix is allowed but ignored). Search for 0x83 and 0xd7 to find the implementations.

The fact that they all agree doesn't necessarily mean they're correct, since they all seem to have been forked from common code at some point. But I suppose that whoever implemented 83/x with no CPU-version test and put an explicit DS in the XLAT implementation probably knew what they were doing.

Consequently, I added a remark on this to my NASM v2.05 based instruction reference:

On 386 or higher level machines, the segment register used to load from [BX+AL] or [EBX+AL] can be overridden by using a segment register name as a prefix (for example, ES XLATB). It is reported that a segment override may be ignored by CPUs of a lower level than a 386.

I added this remark on 2022-03-18. On 2021-06-06 I replaced a use of cs xlatb in inicomp's lzd.asm, most directly by a sequence that costs 3 bytes more than cs xlatb, like so:

push ds
 push cs
 pop ds
xlatb
pop ds

Later I replaced the use of xlatb by code that branches to get the next state number.

However, looking at the current source of MAME (mame/src/devices/cpu/i86/i86.cpp and .../cpu/nec/necinstr.hxx) it appears as if XLATB was changed to use a segment override prefix since this answer was written (2021-06-04).

i86.cpp has:

case 0xd7: // i_trans
	m_regs.b[AL] = GetMemB( DS, m_regs.w[BX] + m_regs.b[AL] );
	CLK(XLAT);
	break;

This calls GetMemB in i86inline.h:

inline uint8_t i8086_common_cpu_device::GetMemB(int seg, uint16_t offset)
{
	return read_byte(calc_addr(seg, offset, 1, I8086_READ));
}

This calls calc_addr:

uint32_t i8086_common_cpu_device::calc_addr(int seg, uint16_t offset, int size, int op, bool override)
{
	if ( m_seg_prefix && (seg==DS || seg==SS) && override )
	{
		m_easeg = m_seg_prefix;
		return (m_sregs[m_prefix_seg] << 4) + offset;
	}
	else

calc_addr with only 4 parameters uses the default for the override parameter, which is equal to true:

virtual uint32_t calc_addr(int seg, uint16_t offset, int size, int op, bool override = true);

So the 8086 sources for current MAME actually do support segment overrides for XLATB.

necinstr.hxx uses this line to implement XLATB:

OP( 0xd7, i_trans  ) { uint32_t dest = (Wreg(BW)+Breg(AL))&0xffff; Breg(AL) = GetMemB(DS0, dest); CLKS(9,9,5); }

I'm unsure which GetMemB definition is used here, but it uses "DS0" which looking at eg the A0h to A3h opcodes is what is known as DS on the 8086 and in a way that allows a segment override:

OP( 0xa0, i_mov_aldisp ) { uint32_t addr; addr = fetchword(); Breg(AL) = GetMemB(DS0, addr); CLKS(10,10,5); }
OP( 0xa1, i_mov_axdisp ) { uint32_t addr; addr = fetchword(); Wreg(AW) = GetMemW(DS0, addr); CLKW(14,14,7,14,10,5,addr); }
OP( 0xa2, i_mov_dispal ) { uint32_t addr; addr = fetchword(); PutMemB(DS0, addr, Breg(AL));  CLKS(9,9,3); }
OP( 0xa3, i_mov_dispax ) { uint32_t addr; addr = fetchword(); PutMemW(DS0, addr, Wreg(AW));  CLKW(13,13,5,13,9,3,addr); }

(DS1 appears to be 8086's ES.)

Moreover, I believe that the RC.SE answer is actually wrong. The git blame for the 0xd7 GetMemB in (then) src/emu/cpu/i86/i86.c points to a 2013-07-02 commit. In this commit GetMemB already can use a segment override if the first parameter is passed as "DS". This contradicts the 2021-06-04 RC.SE answer, which claimed that no segment override prefix was supported at that time. It appears that the user was wrong.

So actually it seems everyone supports segment overrides for XLATB!

Regards, ecm

Discussion

E. C. MaslochE. C. Masloch, 2024-07-01 20:01:01 +0200 Jul Mon

The freedos-devel mail is archived at https://sourceforge.net/p/freedos/mailman/message/58790665/

I added a comment to the mistaken answer on retrocomputing stackexchange:

Actually, I looked into your claim and it appears that the use of GetMemB(DS, ….) in the source code does support segment override prefixes. You can follow the definitions of the functions until you get to calc_addr or you can compare other uses of GetMemB in the same source file to see that passing DS actually does allow for overrides. I wrote up a report on the freedos-user mailing list as well as (a direct copy) on my blog: https://pushbx.org/ecm/dokuwiki/blog/pushbx/2024/0701_support_of_segment_overrides_for_xlatb

You could leave a comment if you were logged in.
blog/pushbx/2024/0701_support_of_segment_overrides_for_xlatb.txt · Last modified: 2024-07-01 19:47:03 +0200 Jul Mon by ecm