PDA

View Full Version : Issue assembling fig-FORTH with MASM 4.0



smp
March 28th, 2015, 01:12 PM
Hello all,

I recently downloaded a copy of MASM version 4.0 to run on my HP-110+ machine with an external 720K floppy drive.

My HP-110+ has MS-DOS 2.11 in ROM, hence I was looking for a version of MASM to match up with that.

My goal is to assemble a copy of fig-FORTH to run on this system. I have the published assembly listing for fig-FORTH for the IBM PC from the Forth Interest Group, and also the assembly code in a text file for input to the assembler.

The fig-FORTH assembly listing has a header on each page indicating the assembler used at the time: The IBM Personal Computer Macro Assembler. When I attempt to assemble my code, the listing header says: Microsoft (R) Macro Assembler Version 4.00.

When I attempt to assemble my code, I get 2 severe errors, both of them are "phase error between passes."

I've been able to track down the issue to this:

On line 3402, the code is: XOR EPRINT,1
The fig-FORTH assembly listing shows the code generated should be: 80 36 14CC R 01 90
The code generated by my attempt is: 80 36 14CC R 01

On line 3436, the code is: TEST EPRINT,1
The fig-FORTH assembly listing shows the code generated should be: F6 06 14CC R 01 90
The code generated by my attempt is: F6 06 14CC R 01

As you can see, in both cases, my assembly does not generate the last byte in the sequence.

On line 3446, the code is: EPRINT DB 0,0
In both the fig-FORTH assembly listing and also my assembly output two 00 bytes get located at address 14CC and 14CD.

I see that I am not using the very same assembler that was originally used to generate the fig-FORTH assembly listing, but I cannot determine what is going wrong for me in my attempts to assemble the same code.

Is it possible to diagnose what might be going on from these bits of information? I can provide the fig-FORTH assembly listing and also my assembly code text file. I have been through all the assembly listings and both of the assemblies are the same with all addresses and code matching up except for in the two areas I point out here. Interestingly (for me anyway) in my assembly listing, the code address gets off by one byte where the error happens, but the assembler gets back to the correct address within a couple of lines of code after the error.

I am a novice with 8086 code. I am much more capable with the 8080/8085. I was hoping that I would be able to assemble this code and get going, but such is not yet the case. Could this just be an issue because the EPRINT DB 0,0 comes after the two lines of code that use it? Do I really need to go back and get the original IBM PC Macro Assembler?

Thanks in advance, for any thoughts that you may have to offer.

smp

smp
March 28th, 2015, 02:07 PM
Here's a thought:

Both of the actions, XOR EPRINT,1 and TEST EPRINT,1 look like byte-size actions, however, the definition EPRINT DB 0,0 looks like it is defining a word. Could that be the reason that MASM does not produce the last byte in the code output like the original assembler did?

How would I change the XOR and TEST statements to indicate byte or word actions specifically? Should I change the EPRINT DB 0,0 to be simply EPRINT DB 0?

Thanks in advance...

smp

Chuck(G)
March 28th, 2015, 02:08 PM
That extra '90' is not part of the instruction; it's a no-op. DEBUG interprets the shorter versions correctly.

My guess is that the original assembler is a bit brain-dead and allocates 2 bytes for the immediate field instruction during the first pass and then pads the excess out with a NOP during the second pass.

smp
March 28th, 2015, 03:12 PM
Hi Chuck,

Thanks for the response.

With the two errors, MASM does not produce an .OBJ file, so I cannot continue and adjust the code with DEBUG.

Do you have a suggestion on how I should adjust the source to avoid the "phase error between passes?"

Thanks very much for your attention!

smp

gslick
March 28th, 2015, 06:25 PM
See if using BYTE PTR solves the problem by explicitly telling the assembler what the argument size is for EPRINT in the first pass. And if that works then add the NOP if you want the binary result to be the same.


PKEY: CALL CI ;CONSOLE INPUT
CMP AL,DLE ;PRINTER TOGGLE?
JNE PKEY1 ;NO
XOR BYTE PTR EPRINT,1 ;TOGGLE ECHO
NOP
JMP PKEY ;GET ANOTHER KEY
PKEY1: MOV AH,0 ;MAKE 16 BITS
JMP APUSH ;SAVE KEY VALUE

POUT PROC NEAR
CALL CHO ;CONSOLE OUT
TEST BYTE PTR EPRINT,1 ;PRINTER ECHO?
NOP
JZ POUT1 ;OFF
CALL LO ;LIST OUTPUT
POUT1: RET
POUT ENDP

Chuck(G)
March 28th, 2015, 07:13 PM
Yup, that should do it. That's why that 90 is there--the assembler during the first pass doesn't know what to generate (word or byte) since it hasn't seen the data items defined yet. So it assumes word, and after pass 1 is complete, discovers that the assumption is wrong, but saves itself, because it inserted a NOP to fill the unused byte of the immediate field.

This works, but is a lousy solution, because the assembler is inserting code behind your back--a not-so-hot thing to do, particularly if there's a reference to the location counter that depends on the length of that instruction.

Note that if the definiton of EPRINT had preceded its first reference, there would be no problem. Unconditional jumps with a forward refernce can handle the problem this way because if a 2-byte jump is determined to be necessary instead of a 3-byte jump, that extra byte will never get executed anyay. MASM 5 simply does additional passes as needed until the resulting code doesn't change length.

Some early 8086 assemblers worked around that by allowing the instruction mnemonic to be modified if the size wasn't immediately apparent (i.e., at least one of the operands being a register). So you could have XORB THAT,2 and specify exactly what you mean.

As I mentioned, MASM 5 gets around this by performing additional passes if needed.

One thing that you have to get used to with x86 assembly is that it's not like 68K, 6800, 8080 or Z80 assembly lanaguage, where there's pretty much a one-to-one correspondence between a mnemonic and its corresponding opcode. That isn't the case for x86; an opcode is determined by both the mnemonic and the operands. So, MOV has no single corresponding opcode; about all you can say about it is that it doesn't affect the condition code flags.

smp
March 29th, 2015, 07:53 AM
Hi Glenn and Chuck,

Thanks a million for your advice! Since I had already wondered about the error coming up because the EPRINT DB 0,0 statement coming after the lines that referred to it, I will try moving the code as my first try. I don't know that the small discrepancy in the code output will make any difference to me. I'll try the suggested code change second, to get the experience.

I'll post back with my results - thanks again.

smp

smp
March 29th, 2015, 09:03 AM
OK! I now have fig-FORTH working on another one of my vintage systems. Thanks very much to you folks who offered assistance and advice along the way.

I moved the bit of code that defined the EPRINT flag storage to a spot prior to the two routines that set and test the flag and MASM liked that quite fine. Now I can get on with trying to figure out how this implementation of fig-FORTH actually handles the disk storage of its screens for user code. It already appears that, even though I am invoking it from its residence on drive C:, it may be assuming that it is running from drive A:. Well, off I go again.

Thanks again,
smp