• Please review our updated Terms and Rules here

VGA & CGA Graphics Library for DOS Games

but it seems like Turbo C won't let you access the structure members...

I really find this hard to believe. What version of Turbo C are you using, and have you consulted the manual (try bitsavers or archive.org)?

If a function needs access to a ton of parameters, there's nothing wrong with what you're doing (passing a pointer to a structure). However, like Plasma suggested, if you're only passing 8 or less, you should pass them normally. They'll get copied onto the stack, then the stack frame will be set up using BP, and then the assembler routine will access them using [BP-xx] which is really fast and simple. Passing 8 variables is slower than passing one, but this is not a big deal unless you're calling the function thousands of times a second, which you won't be in this case. (And if you're going to call anything thousands of times a second, you should be doing it inline anyway, or optimizing the process)
 
I'm using Borland C++ Version 3.1. I downloaded "Borland C++ Version 3.1 Programmers Guide" on page 405 talks about accessing structure members.
I tried to make a program as similar to the book as possible and it still doesn't work. It says "Invalid combination of opcode and operands".

Code:
struct myStruct {
	int a_a;
	int a_b;
	int a_c;
} myA;

void myfunc(void)
{
	asm {mov ax, myA.a_b
		  mov bx, [di].a_c
		 }
}

int main(void)
{
	myA.a_a = 1;
	myA.a_b = 2;
	myA.a_c = 3;

	myfunc();

	return 0;
}

Borland C Using C structure members.JPG
 
I'm using Borland C++ Version 3.1. I downloaded "Borland C++ Version 3.1 Programmers Guide" on page 405 talks about accessing structure members.
I tried to make a program as similar to the book as possible and it still doesn't work. It says "Invalid combination of opcode and operands".

I ran your example just fine under Turbo C++ Version 1.01. I just had to have TASM in the path.
 
I'm using Borland C++ Version 3.1. I downloaded "Borland C++ Version 3.1 Programmers Guide" on page 405 talks about accessing structure members.
I tried to make a program as similar to the book as possible and it still doesn't work. It says "Invalid combination of opcode and operands".

the following compiles fine for me in Borland C++ Version 3.1 ...

Code:
struct A
{
  int a;
  int b;
  int c;
};

A a;

void main()
{
asm mov a.a, word ptr 0000AH
asm mov bx, offset a
asm mov [bx].b, word ptr 0000BH
asm mov [bx.c], word ptr 0000CH
}
 
the following compiles fine for me in Borland C++ Version 3.1 ...

Code:
struct A
{
  int a;
  int b;
  int c;
};

A a;

void main()
{
asm mov a.a, word ptr 0000AH
asm mov bx, offset a
asm mov [bx].b, word ptr 0000BH
asm mov [bx.c], word ptr 0000CH
}

Your code does not work...
Borland error.JPG
 
Your code does not work...

Odd... must be something to do with how you have BC configured....

compile-success.JPG

options-compiler-code-generation.JPG

options-compiler-advanced-code-generation.JPG

A.CPP
Code:
struct A
{
  int a;
  int b;
  int c;
};

A a;

void main()
{
asm mov a.a, word ptr 0000AH
asm mov bx, offset a
asm mov [bx].b, word ptr 0000BH
asm mov [bx.c], word ptr 0000CH
}


A.ASM
Code:
ifndef	??version
?debug	macro
	endm
publicdll macro	name
	public	name
	endm
	endif
	?debug	V 300h
	?debug	S "A.CPP"
	?debug	C E990044F4A05412E435050
A_TEXT	segment byte public 'CODE'
A_TEXT	ends
	assume	cs:A_TEXT,ds:A_DATA
A_DATA	segment word public 'FAR_DATA'
d@	label	byte
d@w	label	word
b@	label	byte
b@w	label	word
_a	label	word
	db	6 dup (?)
A_DATA	ends
A_TEXT	segment byte public 'CODE'
	?debug	C E80105412E43505090044F4A
	?debug	L 10
	assume	cs:A_TEXT
_main	proc	far
	?debug	B
	push	bp
	mov	bp,sp
	push	ds
	mov	ax,A_DATA
	mov	ds,ax
	?debug	B
	mov	ax,seg __stklen
	mov	es,ax
	cmp	word ptr es:__stklen,sp
	ja	short @1@86
	call	far ptr F_OVERFLOW@
@1@86:
	?debug	L 12
 	mov	 _a+0, word ptr 0000AH
	?debug	L 13
 	mov	 bx, offset _a
	?debug	L 14
 	mov	 [bx]+2, word ptr 0000BH
	?debug	L 15
 	mov	 [bx+4], word ptr 0000CH
	?debug	L 16
	pop	ds
	pop	bp
	ret	
	?debug	E
	?debug	E
_main	endp
	?debug	C E9
	?debug	C FA00000000
A_TEXT	ends
A_DATA	segment word public 'FAR_DATA'
s@	label	byte
A_DATA	ends
A_TEXT	segment byte public 'CODE'
A_TEXT	ends
	extrn	F_OVERFLOW@:far
	extrn	__stklen:word
	public	_main
	public	_a
_s@	equ	s@
	?debug	C EA050D
	?debug	C E31800000023040500
	?debug	C EB0B465F4F564552464C4F57401800
	?debug	C EB085F5F73746B6C656E0A00
	?debug	C E31900000023010400
	?debug	C EC055F6D61696E191800
	?debug	C E31A014106001E01
	?debug	C EC025F611A0000
	?debug	C E601411A0700
	?debug	C E2000161040001620400016304C006000000
	end

A.LST
Code:
Turbo Assembler	 Version 4.1	    15/02/17 01:02:35	    Page 1
A.asm



      1					     ifndef  ??version
      2				     ?debug  macro
      3					     endm
      4				     publicdll macro name
      5					     public  name
      6					     endm
      7					     endif
      8					     ?debug  V 300h
      9					     ?debug  S "A.CPP"
     10					     ?debug  C E990044F4A05412E435050
     11	0000			     A_TEXT  segment byte public 'CODE'
     12	0000			     A_TEXT  ends
     13					     assume  cs:A_TEXT,ds:A_DATA
     14	0000			     A_DATA  segment word public 'FAR_DATA'
     15	0000			     d@	     label   byte
     16	0000			     d@w     label   word
     17	0000			     b@	     label   byte
     18	0000			     b@w     label   word
     19	0000			     _a	     label   word
     20	0000  06*(??)			     db	     6 dup (?)
     21	0006			     A_DATA  ends
     22	0000			     A_TEXT  segment byte public 'CODE'
     23					     ?debug  C E80105412E43505090044F4A
     24					     ?debug  L 10
     25					     assume  cs:A_TEXT
     26	0000			     _main   proc    far
     27					     ?debug  B
     28	0000  55			     push    bp
     29	0001  8B EC			     mov     bp,sp
     30	0003  1E			     push    ds
     31	0004  B8 0000s			     mov     ax,A_DATA
     32	0007  8E D8			     mov     ds,ax
     33					     ?debug  B
     34	0009  B8 0000s			     mov     ax,seg __stklen
     35	000C  8E C0			     mov     es,ax
     36	000E  26: 39 26	0000e		     cmp     word ptr es:__stklen,sp
     37	0013  77 05			     ja	     short @1@86
     38	0015  9A 00000000se		     call    far ptr F_OVERFLOW@
     39	001A			     @1@86:
     40					     ?debug  L 12
     41	001A  C7 06 0000r 000A		     mov      _a+0, word ptr 0000AH
     42					     ?debug  L 13
     43	0020  BB 0000r			     mov      bx, offset _a
     44					     ?debug  L 14
     45	0023  C7 47 02 000B		     mov      [bx]+2, word ptr 0000BH
     46					     ?debug  L 15
     47	0028  C7 47 04 000C		     mov      [bx+4], word ptr 0000CH
     48					     ?debug  L 16
     49	002D  1F			     pop     ds
     50	002E  5D			     pop     bp
     51	002F  CB			     ret
     52					     ?debug  E
     53					     ?debug  E
     54	0030			     _main   endp
     55					     ?debug  C E9
     56					     ?debug  C FA00000000
     57	0030			     A_TEXT  ends
Turbo Assembler	 Version 4.1	    15/02/17 01:02:35	    Page 2
A.asm



     58	0006			     A_DATA  segment word public 'FAR_DATA'
     59	0006			     s@	     label   byte
     60	0006			     A_DATA  ends
     61	0030			     A_TEXT  segment byte public 'CODE'
     62	0030			     A_TEXT  ends
     63					     extrn   F_OVERFLOW@:far
     64					     extrn   __stklen:word
     65					     public  _main
     66					     public  _a
     67				     _s@     equ     s@
     68					     ?debug  C EA050D
     69					     ?debug  C E31800000023040500
     70					     ?debug  C EB0B465F4F564552464C4F57401800
     71					     ?debug  C EB085F5F73746B6C656E0A00
     72					     ?debug  C E31900000023010400
     73					     ?debug  C EC055F6D61696E191800
     74					     ?debug  C E31A014106001E01
     75					     ?debug  C EC025F611A0000
     76					     ?debug  C E601411A0700
     77					     ?debug  C E2000161040001620400016304C006000000
     78					     end
Turbo Assembler	 Version 4.1	    15/02/17 01:02:35	    Page 3
Symbol Table




Symbol Name			  Type	 Value

??date				  Text	 "15/02/17"
??filename			  Text	 "A	  "
??time				  Text	 "01:02:35"
??version			  Number 040A
@1@86				  Near	 A_TEXT:001A
@Cpu				  Text	 0101H
@FileName			  Text	 A
@WordSize			  Text	 2
@curseg				  Text	 A_TEXT
F_OVERFLOW@			  Far	 ----:---- Extern
__CDECL__			  Text
__HUGE__			  Text
__stklen			  Word	 ----:---- Extern
_a				  Word	 A_DATA:0000
_main				  Far	 A_TEXT:0000
_s@				  Alias	 s@
b@				  Byte	 A_DATA:0000
b@w				  Word	 A_DATA:0000
d@				  Byte	 A_DATA:0000
d@w				  Word	 A_DATA:0000
s@				  Byte	 A_DATA:0006

Groups & Segments		  Bit Size Align  Combine Class

A_DATA				  16  0006 Word	  Public  FAR_DATA
A_TEXT				  16  0030 Byte	  Public  CODE
 
Your code does not work...

I managed to replicate your problem...

The option you need to set is:

Options->Compiler->Code generation...->Compile via assembler

Code:
E:\TEMP>bcc -Le:\bin\dos\bc31\lib a.cpp
Borland C++  Version 3.1 Copyright (c) 1992 Borland International
a.cpp:
Error a.cpp 14: Invalid combination of opcode and operands in function main()
*** 1 errors in Compile ***

        Available memory 4195916

Code:
E:\TEMP>bcc -B -Le:\bin\dos\bc31\lib a.cpp
Borland C++  Version 3.1 Copyright (c) 1992 Borland International
a.cpp:
Turbo Assembler  Version 4.1  Copyright (c) 1988, 1996 Borland International

Assembling file:   a.ASM
Error messages:    None
Warning messages:  None
Passes:            1
Remaining memory:  929k

Turbo Link  Version 5.1 Copyright (c) 1992 Borland International

        Available memory 4195412
 
Yes! now it works! if I check "Generate assembler source" and "Compile via assembler" under Options->Compiler->Code generation it works ok!

Borland compile options.JPG
 
The basic idea behind the POP code is that it maintains a few variables that count downward, one every timer tick. You put a value in one of those slots, then wait for it to go to 0 and that's when you take your next action. So for example if your timer tick was 60Hz, and you wanted to wait 2/60ths of a second, you'd put a "2" in one of those slots, then check it in a tight loop and wait for it to change to 0, then you know 2/60ths of a second has gone by and you can do your next thing.

In the real world, if you want to animate at 60Hz (ie. screen refresh rate) there are better ways to do it, so you'd typically use this for "game rates" lower than that, like 15fps. POP is inserting values in there like 6, so I guess that would be more of a delay of 1/10th of a second (assuming POP's timer is also 60Hz, I don't know what it is).

You'd use this technique in your game loop:

  1. wait for timer variable to become 0
  2. when it does:
    1. stuff another variable in there to start counting down
    2. do your game logic and screen updates
  3. go to step 1

The variable will always count down even if your game logic and screen updates take a while. Make sense?
 
Back
Top