flat assembler
Message board for the users of flat assembler.

Index > DOS > Porting Tandy&Soundblaster emulation code from TASM to FASM

Author
Thread Post new topic Reply to topic
volkert



Joined: 20 Jul 2017
Posts: 1
volkert 20 Jul 2017, 22:47
Hello everyone! This is my first post in this forum. Smile

Some months ago, I decided to take up the task of porting the source code of two useful DOS tools from TASM to FASM syntax. The main reasons being that I wanted to liberate the source code from their dependency on proprietary build tools, because I wanted to start dabbling with assembly programming in my spare time and because I was hoping it could provide a nice basis for a possible future Sound Blaster (and Tandy) emulator for computers with more modern audio devices, such as AC'97 and/or Intel HD Audio. I know you can pretty much emulate entire systems with DOSBox these days, but where's the fun in that? Wink

First a little background on my assembly skills: I've played with it in my late teens, and learned and practiced some assembly language at college, which is quite some time ago. I am an experienced Java developer by trade, but lately I've been drawn more to some wholesome old-fashioned low-level software engineering. Ah, the rose-tinted glasses of nostalgia. Cool

The source code in question was released by the author and with his permission, I published them on GitHub: https://github.com/volkertb/temu-vsb

My first priority seemed getting rid of the dependency on TASM, which meant porting over the code from one assembly dialect to another. FASM appeared to be the obvious choice, considering its DOS support, its developer community and the available documentation. This porting step seemed a fun and interesting step to ease into assembly language at first, but quickly proved much more complicated than I had expected. Eventually, I started to realize that I may have bitten off more than I can chew. Sad

So far, I've only tried porting TEMU (the Tandy Emulator), since it appeared to be the simplest of the two.

The first steps weren't too hard to figure out, thanks to some Googling:

  • Placed the import paths between quotes. Easy peasy.
  • Placed the rept loops between curly braces and removed the endm at the end of them. Okay, that took some more Googling, but no biggie.
  • Fixed a case sensitivity issue in one of the file names. Trivial.
  • Fixed some "EndIf" statements by placing a space between "End" and "If". That also took a bit of Googling, but so far, so good.
  • Removed the ".SALL" directive, since it was MASM-specific and would apparently only affect the listings, if I understood the documentation I found about it correctly.
  • Removed the ".MODEL TINY" directive, since FASM neither needs nor tolerates it.
  • Removed the ".386P" directive, since FASM didn't recognize it, although I'm a bit concerned if FASM will automatically support compiling a COM file with mixed 16-bit and 32-bit code without such a directive.
  • Removed the ".CODE" directive, since FASM neither needs nor tolerates it.
  • Removed the "SMART" directive, since SMART mode is a TASM-specific feature that FASM apparently doesn't support.


At this point, I hit my first snag:
Code:
..\386pdef.asm [7]:
                locals  @@
error: illegal instruction.
    

It took me quite a bit of Googling to figure this one out and I could hardly find any info on this, but I believe this directive meant something like "treat all labels prefixed with @@ as local labels". It would appear to be a redundant declaration, since "@@" is apparently the default prefix for local labels already. Please correct me if these assumptions are wrong! Anyway, assuming this, I removed this directive, although it left me worried about how different the default behavior with regards to local and non-local labels would be in FASM. Does FASM also automatically treat labels prefixed with "@@" as locals, and if not, how can I tell it to do so? Anyway, I decided to just try to continue fixing each error as I encountered it.

The next issue I came up with was that struc blocks apparently have a different syntax in FASM than in TASM. The first struc the assembler encountered and choked on:

Code:
Desc386         struc
SegLimit        dw      ?       ; limit bits (0..15)
Base0to15       dw      ?       ; base bits (0..15)
Base16to23      db      ?       ; base bits (16..23)
AccessRights    db      ?       ; access rights byte
Granularity     db      ?       ; granularity & default op. size
Base24to31      db      ?       ; base bits (24..31)
Desc386         ends
    


I changed it into this and that seemed to satisfy FASM:

Code:
struc Desc386 {
  SegLimit        dw      ?       ; limit bits (0..15)
  Base0to15       dw      ?       ; base bits (0..15)
  Base16to23      db      ?       ; base bits (16..23)
  AccessRights    db      ?       ; access rights byte
  Granularity     db      ?       ; granularity & default op. size
  Base24to31      db      ?       ; base bits (24..31)
}
    


I then proceeded to similarly update the next struc that the assembler complained about:

From this:
Code:
DT386           struc
TableSize       dw      ?
TableAddr       dd      ?
DT386           ends
    


...to this:
Code:
struc DT386 {
TableSize       dw      ?
TableAddr       dd      ?
}
    


After the above fix, I ran into the next error:
Code:
..\386pdata.asm [37]:
DTload          DT386   <>
error: invalid macro arguments.
    


So I tried removing the diamond ("<>") representing no arguments, and tried building again. I wasn't sure about this "fix" either, but I was eager to move on. And this brought me to the following error:

Code:
..\386pdef.asm [75]:
GDTdescr        macro   Name,DFlags,Granularity
error: illegal instruction.
    


It apparently pertained to the following macro definition:

Code:
GDTdescr        macro   Name,DFlags,Granularity
Name:           Desc386 <0FFFFh,,,DFlags,Granularity>
@&Name          =       GDToffset
GDToffset       =       GDToffset+8
                endm
    


...Which I gave the curly-braces-treatment as well:

Code:
macro GDTdescr Name,DFlags,Granularity {
  Name:           Desc386 <0FFFFh,,,DFlags,Granularity>
  @&Name          =       GDToffset
  GDToffset       =       GDToffset+8
}
    


After applying the same fix to a subsequent macro the assembler complained about, the assembler ran into another struc that I had to rewrite:

Code:
;************************ TSS structure definition ***************************
TSSblk          struc
TSSlink         dd      ?
TSSespP0        dd      ?
TSSssP0         dd      ?
TSSespP1        dd      ?
TSSssP1         dd      ?
TSSespP2        dd      ?
TSSssP2         dd      ?
TSScr3          dd      ?
TSSeip          dd      ?
TSSeflags       dd      ?
TSSeax          dd      ?
TSSecx          dd      ?
TSSedx          dd      ?
TSSebx          dd      ?
TSSesp          dd      ?
TSSebp          dd      ?
TSSesi          dd      ?
TSSedi          dd      ?
TSSes           dd      ?
TSScs           dd      ?
TSSss           dd      ?
TSSds           dd      ?
TSSfs           dd      ?
TSSgs           dd      ?
TSSldt          dd      ?
                dw      ?
TSSiomap        dw      ?
TSSblk          ends
    


... Which I modified like so:
Code:
;************************ TSS structure definition ***************************
struc TSSblk {
  TSSlink         dd      ?
  TSSespP0        dd      ?
  TSSssP0         dd      ?
  TSSespP1        dd      ?
  TSSssP1         dd      ?
  TSSespP2        dd      ?
  TSSssP2         dd      ?
  TSScr3          dd      ?
  TSSeip          dd      ?
  TSSeflags       dd      ?
  TSSeax          dd      ?
  TSSecx          dd      ?
  TSSedx          dd      ?
  TSSebx          dd      ?
  TSSesp          dd      ?
  TSSebp          dd      ?
  TSSesi          dd      ?
  TSSedi          dd      ?
  TSSes           dd      ?
  TSScs           dd      ?
  TSSss           dd      ?
  TSSds           dd      ?
  TSSfs           dd      ?
  TSSgs           dd      ?
  TSSldt          dd      ?
                  dw      ?
  TSSiomap        dw      ?
}
    


After the above fix (or attempted fix?), I finally ran into an error that so far I have been unable to fix:

Code:
..\386pdata.asm [38]:
TaskSegment     TSSblk  <,,,,,,,,,,,,,,,,,,,,,,,,,,offset IOportMap-offset TaskSegment>
error: invalid macro arguments.
    


If I understand this syntax correctly, it's trying to equate TaskSegment to TSSblk, only with the last dw (TSSiomap?) set to that offset and the earlier arguments remaining empty (question marks?). But this is a struc, not a macro, right? Do strucs even have parameters like that? And I also remember reading somewhere that the "offset" keyword is not to be used in FASM and in most cases it just can be omitted. But at any rate, at this point I'm stuck. I've tried a lot of different things here, but nothing worked. Also, even after extensive searching, Google turned up nothing on any FASM-specific syntax regarding "parameterized strucs" or whatever this thing was supposed to be.

Please tell me, am I even close to getting this to build correctly with FASM, or am I in way over my head here? I'm willing to learn, honestly! And also, it would be really cool to liberate this code from TASM, so that it can be built and further tinkered with using nothing but Free and open source tools instead.

Thank you in advance for reading through this rather long summary of my current spare-time conundrum. I hope I'll encounter some knowledgeable and helpful people here whom I can learn from. Smile
Post 20 Jul 2017, 22:47
View user's profile Send private message Visit poster's website Reply with quote
Shahada



Joined: 25 Jul 2008
Posts: 77
Shahada 26 Jul 2017, 10:48
volkert wrote:

After the above fix (or attempted fix?), I finally ran into an error that so far I have been unable to fix:

Code:
..\386pdata.asm [38]:
TaskSegment     TSSblk  <,,,,,,,,,,,,,,,,,,,,,,,,,,offset IOportMap-offset TaskSegment>
error: invalid macro arguments.
    


If I understand this syntax correctly, it's trying to equate TaskSegment to TSSblk, only with the last dw (TSSiomap?) set to that offset and the earlier arguments remaining empty (question marks?). But this is a struc, not a macro, right? Do strucs even have parameters like that? And I also remember reading somewhere that the "offset" keyword is not to be used in FASM and in most cases it just can be omitted. But at any rate, at this point I'm stuck. I've tried a lot of different things here, but nothing worked. Also, even after extensive searching, Google turned up nothing on any FASM-specific syntax regarding "parameterized strucs" or whatever this thing was supposed to be.

Please tell me, am I even close to getting this to build correctly with FASM, or am I in way over my head here? I'm willing to learn, honestly! And also, it would be really cool to liberate this code from TASM, so that it can be built and further tinkered with using nothing but Free and open source tools instead.

Thank you in advance for reading through this rather long summary of my current spare-time conundrum. I hope I'll encounter some knowledgeable and helpful people here whom I can learn from. Smile


In FASM you have to do like this:

Code:
struc TSSblk  TSSlink,TSSespP0,TSSssP0,TSSespP1,TSSssP1,TSSespP2,TSSssP2,TSScr3,TSSeip,TSSeflags,TSSeax,TSSecx,TSSedx,TSSebx,TSSesp,TSSebp,TSSesi,TSSedi,TSSes,TSScs,TSSss,TSSds,TSSfs,TSSgs,TSSld,TSSiomap
{ 
  .TSSlink         dd      ? 
  .TSSespP0        dd      ? 
  .TSSssP0         dd      ? 
  .TSSespP1        dd      ? 
  .TSSssP1         dd      ? 
  .TSSespP2        dd      ? 
  .TSSssP2         dd      ? 
  .TSScr3          dd      ? 
  .TSSeip          dd      ? 
  .TSSeflags       dd      ? 
  .TSSeax          dd      ? 
  .TSSecx          dd      ? 
  .TSSedx          dd      ? 
  .TSSebx          dd      ? 
  .TSSesp          dd      ? 
  .TSSebp          dd      ? 
  .TSSesi          dd      ? 
  .TSSedi          dd      ? 
  .TSSes           dd      ? 
  .TSScs           dd      ? 
  .TSSss           dd      ? 
  .TSSds           dd      ? 
  .TSSfs           dd      ? 
  .TSSgs           dd      ? 
  .TSSldt          dd      ? 
                   dw      ?
  .TSSiomap        dw      ?
}

TaskSegment     TSSblk 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,IOportMap-TaskSegment      
Post 26 Jul 2017, 10:48
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8397
Location: Kraków, Poland
Tomasz Grysztar 26 Jul 2017, 11:06
Shahada wrote:
In FASM you have to do like this:

Code:
struc TSSblk  TSSlink,TSSespP0,TSSssP0,TSSespP1,TSSssP1,TSSespP2,TSSssP2,TSScr3,TSSeip,TSSeflags,TSSeax,TSSecx,TSSedx,TSSebx,TSSesp,TSSebp,TSSesi,TSSedi,TSSes,TSScs,TSSss,TSSds,TSSfs,TSSgs,TSSld,TSSiomap
{ 
  .TSSlink         dd      ? 
  .TSSespP0        dd      ? 
  .TSSssP0         dd      ? 
  .TSSespP1        dd      ? 
  .TSSssP1         dd      ? 
  .TSSespP2        dd      ? 
  .TSSssP2         dd      ? 
  .TSScr3          dd      ? 
  .TSSeip          dd      ? 
  .TSSeflags       dd      ? 
  .TSSeax          dd      ? 
  .TSSecx          dd      ? 
  .TSSedx          dd      ? 
  .TSSebx          dd      ? 
  .TSSesp          dd      ? 
  .TSSebp          dd      ? 
  .TSSesi          dd      ? 
  .TSSedi          dd      ? 
  .TSSes           dd      ? 
  .TSScs           dd      ? 
  .TSSss           dd      ? 
  .TSSds           dd      ? 
  .TSSfs           dd      ? 
  .TSSgs           dd      ? 
  .TSSldt          dd      ? 
                   dw      ?
  .TSSiomap        dw      ?
}

TaskSegment     TSSblk 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,IOportMap-TaskSegment      
This does not initialize the variable values properly. The correct way to do it would be:
Code:
struc TSSblk  TSSlink:?,TSSespP0:?,TSSssP0:?,TSSespP1:?,TSSssP1:?,TSSespP2:?,TSSssP2:?,TSScr3:?,TSSeip:?,TSSeflags:?,TSSeax:?,TSSecx:?,TSSedx:?,TSSebx:?,TSSesp:?,TSSebp:?,TSSesi:?,TSSedi:?,TSSes:?,TSScs:?,TSSss:?,TSSds:?,TSSfs:?,TSSgs:?,TSSldt:?,TSSiomap:?
{  
  .TSSlink         dd      TSSlink
  .TSSespP0        dd      TSSespP0
  .TSSssP0         dd      TSSssP0
  .TSSespP1        dd      TSSespP1
  .TSSssP1         dd      TSSssP1
  .TSSespP2        dd      TSSespP2
  .TSSssP2         dd      TSSssP2
  .TSScr3          dd      TSScr3
  .TSSeip          dd      TSSeip
  .TSSeflags       dd      TSSeflags
  .TSSeax          dd      TSSeax
  .TSSecx          dd      TSSecx
  .TSSedx          dd      TSSedx
  .TSSebx          dd      TSSebx
  .TSSesp          dd      TSSesp
  .TSSebp          dd      TSSebp
  .TSSesi          dd      TSSesi
  .TSSedi          dd      TSSedi
  .TSSes           dd      TSSes
  .TSScs           dd      TSScs
  .TSSss           dd      TSSss
  .TSSds           dd      TSSds
  .TSSfs           dd      TSSfs
  .TSSgs           dd      TSSgs
  .TSSldt          dp      TSSldt
  .TSSiomap        dw      TSSiomap
} 

TaskSegment     TSSblk ,,,,,,,,,,,,,,,,,,,,,,,,,IOportMap-TaskSegment    
Or use the "struct" macro which makes it all a bit easier.

Alternatively this could be simplified for this specific application:
Code:
struc TSSblk TSSiomap:?
{  
  .TSSlink         dd      ?
  .TSSespP0        dd      ?
  .TSSssP0         dd      ?
  .TSSespP1        dd      ?
  .TSSssP1         dd      ?
  .TSSespP2        dd      ?
  .TSSssP2         dd      ?
  .TSScr3          dd      ?
  .TSSeip          dd      ?
  .TSSeflags       dd      ?
  .TSSeax          dd      ?
  .TSSecx          dd      ?
  .TSSedx          dd      ?
  .TSSebx          dd      ?
  .TSSesp          dd      ?
  .TSSebp          dd      ?
  .TSSesi          dd      ?
  .TSSedi          dd      ?
  .TSSes           dd      ?
  .TSScs           dd      ?
  .TSSss           dd      ?
  .TSSds           dd      ?
  .TSSfs           dd      ?
  .TSSgs           dd      ?
  .TSSldt          dp      ?
  .TSSiomap        dw      TSSiomap
} 

TaskSegment     TSSblk IOportMap-TaskSegment    
Post 26 Jul 2017, 11:06
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 26 Jul 2017, 12:54
volkert wrote:

Some months ago, I decided to take up the task of porting the source code of two useful DOS tools from TASM to FASM syntax. The main reasons being that I wanted to liberate the source code from their dependency on proprietary build tools

The source code in question was released by the author and with his permission, I published them on GitHub: https://github.com/volkertb/temu-vsb

My first priority seemed getting rid of the dependency on TASM, which meant porting over the code from one assembly dialect to another. FASM appeared to be the obvious choice, considering its DOS support, its developer community and the available documentation. This porting step seemed a fun and interesting step to ease into assembly language at first, but quickly proved much more complicated than I had expected. Eventually, I started to realize that I may have bitten off more than I can chew. Sad

Please tell me, am I even close to getting this to build correctly with FASM, or am I in way over my head here? I'm willing to learn, honestly! And also, it would be really cool to liberate this code from TASM, so that it can be built and further tinkered with using nothing but Free and open source tools instead.


All of this is much harder than it sounds. But for tiny model code in .COM format, it's relatively easy to disassemble (which is actually extremely helpful when the sources are in some obsolete assembly dialect).

Of course, I never fully understood TASM (structs? macros? blech!), so I'm not directly much help. But I sympathize, and I too have an interest in converting old code.

I don't think jumping to FASM is a good first move. Maybe later, but not right now. (Lack of OMF/OBJ support is one omission, which AFAIK thankfully you don't rely on here.) TASM is not really easily available anymore, nor is it actively developed much, but it's still allegedly bundled with some Embarcadero Products. So it's not even freeware (except maybe as trialware/demo). For simplicity, at first, I would recommend using a clone or similar dialect, at least until you can replicate the original builds. So that would mean (freeware) LZASM, (OSI) OpenWatcom WASM (-zcm=tasm) or (OSI) JWasm (MASM v6) or similar. Once you get it assembling in such widely-available tools (even if not 100% GNU friendly), then it should be much easier to work with. (MASM v6 is well-documented in the online copy of The Art of Assembly.)

Seriously, I'm all for Free Software, but some things are impossible. So it doesn't make sense to make things harder on yourself (at first) when everything else in the ecosystem isn't perfect either. "But OpenWatcom isn't Free". Well, it's OSI, and it's easily available everywhere, even with sources. FreeDOS relies heavily on it, and AFAIK no better DOS OS exists. So there's little point in struggling to surpass FreeDOS in freedom if you're exclusively relying on it anyways. Do you know what I mean? Yes, sure, be perfect, use 100% Free/libre tools, but if it's easier to just use freeware, that may be more pragmatic. (CuteMouse was converted from TASM to JWasm by Eric Auer. Yes, it's much harder than it sounds.)

Apparently one can buy a used paperback copy of Mastering Turbo Assembler (2nd) (circa 1995 but 900+ pages!) from Amazon for $8 USD. If you're really interested in TASM dialect, that might be a worthy investment.

Other references exist (e.g. PDFs):

Post 26 Jul 2017, 12:54
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 26 Jul 2017, 13:00
Tomasz Grysztar wrote:
Or use the "struct" macro which makes it all a bit easier.


But the DOS version of FASM doesn't have this macro (missing "INCLUDE/MACRO/STRUCT.INC" file).
Post 26 Jul 2017, 13:00
View user's profile Send private message Visit poster's website Reply with quote
Shahada



Joined: 25 Jul 2008
Posts: 77
Shahada 26 Jul 2017, 18:29
Tomasz Grysztar wrote:
This does not initialize the variable values properly. The correct way to do it would be:
Code:
struc TSSblk  TSSlink:?,TSSespP0:?,TSSssP0:?,TSSespP1:?,TSSssP1:?,TSSespP2:?,TSSssP2:?,TSScr3:?,TSSeip:?,TSSeflags:?,TSSeax:?,TSSecx:?,TSSedx:?,TSSebx:?,TSSesp:?,TSSebp:?,TSSesi:?,TSSedi:?,TSSes:?,TSScs:?,TSSss:?,TSSds:?,TSSfs:?,TSSgs:?,TSSldt:?,TSSiomap:?
{  
  .TSSlink         dd      TSSlink
  .TSSespP0        dd      TSSespP0
  .TSSssP0         dd      TSSssP0
  .TSSespP1        dd      TSSespP1
  .TSSssP1         dd      TSSssP1
  .TSSespP2        dd      TSSespP2
  .TSSssP2         dd      TSSssP2
  .TSScr3          dd      TSScr3
  .TSSeip          dd      TSSeip
  .TSSeflags       dd      TSSeflags
  .TSSeax          dd      TSSeax
  .TSSecx          dd      TSSecx
  .TSSedx          dd      TSSedx
  .TSSebx          dd      TSSebx
  .TSSesp          dd      TSSesp
  .TSSebp          dd      TSSebp
  .TSSesi          dd      TSSesi
  .TSSedi          dd      TSSedi
  .TSSes           dd      TSSes
  .TSScs           dd      TSScs
  .TSSss           dd      TSSss
  .TSSds           dd      TSSds
  .TSSfs           dd      TSSfs
  .TSSgs           dd      TSSgs
  .TSSldt          dp      TSSldt
  .TSSiomap        dw      TSSiomap
} 

TaskSegment     TSSblk ,,,,,,,,,,,,,,,,,,,,,,,,,IOportMap-TaskSegment    
Or use the "struct" macro which makes it all a bit easier.

Alternatively this could be simplified for this specific application:
Code:
struc TSSblk TSSiomap:?
{  
  .TSSlink         dd      ?
  .TSSespP0        dd      ?
  .TSSssP0         dd      ?
  .TSSespP1        dd      ?
  .TSSssP1         dd      ?
  .TSSespP2        dd      ?
  .TSSssP2         dd      ?
  .TSScr3          dd      ?
  .TSSeip          dd      ?
  .TSSeflags       dd      ?
  .TSSeax          dd      ?
  .TSSecx          dd      ?
  .TSSedx          dd      ?
  .TSSebx          dd      ?
  .TSSesp          dd      ?
  .TSSebp          dd      ?
  .TSSesi          dd      ?
  .TSSedi          dd      ?
  .TSSes           dd      ?
  .TSScs           dd      ?
  .TSSss           dd      ?
  .TSSds           dd      ?
  .TSSfs           dd      ?
  .TSSgs           dd      ?
  .TSSldt          dp      ?
  .TSSiomap        dw      TSSiomap
} 

TaskSegment     TSSblk IOportMap-TaskSegment    


Thanks for the correction, I meant like in your first example but after copy-paste I forgot to replace '?' with the argument names.
Post 26 Jul 2017, 18:29
View user's profile Send private message Reply with quote
ACP



Joined: 23 Sep 2006
Posts: 204
ACP 29 Jul 2017, 09:11
As I've been using TASM and A86 back in 286 days exclusively (A86 only for small COM files, mostly TSR since on AT it was blazing quick comparing to TASM and MASM and did not required separate linker) I may add a bit of info here.

Paradigm assembler is TASM with changed copyright and few minor changes in the manual. Use original TASM manual for 5.x version (keep in mind that in original TASM 5 package DOS real mode TASM is 4.x, 5.0 refers to TASMX and TASM32 only) the one on the bitsavers site. The manual has mostly everything you need with maybe an exception of handling tlink in some cases.

First assemble and link the code with TASM 5 package and see if you have correct executable files as output. Comparing original COM file with your output will be handy too.

Next check if your code is using MASM or IDEAL mode. FASM syntax has been designed around IDEAL model ideas but is pretty far away from it by now. Most people used MASM mode actually, and very few went IDEAL path. Therefore porting to MASM first as in one of above suggestions makes little sense IMHO - especially considering some limited MASM 6.x compatibility in TASM.

The (lack of) usage of IDEAL keyword will tell you more about changes you need to make.

The LOCALS does not only apply to labels only but to other symbols as well. By default LOCALS prefix is @@ so no need to add it in TASM. @@ prefix tells TASM to treat label locally for current scope (PROC for example). Whan TASM is in MASM mode this works differently.

As for mixing 16 and 32bit in COM/MZ EXE files in case of FASM this should pose not problems. I've done it in the past for some DPMI related code. There is an example of entering DPMI code using FASM - take a look at it to see how it is done if memory servers me well.

Finally take a look at my blog: https://corexor.wordpress.com/ You will find some tidbits about TASM.

Good luck with you project: you are facing a lot of fun. I know I had my dose when converting DesqView sdk to FASM.
Post 29 Jul 2017, 09:11
View user's profile Send private message Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 30 Jul 2017, 11:20
ACP wrote:
As I've been using TASM and A86 back in 286 days exclusively (A86 only for small COM files, mostly TSR since on AT it was blazing quick comparing to TASM and MASM and did not required separate linker) I may add a bit of info here.


A86 was fast because it was one-pass only (and only optimized backwards jumps without explicit override). I'm not majorly complaining here, but it required some workarounds to use. It hated the MASM/TASM style "mov ax,MyVar" (where FASM would be "mov ax,[MyVar]") unless declared before use. It only halfway barely supported old MASM v5 syntax.

For laughs (although it omits A86), here's an old Dr. Dobbs article (with speed tests) from 1989 called MS-DOS Assemblers Compared.

TASM was one-pass only until v2 (and even then it was optional). Even PSR Invaders forgot to use multi-pass in final release, thus it had inefficient encodings (roughly 9300 vs. 9194 bytes). Sure, one-pass is faster, but it's not preferred (if you can afford the slower assembling speed, and we've long ago jumped the shark there).

Quote:

Paradigm assembler is TASM with changed copyright and few minor changes in the manual.


I think LZASM ("Ideal" only) is also just modified TASM as well (presumably licensed). Borland (or whoever) basically abandoned TASM after year 2000 (5.3) although Embarcadero allegedly has 5.4 nowadays, but it's probably very minor changes.

Quote:

Use original TASM manual for 5.x version (keep in mind that in original TASM 5 package DOS real mode TASM is 4.x, 5.0 refers to TASMX and TASM32 only) the one on the bitsavers site. The manual has mostly everything you need with maybe an exception of handling tlink in some cases.


Yes, the last real-mode version was something like 4.1, but you can run WDOSX's STUBIT on (PE/Win32) TASM32.EXE (which I did from the freeware one included in 2007's Turbo C++ Explorer) to run natively in DOS. Not real mode but pmode, but at least it runs.

Quote:

First assemble and link the code with TASM 5 package and see if you have correct executable files as output. Comparing original COM file with your output will be handy too.


Yes, but comparing raw binary code output to a different assembler (e.g. FASM) requires ignoring the actual encoding bytes and only comparing the actual disassembled instructions. I whipped up a (very simple) script to do that with NASM / NDISASM and AWK.

Quote:

Next check if your code is using MASM or IDEAL mode. FASM syntax has been designed around IDEAL model ideas but is pretty far away from it by now. Most people used MASM mode actually, and very few went IDEAL path.


Actually, Ideal was insanely popular in DOS circles. There's still tons of legacy code that no one converted to other assemblers. Unfortunately, Ideal isn't well-supported by any other assemblers, so it's annoying.

Quote:

Therefore porting to MASM first as in one of above suggestions makes little sense IMHO - especially considering some limited MASM 6.x compatibility in TASM.


You should use LZASM (Ideal) for such code else just use MASM (or better, JWasm or HJWasm). My point was that MASM v6 is semantically similar, so it isn't impossible to convert from TASM to MASM. All the so-called advantages of Ideal mode (allegedly) went away with MASM v6, so there's no huge advantage to TASM anymore.

Quote:
The (lack of) usage of IDEAL keyword will tell you more about changes you need to make.


Like I said, _Art of Assembly_ (online) explains MASM v6 syntax. Granted, it depends on what you're trying to do, and none of it is super easy.

Quote:

The LOCALS does not only apply to labels only but to other symbols as well. By default LOCALS prefix is @@ so no need to add it in TASM. @@ prefix tells TASM to treat label locally for current scope (PROC for example). Whan TASM is in MASM mode this works differently.


MASM v6 by default (unlike v5) made all labels inside procs as local. This was for better scoping, but if your old code (e.g. PSR Invaders) doesn't like that, you can use "jwasm -Zm" to enable old v5 syntax or just put "option noscoped" at the top of the file. Or change the label's single colon at end into "::".

Quote:

As for mixing 16 and 32bit in COM/MZ EXE files in case of FASM this should pose not problems. I've done it in the past for some DPMI related code. There is an example of entering DPMI code using FASM - take a look at it to see how it is done if memory servers me well.


Right, it won't forbid any instructions (so be careful!). You may want to use revolution's old compatibility.inc macros for help with that, if you're unsure.

Quote:

Finally take a look at my blog: https://corexor.wordpress.com/ You will find some tidbits about TASM.


I'll probably forget (too much else on the brain), but it looks interesting.

Quote:

Good luck with you project: you are facing a lot of fun. I know I had my dose when converting DesqView sdk to FASM.


There's still tons of old DOS code that was abandoned that should probably be converted to Free tools. But I guess few find it worthwhile, sadly.
Post 30 Jul 2017, 11:20
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.