News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Dabz

Hisoft-C and CALL (Amstrad CPC)

Started by Dabz, 12:38, 17 January 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dabz

Hi there... Quick question...


I'm using Hisoft-C, well, looking at it anyway, and what I'm wondering is how you go about using CALL's, now, I know this:-


#define CALL 0xCD
inline(CALL,0xbb18); <--- Waits for keypress


Now, what I'm after is how do I pass values through to the firmware routines, say, Mode e.g.


inline(CALL, 0xbc0e);


I know in assembly you load the parameter into the 'a' register then call it, but, I cannot quite figure out how to do this in HiSoft-C, I've looked at init_events(), with an char *eventblock[12], but alas, I just cannot see it!


Thanks in advance! :)

FloppySoftware

Well, you could replace CALL with LD equivalent; anyway, it's seems to me a bad solution to use inline code in this way.

I don't know Hisoft C, but in other C compilers you have one or two options:

- #asm and #endasm.
- external REL modules written in assembler to be linked later.

Maybe Hisoft C supports one of these.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

Dabz

Unfortunately, inline asm isnt provided, and the inline(); is what's recommended in the docs.


I mean, it should be possible, but I honestly cannot work it out, like, I just cannot "see" it if you get me!


It's probably the most simplest thing, lol, it always is! :)


Hopefully someone will know! :)

Thanks for the reply anyway, I appreciate it! :)

FloppySoftware

From the manual:


9.13 Null statement
9.14 Inline Statement
HiSoft C provides the ability to incorporate machine code into C programs, A new type of
statement (which looks like a function call) is used:
inline ( k1, k2, k3, );
k1, k2 etc is a list or constant expressions which will be put into the output code. An expression
which has a value in the range 0 to 255 inclusive will cause a single byte in be generated and
any other number will cause two bytes to be generated. Any constant expression may be used
(see section 15) For example. to jump to location 0:
inline (0xC3,0,0): /1 CxC3 is the Z80 JP instruction */
or to call location 1601 (hex) with 3 m the A register (open stream 3 on a Spectrum]:
#define CHAN OPEN0x160:
#define ld a with 0x3E
#define call0xCD
inline ( ld_a_with,3, call CHAN_OPEN);
and to Store an input character in a global variable c:
#define ld_mem_from_hl 0x22
inline ( call, getchar, ld_mem_from_hl, &c);


You have to use the LD code.

Anyway, what a tricky procedure regarding int values!
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

Dabz

Ah.... Brilliant! :)

I don't know how I missed that mind, bloody scoured the docs! :/

Thanks for that though... I do appreciate the help! :)

AMSDOS

Just a thought, I was wondering if hisoft c could handle rsx's there's a program which allows you to safely poke values into registers and call the appropriate firmware (all via rsx's).
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

GeoffB17

Hisoft C includes normal 'poke' and 'peek'.


i.e. char peek(address);


and void poke(address, value);


Do you need RSX for this?


Regarding the inline statement, there may be a file BASIC.LIB which contains other examples.


Part of what was described above is not essential, it's just there for readability, as 'inline' is NOT an 'assembler', merely a way of inserting binary into the prog.   If you're not bothered with readability, you could forget the #DEFINE things, and just use the hex code?


i.e. inline(0x3E, 3, 0xCD, 0x1601);
/* for LD A, 3     CALL CHAN_OPEN */


or inline(0xCD, getchar, 0x22, &c);
/* for CALL getchar   LD HL &c  */


NB that last will assume that the prev defined variable c is big enough to take HL.


Maybe more sensible, do each line (of assembler) as a separate inline() statement rather than run lines together as in the examples in the manual.


Geoff

GeoffB17

Just an extra thought regarding RSX.


If you're using CP/M+ )(3) then Hisoft C for that does include GSX, which I believe is an RSX, so Yes.


If you're using CP/M 2.2, then No.   If your disk (or the side of the disk you're using) did not include the GSX bits, then I guess it's No.


Geoff

AMSDOS

Quote from: GeoffB17 on 15:05, 18 January 16
Just an extra thought regarding RSX.


If you're using CP/M+ )(3) then Hisoft C for that does include GSX, which I believe is an RSX, so Yes.


If you're using CP/M 2.2, then No.   If your disk (or the side of the disk you're using) did not include the GSX bits, then I guess it's No.


Geoff


Unfortunately I never got to learn how RSXs worked through CP/M Plus.  I was wondering if RSXs could be accessed from the AMDOS version. After having a bit of a look through the Hisoft-C Manual, I found that it does. Page 134 (which is page 178 of the PDF), external Commands are accessible from extcmd.h library.


Using that approach of course means setting aside some memory for the RSX Library & unfortunately the Manual only shows AMSDOS Commands and doesn't explain how you would go about Setting up your own RSXs from KL LOG EXT (#BCD1). In Hisoft Pascal 4T for example, you can enter an address that you can set aside for using those sorts of routines.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Dabz

Nice bit of reading there! :)


Here's a one which I cannot figure out...


In assembly, if I wanted a pointer to a specific address, lets say, x0C000 which is obviously the start of screen memory, I would [if memory serves me right] use somethinggggg like:-


LD DE,0xC000
LD (DE), var <---- Then plonk something in to address 0xC000


Now, I would use something in C like this, :-


type *pnt = (type *)0xC000


if I wanted 'pnt' to point at 0xC000, but, when I try this in Hisoft-C, its a restriction... Now, I'm half guessing that I dont understand the standard that was used at the time, and only really understand a more modern approach, so, can anyone enlighten me on the right way to do this... Like  previously mentioned, I can use "poke", but, if I can get away with just pointers, jobs a good'un! ;)


Dabz

GeoffB17

#10
Hello,


I confess I don't know THAT much about Hisoft C, but I assume it follows many of the same rules as other C systems.


I've done most of my work with MS C5 and then C7, involving some quite large projects, mostly using the CodeBase library to access dBase/Clipper/Fox type databases and indexes.  So there may be some differences


However, I would expect you example to require:


char *ptr;    // this declares ptr to be a pointer, pointing at char data (i.e. a single byte).


In effect, ptr will contain an address, i.e. the address of the data being pointed at.


You could therefore initialise the pointer be assigning it an explicit address, so I would expect:


char *ptr;
ptr = 0xC000;


which defines ptr as a pointer, and then sets the destination as 0xC000, i.e. ptr points at 0xC000 and therefore *ptr returns the contents of the byte at 0xC000, while ptr would return 0xC000.


Alternatively, sometimes pointers and arrays can be interchanged.


char  str1[8] = "1234567";   // define str1 as a 8 byte str (last byte will be null byte);
char *ptr;                              // define ptr as pointer to char
ptr = &str1[0];                      //  initialise ptr to contain address of first byte of string


hence:


for( i = 0; i < 7; i++)
{
   str1 = *ptr++;       // ?? something messing here, should be str1(sq br) i (sq br), not str1
}
in effect does nothing, as at the end the string str1 will be the same at it started, as each byte has been read via the pointer, and put back as an array element.


if 0xC000 is the start of screen memory, and 0xB000 was the start of spare ram, and you wanted to copy the screen memory to spare:


unsigned char *ptr1, *ptr2;     // unsigned as you'll be dealing with binary data 0 - 255
ptr1 = 0xC000;
ptr2 = 0xB000;       // not sure offhand, maybe these two lines might need  ( char * ) prefix before literal                                                address to ensure compiler sees as addr containing char data.


for(i = 0; i < 100; i++)
{
     *ptr2++ = *ptr1++;        // reverse variables to copy data back.
}


I would expect this would be a LOT faster than using peek/poke commands, though that would work as well.


In your little example, what is 'type' supposed to be?   Defining the data as char (or unsigned char) is more important.   'type' is not a keyword in Hisoft, 'typedef' is when you're creating something, i.e. a structure.


I've got some C code somewhere relating to using creating/saving/disposing of screen memory for DOS 'windows', this code is reading screen data from one place, saving the data somewhere, then writing the data back when the window is closed (pop-up windows).


Geoff

Dabz

Thanks Geoff, I'll have a look into that, if it is as easy as that I'll defo be doing a  :doh:


:D



The "type" word was just a bit of p-code I chucked in to represent a type that could hold an address!  :)

Dabz

Finalllyyyyyyyyyyyyyy cracked it:-



typedef char * CHAR_POINTER;
char * ptr;
ptr = cast(CHAR_POINTER) 0xC000; 



CAST..... IT WAS CAST THAT I RUDDY NEEDED!!! :D


It's drove me up the ruddy wall that! ;)

GeoffB17

Hello,


Not sure what you're trying to do with your example above, or is there something VERY strange in Hisoft C?


First, why the 'typedef' in the first line?  the 'char * CHAR_POINTER' declares CHAR_POINTER to be a pointer to char data OK, so unless there's some reason why CHAR_POINTER might be something else, the 'typedef' isn't doing anything.


Line 2, 'char * ptr', seems perfectly normal, just like line one could be?


line 3 - I've never seen an explicit keyword as 'cast' - the C books I have refer to 'cast' as changing one type to another within the prog, i.e.


var1 = (int) var2;


where var1 is an int, but var 2 is not, but just here you want to make it a int.


Are you trying to do something like?


unsigned int addr1 = 0xC000;
ptr = (char *) addr1;


although it is maybe un-necessary to put the address into an int, just put it right into the ptr i.e.


char *ptr ;
ptr = 0xC000;   (or maybe (char *) 0xC000) but the ptr would be an address anyway!


I suspect you're misunderstanding the word 'cast'?  'C' certainly does use the word 'cast', but it's a process that you do using appropriate 'C' keywords/commands, not a keyword itself.


i.e. the line shown above 'ptr = (char *) addr1' includes a 'cast' where 'addr1' was NOT a pointer to char data but is temporarily treated as one.


If 'addr1' is already a char *, then there is no need for any cast.


Geoff

Dabz

#14

Quote
char *ptr ;
ptr = 0xC000;   (or maybe (char *) 0xC000) but the ptr would be an address anyway!


You would think so... And well, we'd all be wrong.

This is the way it is...


If I do it the way your specifying, which may I add, would be the way I would go about it, it just simply doesnt work... I spied the cast keyword in the documentation, so winged my way to look at where operators and such is documented, and voila, cast(), and it's pretty much for that purpose what I'm using it for!

EDIT: Page 54 in the manual.

Quote
I suspect you're misunderstanding the word 'cast'?  'C' certainly does use the word 'cast', but it's a process that you do using appropriate 'C' keywords/commands, not a keyword itself.


Now, also in the documentation it states that it tries its best to conform to Kernighan and Ritchie's C, but, it does state that it doesn't do it fully, and as such, this is one of them moments!


This has been half the battle as it doesnt follow standard C to the latter and as such, why I've had such a mare!

Quote
First, why the 'typedef' in the first line?  the 'char * CHAR_POINTER' declares CHAR_POINTER to be a pointer to char data OK, so unless there's some reason why CHAR_POINTER might be something else, the 'typedef' isn't doing anything.


Just readability really, though, to be fair, that has nothing to do with the problem at hand, which is now fixerererered! :P 
;)  YAY

andycadley

Quote from: Czar on 18:48, 24 January 16
This has been half the battle as it doesnt follow standard C to the latter and as such, why I've had such a mare!

C wasn't standardized until 1989, so it's not overly surprising that 8 bit C compilers pretty much follow whatever rules suited them.

GeoffB17

Aha...


Yes, I've looked at section 3.4 in my Hisoft manual, and I see the cast() operator.   OK!


In all the C versions I've used before, the use of (char *) xxx would have done a 'cast', without needing to say 'cast', but is appears that Hisoft doesn't, and in fact needs the 'cast(...)' keyword.


Doesn't the use of 'cast (char *) 0xC000' do the job just as well??   Yes, the examples in the manual DO show it the way you've done it, but isn't that just for extra clarity (or in my case, extra confusion !!!).   Then you wouldn't need the 'typedef' line??


Still, if whatever does work - OK.


Geoff

GeoffB17

Hmm, more Aha....


Just found the bit in the manual, section 7.2, discussing differences between the Hisoft implementation and standard.


Indicates some extra things regarding the use of cast(), including a necessary '#define  cast', however, more important, it seems here to be indicating that cast( char *) will NOT work, so I guess you HAVE to do it the way in the example.


However, note the example function on section 1.12.4, memory dump.   In some ways, this is doing a similar thing to what you're trying to do.   Just displaying the byte-by-byte data, rather than copying it.   This example does not need any 'typedef' or 'cast', just that the address is passed via the function parameter.


I'll get my HiSoft C fired up, with that example, and see what I can determine.


Geoff

GeoffB17

Well, I've had a little play with the C compiler, and the attached .zip contains the two C progs.


Test 1 is pretty much like the DUMP example in the manual, i.e. it's pretty straight C, but the explicit address is passed to the subroutine as a parameter, which appears to need no special treatment.   The passing as a parameter seems to take care of everything.


Test 2 is the same prog, but no parameter is passed.   I tried various ways to set the explicit address in the subroutine, but the only way that worked is pretty much the one you were using.


I don't know what the 'cast' is doing given that the passed parameter manages fine, but that's how it is.


If your prog is going to need a memory move function, then you could easily do it like Test 1, passing a relevant address each time.


Geoff

FloppySoftware

Maybe cast() is simply a function.
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

GeoffB17

Could be a function, but it's presented in the manual as a keyword.


Also, there is a note that if you use a HiSoft C prog in another compiler, then you should use


#define  cast


to disable it (i.e. define cast as blank/nothing) ??   I could understand that if we were using (say) cast(char *) as simply nulling the 'cast' bit would leave the (char *) that another compiler would be quite happy with, but it doesn't work like that.


Anyway, what does work, does work!


I played a bit more with my TEST1 prog, and added some more to it.   Re-named the new version MEM-DUMP.
It will now accept a command line parameter, a memory address, and will dump 256 bytes from that address to the screen.   The prog will accept the address as a variable, and it will pass the variable through to the function fine, at which point it will become a pointer and everything will be fine.   No need for cast!


I had wanted to present the address as hex - more convenient - but I couldn't get this to work, no easy function to convert hex (ok, I could use sscanf, but that's a bit heavy-handed ??).   Anyway, the decimal works fine.  So, something useful for me!!


.ZIP attached, with .C and .COM


Geoff

Dabz

Ah, you have been busy! :D


I dont like the cast() thing as much as you, but alas, stuck with it... No biggy! :)


It was fun though trying to get around it! :D


Dabz

FloppySoftware

Hi Geoff,

As an exercise, I took your code and did the same for MESCC (C & COM files are attached).  :)

MESCC was able to build a COM file -50% in size compared to HiSoft-C!  8)
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

GeoffB17

Yes, interesting.


Your .com file is half the size, although using the larger block size of larger disks, the difference is less marked, 6k vs 4k.


However!


I timed the two programs running, and the HiSoft prog took 6 secs, your version was just over 7 secs.   Not that much, but the timing includes the prog loading from disk, and the HiSoft version is twice the size!   I did the timing because when the prog was running, I could plainly see that the hex data was displaying on the screen faster with the HiSoft prog than with yours.   


I don't know why your version was slower, and I don't know if a larger prog would be proportionally slower, or if certain routines are slower while other routines might be faster, but just for this little prog the Hisoft is a bit faster, while the MESCC prog is smaller.   Take your choice!


Hmm, I'll have to try the same prog with my Eco C, and see how that is.   I think I did something before, and the Eco version was bigger than the Hisoft prog.


I tried the sscanf routine to try to convert the hex command line, but I wasn't able to get it to work.   I suspect something a little odd with the strange way that the HiSoft C handles the command line.


Learning things!!


Geoff

AMSDOS

Quote from: GeoffB17 on 01:17, 26 January 16
I timed the two programs running, and the HiSoft prog took 6 secs, your version was just over 7 secs.   Not that much, but the timing includes the prog loading from disk, and the HiSoft version is twice the size!   I did the timing because when the prog was running, I could plainly see that the hex data was displaying on the screen faster with the HiSoft prog than with yours.   


I don't know why your version was slower, and I don't know if a larger prog would be proportionally slower, or if certain routines are slower while other routines might be faster, but just for this little prog the Hisoft is a bit faster, while the MESCC prog is smaller.   Take your choice!


It sounds like MESCC is compressing the final COM file, which would in effect slow the result in order to Decompress the code. Hisoft have written their C language for CP/M, AMSDOS as well as the tape based CPC OS, probably around the time, Compression Tools would have been more readably available under CP/M, through less so under those other Systems perhaps.
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

Powered by SMFPacks Menu Editor Mod