Enterprise Forever

:UK => Summaries from the Hungarian topics => Topic started by: MrPrise on 2007.March.09. 00:53:39

Title: Enterprise C compiler for PC
Post by: MrPrise on 2007.March.09. 00:53:39
Gep (http://enterpriseforever.com/index.php?action=profile;u=94) would like to know here (http://enterpriseforever.com/index.php/topic,225.msg6972.html#msg6972) if there is any C compiler for the Enterprise which runs on PC? He would like to tinker with the EP, but he would also like to enjoy the PC's comfort. After searching on SF he found the SDCC (http://sdcc.sourceforge.net/) which looks promising.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.03. 23:20:15
Hello,

 I found this topic very close to my today/yesterday work. I know, the last post came in 2007, but who knows, maybe we can help each other.

The reason why I started to seek for a Z80 C-Compiler, because I cannot program big things in Assembly. And I got used to use C for programming.

 So I have started yesterday with SDCC, Today I made a little program, and tested it. I wanted to share my experiences.

For a new Project I do the following:

1. I create a C-code with the 'int main(void)' function and other sub functions
2. Compile the project with the folowing command which places the file at memory 0x4000
   sdcc main.c -mz80 --code-loc 0x4000 --data-loc 0x4000
3. Then I convert the created main.ihx file to binary format using the hex2bin.exe
  hex2bin.exe -p 0 main.ihx
 (-p 0 means, the unused bytes im file has to be ZERO)
4. I copy the data from 0x4000 to the end and I give it to the emulator

 As I started the program from 0x4000, it didn't work, the program returned immediately. As I made a dissassembly listing I had noticed, that the first 10 bytes are foreign code. See attachment, the red line shows where the first planned instruction starts, the instruction before 'DEC SP' means the main function has a integer return value it's still ok, but the others are not from me.
 If I jump it over, and call 0x400A, the program runs normally.

 Does anyone know, what for are these first 10 bytes, and how can I switch it off in SDCC?
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.03. 23:35:57
Dunno, but some time ago I played with sdcc for EP: http://ep.lgb.hu/sdcc/ (http://ep.lgb.hu/sdcc/) Please note, that sdcc seems to be a bit odd to change internals all the time. For example it had an odd behaviour to store data as Z80 code to store the needed code by executing Z80 ops actually instead of just store the data bytes. I had some solution to try to "convert" this into a sane form, but it seems it's depend on the sdcc version. And similar things. I've also made a bug report to the sdcc team about the issue (sdcc should store data as data and not as code which initializes the data ...) I have no idea about the current state of my bug report, or this issue though ...

You can try to follow my Makefile if it helps at all. My intent was creating "normal" EXOS-5 header program right from C source compiled with sdcc, so with some major further development, at least simple C programs can be compiled for the Enterprise without the need to load them to specific address etc, just LOAD them, and that's all.

Also, you can visit this Hungarian topic (about z88dk, but also sdcc related): http://enterpriseforever.com/programozas/z88dk/ (http://enterpriseforever.com/programozas/z88dk/)
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.03. 23:42:46
I found the following list in the .map file:

Code: [Select]
     Value  Global                              Global Defined In Module
      -----  --------------------------------   ------------------------
     00004000  __clock                            crt0
     00004004  _exit                              crt0
     0000400A  _main                              main02
     0000400A  _main_start                        main02
     00004062  _main_end                          main02

According to this list, it has to be a clock and exit functions, which belong to crt0.
I haven't made crt0 module.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 00:01:28
I found the solution here, I searched for 'CRT0'
http://sdcc.sourceforge.net/mediawiki/index.php/Z80_port

To get rid of the problem I have to use the '--no-std-crt0' option. And it works perfectly.

So my second point is changed:
2. Compile the project with the folowing command which places the file at memory 0x4000
   sdcc main.c -mz80 --no-std-crt0 --code-loc 0x4000 --data-loc 0x4000
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 00:07:17
LGB, can you show a short example how can I append Inline assembly code?
 I am afraid, that the inline ASM code changes a register, and it generates an error.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.04. 00:29:11
To get rid of the problem I have to use the '--no-std-crt0' option. And it works perfectly.

Yeah. I told to look at my Makefile at the URL I've already posted, it may help, unfortunately I don't remember these things now :(
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.04. 00:38:44
LGB, can you show a short example how can I append Inline assembly code?
 I am afraid, that the inline ASM code changes a register, and it generates an error.

Sorry, but I have no idea. What I've done is to starting to create an "Enterprise library" for sdcc (including crt0, yes) but those were separated asm files, and just the linking stage was where they were "combined" to an Enterprise EXOS-5 program. I've never tried to insert inline assembly into a C source with sdcc, if your question was about that.

Sdcc manual at http://sdcc.sourceforge.net/doc/sdccman.pdf (http://sdcc.sourceforge.net/doc/sdccman.pdf) may help you though. It has some hints about the "naked" functions (= a function written in assembly fully) and what registers can be used or not (also, for a full assembly but C callable example can be seen in my sources in crt0.s written by me, but it's not "inline" assembly). I have really no idea about inline assembly fragments really inserted into a C function with also C code ...
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 02:13:38
I am through the user manual of SDCC, and some search in diverse websites.
The conclusion is, SDCC lacks of variable-passing between C-code and inline assembly code. And the support appears dead.

It would be very important using a variable bound with a CPU-register, to accelerate the execution time.

 I will shut down the study of SDCC, and I will try other programs like the Z88DK.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.04. 07:13:50
I am through the user manual of SDCC, and some search in diverse websites.
The conclusion is, SDCC lacks of variable-passing between C-code and inline assembly code. And the support appears dead.

It would be very important using a variable bound with a CPU-register, to accelerate the execution time.

Why is it strange for you? This is natural for C, there are no "registers" in C too much, just variables, bound to memory locations (thus subject of pointers etc), this is natural. C compilers usually have the complexity to keep some variables in the registers (traditionally there was the "register" keyword to organize this, but a modern C compiler will surely make better code if you don't try to outsmart it, if it handles for that keyword at all and not just silently ignores). Often (always?), C compilers are two pass compilers ie, generating assembly code first than doing the assembly. Some compilers even runs optimizations through the generated asm code. The problem, that in-line assembly in the that stage can be an issue, as that kind of optimizator only see the asm code regardless written by you or generated from the C code, mixed together within even the same function. Etc, etc. So I am not surprised not having too much support in C compilers for that. Why would you need it? OK, "to accelerate the execution time" but then one can say do not use C at all, but only asm to accelerate it further :) Using C is more about accepting the basic construction of the language which is memory/stack oriented (stack based ... no like forth but the implementation, it is transparent to the programmer usually) and not register based.

Z88DK is actually not a C compiler but Small-C (well it seems, its origin is about Small-C and nowdays it supports maby ANSI C stuffs, I can't judge too much ...), so some features of the C programming language is not supported. Also please note, that the problems with "direct control on registers" may seem a real issue for you, it's also one of the key  factors to write an efficient C compiler. So a C compiler which gives you more control on things you would like would be (probably) slower, ie generating worse code from the same C source.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 10:08:01
I want to something like that (extract from website http://wiki.osdev.org/Inline_Assembly)

Code: [Select]
int a=10;
int b;

asm ("
      movl %1, %%eax;    // eax <- a
     ....
     (doing other things here)
     ....
      movl %%eax, %0;"  //  b <- eax
     :"=r"(b)        /* output  , %0*/
     :"r"(a)         /* input , %1 */
     :"%eax"         /* clobbered register */
     );

With this snippet I can pass variable (int a) thru register (eax) to a ASM code, and at the end, I can pass an another back (int b).
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.04. 10:24:21
Ah yes, the "gcc in-line assembly black magic with at&t syntax" as it is referred by some funny people :) The complexity of this syntax is exactly because of the fact that the compiler should "integrate" your asm code as a part of the compiled C code. I guess, at least. So it's kinda hard to provide this feature in an efficient way, and probably "low end compilers" (ok, sdcc may not means to have a compiler "as serious" as gcc is) can't provide this flexibility because of its complexity. But again, this is my best guess only ... In case of sdcc I would go for naked/assembly functions so you write a whole function in assembly when it's easier to tell how you control the usage of registers, etc because context is not "mixed" with your own asm code and the compiled C code within the same function. Of course this is not the best solution if you need some short asm code only when you will have the overhead to call a function all the time when you need to invoke your code. But the overhead is minimal if your "all asm" function is heavy enough anyway and not just a few opcodes.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 16:34:25
1. Thing which came to my mind
Could show you an exaple as well, why we need inline Assembly:
 If we want to fill memory incrementally, e.g. from 0x1000 to 0x3000 with the same value (0x01), we do the following

This is a for loop made by SDCC
Code: [Select]
label1:
- HL <= 1000
- (HL) <= 0x01
- HL++
- IF HL= 3000
     RETURN
- GOTO label1

option 2, an user made inline asm:

Code: [Select]
label1:
- SP <= 3000
- PUSH 0x01   - This instruction seems to be faster on EP
-  IF SP=1000 THEN
     RETURN
- GOTO label1

2. Thing
 A normal call saves all register into memory, plus uses the stack, and call a block. The inline call means, the compiler paste the code everywhere, where it's called, directly. It produces more code, but faster execution.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.04. 22:29:31
I found the following website where C compiler is developed, and someone shared how to use the utils.
https://github.com/earl1k/llvm-z80/issues/2
See comment:  Apr 25, 2014

He mentioned LLVM and CLANG.

A site about LLVM:
https://olduino.wordpress.com/2014/12/30/llvm-for-the-z80-another-source-of-inspiration/
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.May.04. 22:33:26
I found the following website where C compiler is developed, and someone shared how to use the utils.
https://github.com/earl1k/llvm-z80/issues/2
See comment:  Apr 25, 2014

He mentioned LLVM and CLANG.

A site about LLVM:
https://olduino.wordpress.com/2014/12/30/llvm-for-the-z80-another-source-of-inspiration/

Yes, LLVM is a young but serious stuff. I mean even for "mainstream CPUs", head-to-head with gcc now, as I can feel. The interesting thing about LLVM is the easy adoption for new CPUs, which is in contrast (?) of gcc. But please note I am far from being an expert of C compiler internals, so maybe it's just a feeling I can express this way. I've read various "mad" targets of LLVM including Z80 and 6502 too, but I am not sure how serious (never checked) projects they are, are they usable at all, etc ...
Title: Re: Enterprise C compiler for PC
Post by: Povi on 2015.May.05. 15:09:09
it seems the LLVM uses similar technology to passing parameters as HiSoft Pascal compiler did.
Title: Re: Enterprise C compiler for PC
Post by: Tuby128 on 2015.May.05. 17:12:37
Can you present me an example?
Title: Re: Enterprise C compiler for PC
Post by: Povi on 2015.May.05. 18:02:00
Code: [Select]
        push ix
        ld   ix, 0x0004
        add  ix, sp
        ld   hl, 0x0000
        add  hl, sp
        ld   de, (0x1501)
        add  hl, de
        call nc, 0x0693
        ld   l, (ix + 4)
        ld   h, (ix + 5)
        push hl
        ld   l, (ix + 2)
        ld   h, (ix + 3)
        pop  de
        or   a
        add  hl, de
        call pe, 0x06a6
        ld   (ix + 6), l
        ld   (ix + 7), h
        pop  ix
        pop  de
        ld   hl, 0x0006
        add  hl, sp
        ld   sp, hl
        ex   de, hl
        jp   (hl)
       

Code: [Select]
function addint(a, b : integer) : integer;
begin
  addint := a + b;
end;
Title: Re: Enterprise C compiler for PC
Post by: Mobsie on 2015.May.11. 20:45:01
Hi,
interesting!
I just now setup my Enterprise 128, after years, also with the great SD-Cart.

I plan to write some small games, i wirte mostly games on the vtech CreatiVisio in ASM.

But the Enterprise was one of my dream machines for years.

I will test http://www.z88dk.org/wiki/doku.php?id=platform:enterprise
looks interesting and the samples show also Inline Assembler.

Best Regards,
Mobsie
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.18. 08:21:05
some time ago I played with sdcc for EP: http://ep.lgb.hu/sdcc/ (http://ep.lgb.hu/sdcc/)

Has anyone gone further than this in trying C for the EP on either sdcc or z88dk?  Any crts, assembler libraries, etc?

Quote
I found the solution here, I searched for 'CRT0'
http://sdcc.sourceforge.net/mediawiki/index.php/Z80_port
To get rid of the problem I have to use the '--no-std-crt0' option. And it works perfectly.

The crt sets up the environment before calling main().  Some of the things it's supposed to do is initialize the data segment, zero the bss segment and initialize the heap.  If you eliminate it and don't initialize those segments, the global variables may not have correct initial values and malloc() may not work.

Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.18. 09:05:36
The crt sets up the environment before calling main().  Some of the things it's supposed to do is initialize the data segment, zero the bss segment and initialize the heap.  If you eliminate it and don't initialize those segments, the global variables may not have correct initial values and malloc() may not work.

Yes, but as I mentioned at the first URL I wrote my own crt0 for EP ...

http://ep.lgb.hu/sdcc/crt0.s

(so the no std crt0 was about using my own crt0)

I did this project some time ago, so I can't remember everything. Unfortunately sdcc was (or "is" still?) a moving target: its internals was changed all the time, but I couldn't stick with a given version (which would be a better strategy) since it had another annoying bugs (fixed later, but also introduced changes affected my tries as well). So this was a reason I lost my interest. Maybe it's time now to re-check the situation now :) I also had an "official" bugreport (about _one_ bug only) to the sdcc team:

https://sourceforge.net/p/sdcc/bugs/2089/

About 3 years, and the bug report is still have status of "open" ... :(

And for sure my work was so "initial only" that it can't be used for more serious stuffs too much.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.18. 17:45:26
Quote
I did this project some time ago, so I can't remember everything. Unfortunately sdcc was (or "is" still?) a moving target: its internals was changed all the time, but I couldn't stick with a given version (which would be a better strategy) since it had another annoying bugs (fixed later, but also introduced changes affected my tries as well). So this was a reason I lost my interest. Maybe it's time now to re-check the situation now :)

It looks like you got involved while the z80 port was being rewritten.  Things are stable now :)

Quote
I also had an "official" bugreport (about _one_ bug only) to the sdcc team:
https://sourceforge.net/p/sdcc/bugs/2089/
About 3 years, and the bug report is still have status of "open" ... :(

To be fair, they do have eight pages of bug reports -- enough that they probably pick the easiest and/or most interesting (to them) to fix first.

That bug report I know about (I'm a dev at z88dk) and it also affects another major project (fuzix).  Fuzix has resolved it like you did -- they post process the source and remove the redundant space.  The solution is not as straightforward to fix with postprocessing as it might seem at first and I'm not sure if fuzix's solution considers the following.

If you change your code example a little bit:

Code: [Select]
char *test = "Hello world, this is not const!";
char welcome[] = "Hello world, this is not const!";

The generated output (with z88dk tools but the output comes from sdcc):

Code: [Select]
SECTION code_compiler

___str_0:
DEFM "Hello world, this is not const!"
DEFB 0x00

SECTION data_compiler

_test:
DEFW ___str_0
_welcome:
DEFM "Hello world, this is not const!"
DEFB 0x00

The third extra bit of space is eliminated by z88dk but there is still the string constant in section code_compiler which is not required.  However it's not safe to blindly remove it :- you can see that that the same string "Hello world, this is not const!" is reused for assignment to variable test.  Without test there, ___str_0 is redundant and can be removed.

Anyway I do agree with you that this bug is annoying and probably deserves a bump to gain some present day attention.

What I was mainly wondering is if anyone had taken the EP further with C compilation.  It looks like it stalled with your efforts a few years ago :(  The EP is an especially interesting target and we're all interested in it but it's also one of the more difficult ones that would require some input from experienced EP users to do well.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.18. 19:45:21
It looks like you got involved while the z80 port was being rewritten.  Things are stable now :)

Sounds cool. About your previous message in general: my try with sdcc was more or less a "one night coding experiment". Please do not treat that I am so great in sdcc internals or such, all of my work was just experimenting, and checking out what sdcc generates and try to "squeeze it" into some usage program on the Ep128 :) That's about all.

Since it was years ago, you must be right: things can change during the time passed meanwhile.

Honestly I can't remember what was the details about my problems with sdcc, but surely one of was the "stored twice" stuff (the bug report). Another issue was (but again: I can't remember too much) that sdcc generated CODE to initialize data ... of course it's totally useless and unacceptable, I guess it was because of some MCU support (sdcc was - originally? - written for, where there is strict separation between code and data usually, the so called Harvard-architecture).


Quote
To be fair, they do have eight pages of bug reports -- enough that they probably pick the easiest and/or most interesting (to them) to fix first.

Well, do not misunderstand me. I don't want to "blame" sdcc project, just it was "too much" for the knowledge/time I have for a "proof of the concept" EP/sdcc project only with some "Hello world!" style result :)

Quote
What I was mainly wondering is if anyone had taken the EP further with C compilation.  It looks like it stalled with your efforts a few years ago :(  The EP is an especially interesting target and we're all interested in it but it's also one of the more difficult ones that would require some input from experienced EP users to do well.

Well I am not sure how experienced EP user I am, but since I wrote (well, "am writing") two EP emulators, maybe I have enough knowledge on the EP side, but not on the sdcc :(  I would be interested, but I have not so much time ...
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.19. 02:17:14
Honestly I can't remember what was the details about my problems with sdcc, but surely one of was the "stored twice" stuff (the bug report). Another issue was (but again: I can't remember too much) that sdcc generated CODE to initialize data ...

Yes that problem is gone now too.

Quote
Well I am not sure how experienced EP user I am, but since I wrote (well, "am writing") two EP emulators, maybe I have enough knowledge on the EP side, but not on the sdcc :(  I would be interested, but I have not so much time ...

Well I can do the compiler side; it's the EP side that I would need the help with :)  This would be under z88dk but sdcc can be used with z88dk too.   When used with z88dk, sdcc gains access to the much larger set of libraries in z88dk which are all written in assembly language.

I will see what I can learn tonight but mainly I'm looking at:

1. What sort of executables should be produced..   Cartridge?  Com?  Binary loaded into ram?

2. Is EP64 and EP128 different enough that they should be two different targets?

3. What does the memory map look like.  Is there any 'slow' ram to be aware of?

4. Who owns the interrupts and does the program field them?

5. The display file is a difficult one.. it's programmable so I'd need to know what sort of resolutions should be supported and then pick one to start with.  Ideally it's a bitmapped screen.

6. For stdin/stdout/stderr, z88dk can supply its own terminals.  These terminals support non-overlapping windows and proportional fonts so we usually want to implement terminals using z88dk's drivers for every target and then supply another set of terminals as supported by the target (eg EXOS).  These will occupy less space in the binary but the native terminals can't always do the type of terminal expected by C, particularly the line-oriented editing.  I'd need to figure out if EXOS can be used for these lightweight terminals.

7. The initial main block of asm code we look for from the target is a set of display file primitives that can compute screen addresses from pixel and character coordinates, scroll a rectangle upward, clear a rectangle so that the terminal drivers can be easily implemented.  If these are missing we have to write them.  As an example, here is a set for the spectrum: http://z88dk.cvs.sourceforge.net/viewvc/z88dk/z88dk/libsrc/_DEVELOPMENT/arch/zx/display/z80/  Again we've tended to implement them separately from the existing OS code (EXOS in EP's case) because they tend to be quicker and it gives the tools the ability to generate code that doesn't rely on the firmware.  Sometimes cartridge targets cannot access system firmware.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.19. 08:46:37
Well, sorry in advance, I type this in hurry, hopefully it's understandable even with my English :)

Quote
1. What sort of executables should be produced..   Cartridge?  Com?  Binary loaded into ram?

It depends what you want to use :) But in general, I think the most useful on EP (for a program compiled from C source) is maybe the loadable program (into RAM). I am not sure if it's important that someone want to write a C program can be complied into ROMable code ... What people usually does, is the type-5 EXOS header applications (EXOS have the notion of file headers which is basically makes possible that EXOS will "know" what to do with a file ... it's a "machine code user app", an IS-BASIC program, or a system extension or even some gfx information with some special EXOS extensions, and so on). So you don't need "BASIC loader" what many 8 bit micros, for machine code programs.

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/kernel/Ch10.html

(see: 10.4 New Applications Programs)

Quote
2. Is EP64 and EP128 different enough that they should be two different targets?

Not so much, the main difference is the amount of RAM. In general, EP is quite flexible on memory configurations, it has 4Mbyte (22 bit) address space and address bus width on the motherboard, and it's not uncommon nowdays to have EPs with 512K or even more RAM installed. On the software side, I think original EP64 had older EXOS version.

Quote
3. What does the memory map look like.  Is there any 'slow' ram to be aware of?

Z80 as the CPU has four 16K long pages of the 64K address space. The system bus instead is 4Mbyte wide, also divided into 16K long segments (256 segments). Any of the segments can be "mapped" to any of the pages. A segment can contain ROM, RAM or undecoded. The last four segments is the VRAM (Video RAM) used by the video chip ("Nick") of the Enteprise. On EP64 this is the only RAM in the system without expansion. On EP128 there are another 64K RAM in the system as a form of a PCB "stacked over" on the mother board. VRAM access by the CPU is slower as it must share the time with the Nick chip (actually VRAM access by the CPU is done through the Nick chip which used the "CPU clock deformation" trick). Please note, that Nick *always* accesses the 64K VRAM directly, the segment/page mapping stuff is only for the CPU (but from the view point of the CPU VRAM are the segments 0xFC-0xFF). Also please note, that RAM segments are not needed to be continuous and often it's not (EP's own - EXOS - is flexible enough to handle situations like this). EXOS has the function 24 - allocate segment which can be used by programs to allocate RAM segment, it always gives the lowest numbered segment. Thus it only gives video segment ("slower") if "other" RAM segments are all used. Segment 0xFF (which is the top segment in VRAM too) is used by EXOS as the "system segment".

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/kernel/Ch11.html

Quote
4. Who owns the interrupts and does the program field them?

Usually (see memory mapping) page 0 (so 0-3fff Z80 addresses) should always contain the "zero page". A segment for this (if I am correct the lower numbered segment with RAM on the system detected by EXOS memory test on boot etc) is selected by EXOS. This contains the interrupt vector for "hardware" interrupt (in IM1 mode of Z80), and also eg the vector for RST 0x30 used by EXOS calls for example. The memory mapping applied by the user is preserved, and restored after execution of the interrupt handler but of course it is modified meanwhile eg to page EXOS ROM code in, etc, meanwhile. In EP, there can be more sources of interrupts: Nick, the video chip can generate interrupt baed on the LPT definition, the Dave chip (which does eg sound, interrupt "controller" purposes and for example the memory "mapping" itself) can generate 1Hz interrupt or even a programmable one, etc. Of course, if you disable interrupts, or having own interrupt service routine then you can map another segment into page 0 as well.

Quote
5. The display file is a difficult one.. it's programmable so I'd need to know what sort of resolutions should be supported and then pick one to start with.  Ideally it's a bitmapped screen.

Complex topic. Nick is quite flexible, no "global video mode" as with most video chips, but only the starting address of the LPT (Line Parameter Table) is set, and even for every scan lines you can have entries (LPB - Line Parameter Block) in LPT with the video mode, colour mode, margin parameters, and so on. The time of a scanline is divided into 57 "slots". The main rule of Nick, that it can read two bytes within a slot from VRAM. The first 8 slots are used to fetch the current LPB (2*8=16 bytes) the last three is used for horizontal retrace and memory referesh. So in theory, there is 46 slots left, but it can be outside of the visible area of video displays to show all, so sometimes fewer (like 42) is really used. Anyway, let's the example with 42 now. As within a slot Nick can read 2 bytes, for 1 bpp mode it means 2*8=16 pixels, which is 16*42=672 pixel horizontal resolution. You can see that in 2 bpp (= 4 colour mode) it's the half of that, and so on. This is "pixel mode", but there is eg text mode (I mean the hardware text, the "80 coloumn text mode" is a pixel mode for real not hardware text) uses one byte for character code and one byte for chargen access, and attribute mode for screen/attrib access (I don't know too much on ZX Spectrum, but I think this attribute mode is the most similar to ZX screen, just the definition of the attribute bytes are a bit different and there is no hardware flashing stuff). Colour modes: 1bpp=2col, 2bpp=4col, 4bpp=16col, 8bpp=256col. An LPB contains 8 colours for palette information used in 2/4/16 colour modes (in 16, only the first 8 colours, and the "FIXBIAS" register is needed). In 256 colour mode the palette is not used at all and controls the output directly. The vertical resolution is limited more by the requirements of the PAL video standard, and you must provide the correct vblank/vsync as well (in the LPT). This sounds too complex but it allows tricks to use eg even interlace modes, and other tricks. Even the location of the given video memory address is stored on per LPB basis! It allows nice tricks eg show the same scanline more on the screen or even "faked" reflection like tricks / whatever, or animation by hardware without any CPU usage, and so on.

http://ep.lgb.hu/doc/Nick.html

Quote
6. For stdin/stdout/stderr, z88dk can supply its own terminals.  These terminals support non-overlapping windows and proportional fonts so we usually want to implement terminals using z88dk's drivers for every target and then supply another set of terminals as supported by the target (eg EXOS).  These will occupy less space in the binary but the native terminals can't always do the type of terminal expected by C, particularly the line-oriented editing.  I'd need to figure out if EXOS can be used for these lightweight terminals.

I am not sure about this one, especially about the control characters. EXOS (as always ...) has a quite complex and advanced solution for this topic as well: if you want to display anything you must open a channel (similar notion as open a file in other OSes, just the special name "DISPLAY:" needed, with some preparation call). In theory you can even have more video channels open at the same time "allocated" from different space of the visible area but not side-by-side, so a given scanline describes one mode for the Nick.

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/video/

For stdin if it's the keyboard, you must also open a channel for the keyboard device. And for sound, the sound device. :) Anyway, all of these channels have the common attribute that then normal read/write calls are used as with "regular files". For speaking of C, it's similar that stdin has fd=0 and stdout fd=1, stderr=2, and you can have other files open, and depending the file descriptor value the underlaying OS will do different things of course. Just one difference with EXOS channels, that in EXOS you must give a number to be used later on open, while with C file open function you will get some number at open (excluding the "well known fd numbers" like the mentioned stdin/stdout/stderr).

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/

Quote
7. The initial main block of asm code we look for from the target is a set of display file primitives that can compute screen addresses from pixel and character coordinates, scroll a rectangle upward, clear a rectangle so that the terminal drivers can be easily implemented.  If these are missing we have to write them.  As an example, here is a set for the spectrum: http://z88dk.cvs.sourceforge.net/viewvc/z88dk/z88dk/libsrc/_DEVELOPMENT/arch/zx/display/z80/  Again we've tended to implement them separately from the existing OS code (EXOS in EP's case) because they tend to be quicker and it gives the tools the ability to generate code that doesn't rely on the firmware.  Sometimes cartridge targets cannot access system firmware.

One problem (in my opionion - I mean) that if you use EXOS to set video mode / open video channel etc EXOS stuffs. Though you don't need to mess with LPT/LPB and things like this, the allocated structure for the video information in VRAM (done by EXOS for you) LPT etc, but you can't know exactly where the video information is put (eg start of the video information) also it may not be linear. For example EXOS on scrolling the screen can modify LPT (the start address of video information in LPBs) instead of "scrolling information on memory" which is good for the performance, but problematic if you want to use the memory directly. Through EXOS you can dispaly stuffs of course, but as you can expect, it's much slower than doing it "directly".

If you see my crt0 implementation is barely the type-5 EXOS file header, opening video and keyboard channel, and simple routines to get a char from keyboard or output one to the screen using EXOS functions.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.19. 19:53:20
Well, sorry in advance, I type this in hurry, hopefully it's understandable even with my English :)

Ha, your English is better than most Englishmen's.  Example:

Quote
it's a "machine code user app"

You know the difference between "it's" and "its".  This is a 'tell' for people educated in the UK - a very large number have difficulty with correct usage of apostrophes.  I've spent some time on UK-dominated forums and, sadly, it's beginning to rub off on me too when I write quickly.  Maybe some Hungarian English will set things right :)

Quote
Quote
1. What sort of executables should be produced..   Cartridge?  Com?  Binary loaded into ram?
It depends what you want to use :) But in general, I think the most useful on EP (for a program compiled from C source) is maybe the loadable program (into RAM). I am not sure if it's important that someone want to write a C program can be complied into ROMable code ...

I'd like to support all types even if people only use the RAM executable.  It's not difficult to do since the tools are already there to produce ROMs.

Quote
What people usually does, is the type-5 EXOS header applications (EXOS have the notion of file headers which is basically makes possible that EXOS will "know" what to do with a file ... it's a "machine code user app", an IS-BASIC program, or a system extension or even some gfx information with some special EXOS extensions, and so on). So you don't need "BASIC loader" what many 8 bit micros, for machine code programs.
http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/kernel/Ch10.html
(see: 10.4 New Applications Programs)

Thanks for the link - I'm still working through all the documentation on that site.

EP devices are not interrupt driven then, other than what dave & nick are doing?  For example, disk / network / serial devices are not depending on an interrupt to do i/o or turn off motors or anything like that?  And the interrupters (including new peripherals) are not im2 devices?

Quote
In general, EP is quite flexible on memory configurations, it has 4Mbyte (22 bit) address space and address bus width on the motherboard, and it's not uncommon nowdays to have EPs with 512K or even more RAM installed. On the software side, I think original EP64 had older EXOS version.

What I'm thinking about doing initially is a 64k target with 48kish ram at the bottom and the top 16kish containing the display data and being pageable for extra ram.  This fits with the simple model many other machines are currently using for games where a 16k window is used to copy level data (eg) into the main ram as needed.  The EP is more flexible than that but this would provide a simple starting point familiar to everyone where we don't have to worry about code being generated into individual 16k pages.

The -ish part depends on how much ram EXOS is using on the top segment on EP64 machines.

Quote
EXOS has the function 24 - allocate segment which can be used by programs to allocate RAM segment, it always gives the lowest numbered segment. Thus it only gives video segment ("slower") if "other" RAM segments are all used. Segment 0xFF (which is the top segment in VRAM too) is used by EXOS as the "system segment".

Ok so you always get fast ram if it's available when you load in.  Executables output by the compiler consist of CODE/DATA/BSS sections in order and on other targets, BSS is sometimes left off to improve loading times.  The EXOS header for New Application Programs (bytes 2&3) contain a length which I assume corresponds to how many pages will be allocated for the program by the loader.  Does that length have to correspond to the length of the file on disk or tape?  What I want to do is chop off BSS so that only CODE+DATA sections are loaded but the length parameter in the header must be CODE+DATA+BSS size to reserve the necessary number of pages.

Quote
(display)
Complex topic. Nick is quite flexible, no "global video mode" as with most video chips, but only the starting address of the LPT (Line Parameter Table) is set, and even for every scan lines you can have entries (LPB - Line Parameter Block) in LPT with the video mode, colour mode, margin parameters, and so on.

Yes it is.. that flexibility also makes it difficult to settle on a good way to do things.  I think what I will do is take over the machine and access hw directly except for file / printer / serial i/o.  I'm guessing that EXOS can't be used to implement the sort of terminal io expected from C but we can put that decision off until much later.

For display, I think there should be a way to declare surfaces of variable size for different modes.  The data for the surface would be directly written by the terminal / graphics / sprite engines and then the LPT is under program control so that you can pick out where and how much of these surface are displayed.  I think we can define LPTs declaratively in the crt so you could split a screen into hi-res top, text bottom, eg without too much trouble and we can do the same for display surfaces.  This would be an extension of how we statically instantiate drivers on stdin/stdout/stderr in crts now and would get some good defaults for users and at the same time leave it open to more advanced users to make their own crts with their own custom resolutions.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.21. 20:51:12
Ha, your English is better than most Englishmen's.  Example:

You know the difference between "it's" and "its".  This is a 'tell' for people educated in the UK - a very large number have difficulty with correct usage of apostrophes.  I've spent some time on UK-dominated forums and, sadly, it's beginning to rub off on me too when I write quickly.  Maybe some Hungarian English will set things right :)

Maybe it's because we ("we" as non-native speakers) learn English with the "logic" of the grammar rules, where native speakers don't even think too much about the "logic" so it can result in confusing similarly spelled (but quite different) constructs like "its" and "it's" because they would say "well I know WHAT meaning of the confused it's/its is used there so who cares". But learners/non-native speakers would have problems not to see the exact (and right) word thus it looks like confusing for them then.

Quote
I'd like to support all types even if people only use the RAM executable.  It's not difficult to do since the tools are already there to produce ROMs.

I see. EP ROM's are usually in the form of EXOS_ROM stuffs, that the ROM image starts with the identifier of string "EXOS_ROM". EXOS itself (by its "boot process") will find these (because of the identifier strings). These ROMs then are "attached into the system", eg an EXOS command will ask these ROMs too if they "owns" the command and want to react, or it's not the command it is aware of. The same applies for device drivers, you can even create a DISPLAY: device which then "overrides" the internal DISPLAY: of EXOS (the display device driver, I mean). Also, EXOS makes it possible to "decode" HELP requests in the system or custom error strings. EXDOS itself is also an EXOS_ROM in this manner to be "connected into" the EXOS "system flow" this way.
However this requires quite "tight" bonding eg passing values/return codes in registers, preserving some other registers. Maybe that is a bit hard doing in C code. Of course the situation is more simple if you want a more complex program in ROM. In this case you can have an EXOS command to "start" your program, then you will have some minimal code to "respond" the EXOS requests, but then you do whatever you want. Hmm, I am not sure if I can explain myself well enough in an understandable way though ...

What I also wanted to say: the situation is a bit more complex than on other 8 bit systems where you usually put a ROM image in the system without too much interaction with the rest of the software components on the system. But it's more like a "my feeling" like difference ...

Quote
Thanks for the link - I'm still working through all the documentation on that site.

You're welcome.

Quote
EP devices are not interrupt driven then, other than what dave & nick are doing?  For example, disk / network / serial devices are not depending on an interrupt to do i/o or turn off motors or anything like that?  And the interrupters (including new peripherals) are not im2 devices?

Not IM2, but IM1, if I remember correctly :) Interrupts from various sources are routed through the Dave chip acting as "interrupt controller" (generating the single interrupt for the Z80 then, well, if it's enabled in Dave). So though there is only one "hardware interrupt" entry for Z80, the interrupt handler code of EXOS can look bits in Dave up to get to know what is the source of the given interrupt. You can even disable one or more interrupt sources in Dave. Also Dave contains latches for the interrupt sources you must clear to stop generating interrupt for the Z80. So, if there is an interrupt and other sources would generate one for another source meanwhile, it won't lost this way, at least I can see the situation.

Interrupt sources can be Nick (each LPB in LPT can specify VINT to generate an interrupt but since it's edge triggered, you can't have interrupt for two (or more) neighbour LPBs as it won't provide an edge between them. So it's some kind of "raster interrupt" programmable for even more raster lines (with the constraint I mentioned above). EXOS creates its LPTs to generate one VINT per frame to provide the 50Hz (PAL video timing) interrupt needed eg for keyboard scanning to fill the kbd buffer which can be queried by software then. This is one of the two external interrupt pins of Dave (connected with the VINT pin of Nick). The other is not used, or hmm maybe it's the serial stuff, I am not sure about this, since I've never wanted to use serial connection with the EP). The two other interrupt sources are generated internally by the Dave itself (well, if they're enabled of course). One of that is the 1Hz interrupt which can be useful for real-time clock stuff (for example Zozosoft's RTC card uses that to display time on the top of the screen with its ROM, ZT - ZozoTools). The other internal interrupt is the "sound interrupt". I guess it's named that way since it uses a programmable frequency oscillator of the Dave which would be used to generate a sound normally or can be switched to a constant frequency (1KHz or 50Hz).

http://ep.lgb.hu/doc/Dave.html

I don't know if other components in EP uses interrupts anyway ... The FDC motor auto-off is maybe used by EXDOS (I'm sorry, I can't remember ...) but I don't think there are too much other uses. Of course the VINT generated std 50Hz EXOS interrupt as I've written, is used keyboard scanning and maybe the FDC motor stuffs and also some internal EXOS stuffs (increment its internal software clock, etc). What I meant that FDC controller for example don't use hardware interrupts, EXDOS uses (as far as I can guess, maybe I am not the most clever person in this area on the forum, I have to say ...) polling to wait for a completed operation for example (possible with some upper limit for timing the operation out).

Quote
What I'm thinking about doing initially is a 64k target with 48kish ram at the bottom and the top 16kish containing the display data and being pageable for extra ram.  This fits with the simple model many other machines are currently using for games where a 16k window is used to copy level data (eg) into the main ram as needed.  The EP is more flexible than that but this would provide a simple starting point familiar to everyone where we don't have to worry about code being generated into individual 16k pages.

The -ish part depends on how much ram EXOS is using on the top segment on EP64 machines.

This sounds good for me. There is a more complex scenario but I don't think sdcc can support it: ie the "far pointer" scenario where a segment number and offset is also stored within a pointer (in contrast of "near pointer" which is simply a 16 bit value directly accessible for the Z80 without extra ops) and an access would cause to alter the segment mapping. But it's complex, slow, and requires extra code in the core compiler code, I think. If I am right ...

Quote
Ok so you always get fast ram if it's available when you load in.  Executables output by the compiler consist of CODE/DATA/BSS sections in order and on other targets, BSS is sometimes left off to improve loading times.  The EXOS header for New Application Programs (bytes 2&3) contain a length which I assume corresponds to how many pages will be allocated for the program by the loader.  Does that length have to correspond to the length of the file on disk or tape?  What I want to do is chop off BSS so that only CODE+DATA sections are loaded but the length parameter in the header must be CODE+DATA+BSS size to reserve the necessary number of pages.

As far as I can remember, EXOS files with type-5 header can be max of 48K (well, minus 256 bytes, since they are loaded to $100 - the 16 bytes long header is not loaded though), and the memory used by the loaded program is allocated, and segments are mapped to be able to access them by the CPU directly. However, there is some problem if you have large BSS area. What I mean here, that your program (let's say) would fit in 16K after loaded, but with the BSS part it's over of 16K. Then you have some extra work to allocate and then map a segment as page 1 ($4000-$7FFF) so you can use it for the "tail of the BSS area". Some people are lazy :) and have the habit to simply enlarge the binary enough to also contains the BSS thus no problem, and no "manual" memory allocation + mapping work is needed. However in my opinion it's not so nice to enlarge the binaries just to save this work which can be done in some bytes of asm code (even with some code to zero the BSS area to have a well defined state, if it's needed at all, since in C, I think nobody says that it's a good idea to access uninitialized variables before some value assignment ...).

To be honest, I can't recall now what the size info in the header means exactly, but if you see the example crt0 code, you will see hopefully :) I so often confuse this that I usually have a look of an older work of mine and do that way :) I must admit, this is a very lame answer from me, I'm sorry :oops:

Quote
Yes it is.. that flexibility also makes it difficult to settle on a good way to do things.  I think what I will do is take over the machine and access hw directly except for file / printer / serial i/o.  I'm guessing that EXOS can't be used to implement the sort of terminal io expected from C but we can put that decision off until much later.

Well, that's a hard question. As I will mention later :) in this post, some may want to use "EXOS centric" simple stream like console I/O which can be integrated into std EXOS I/O for some reason. Without even using any (console) control codes other than maybe newline or such. It's more like a C program can also use only putchar() (or some "frontend" on top of it like printf()), but others may expect a conio-level interface for some _other_ purpose. Both of them can be important and useful in some cases, hard to replace with the other!

Quote
For display, I think there should be a way to declare surfaces of variable size for different modes.  The data for the surface would be directly written by the terminal / graphics / sprite engines and then the LPT is under program control so that you can pick out where and how much of these surface are displayed.  I think we can define LPTs declaratively in the crt so you could split a screen into hi-res top, text bottom, eg without too much trouble and we can do the same for display surfaces.  This would be an extension of how we statically instantiate drivers on stdin/stdout/stderr in crts now and would get some good defaults for users and at the same time leave it open to more advanced users to make their own crts with their own custom resolutions.

I like the idea to create an API which can provide most of the features what EP can do. Split screen with different resolution (thanks to Nick and its LPT feature) is one of that. But not only hardware is what someone should relay on, but also the software. Eg EXOS has the channel notion to open files. For screen/display stuff I would vote for direct hardware access because of the speed. However for file I/O it's better to use it trough the EXOS (and EXDOS) of course, especially because of the great spectrum of possible "modern" storage solutions (just two examples: SD card cartridge, and the IDE HDD interface) which are totally incompatible at hardware level, but there is a common ground (implemented in software), in the form of EXDOS. For example Bruce (one of the creator of Enterprise) has the nice EPNET project to build ethernet connectivity for the EP with the help of "hardware tcp/ip chip" from Wiznet (W5300). If I know well enough the details, it's also considered to provide EXOS compatibility later, that is, you can open a channel (like a file channel ...) to open - for example - a TCP connection to a remote server on the Internet. Just supporting this channel notion through the planned C API/SDK would make it possible to support even future projects more or less.

Thanks to the well designed (especially to its age!) software of the EP, most software would use software access anyway for many things, especially file I/O unlike on computers like Commodore 64 (don't get me wrong: I am a great fan of C64 too), where a new storage solution is kinda problematic because of the not so well defined software layer (first: you need a modified KERNAL ROM, but even then many software use non-standard entry points, IEC-serial direct routines or even hardware access, and so on. Just read the description of IDE-DOS for C64 with the guide how to port/write "good" softwares works with IDE-DOS then too). Nice thing about EXOS/EXDOS that you don't need too much to "modify" ROM etc, because you can add "extensions" expanding the base set of OS routines, if I can say this way. For example SD card cartridge only needs a quite short "block level routines" used by the base EXDOS then to "hook it up" into the system then quite naturally.

But it raises a question (better say: a bunch of questions): let's see open file first. One can support EXOS specific/centric functions like exos_open() with the semantics of the EXOS to be able to exploit all the EXOS features. At the other hand, for C portability some can support fopen() or open() too. For simple I/O some can support simple putchar() and higher level stuffs like printf() which does not even assume too much control characters or such (some programs needs only this!), but others would prefer conio like functions, or even (well, let's say an example BGI/TGI like stuff) gfx functions. I think, the best would be providing all of the possibilities and usage cases ... But that requires great amount of work, of course. Also, static linking the full feature set would result in too large binaries.

Sorry, I do not know enough about the features of sdcc and its standard library/libraries, maybe my ideas are simply odd or overkill.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.22. 01:37:34
This sounds good for me. There is a more complex scenario but I don't think sdcc can support it: ie the "far pointer" scenario where a segment number and offset is also stored within a pointer (in contrast of "near pointer" which is simply a 16 bit value directly accessible for the Z80 without extra ops) and an access would cause to alter the segment mapping. But it's complex, slow, and requires extra code in the core compiler code, I think. If I am right ...

sdcc is beginning to support C Embedded, which is a C language extension for embedded systems.  C Embedded specifies how to deal with bankswitched memory and sdcc is starting to do that but I haven't looked in detail at it yet.  sccz80 does have 3-byte far pointers but again it's preliminary.  This is on my to-do list so once I've studied it I will include it in the crts.  I don't think it needs more than providing a subroutine in page-0 (the 'HOME' bank) to perform bankswitching and maybe provide some trampoline code.

So for now, it's left to the user program to handle bankswitched memory intelligently.  What we can do with the crt, for the ep, is make sure all the video-related stuff, some key functions like memcpy, and interrupt related handlers are in page-0 so that user code can be free to place two 16k pages in page-2/3 to copy or operate on data in different banks.  The ep will be the first target that needs a special memory map for this sort of thing :)

Quote
As far as I can remember, EXOS files with type-5 header can be max of 48K (well, minus 256 bytes, since they are loaded to $100 - the 16 bytes long header is not loaded though), and the memory used by the loaded program is allocated, and segments are mapped to be able to access them by the CPU directly. However, there is some problem if you have large BSS area. What I mean here, that your program (let's say) would fit in 16K after loaded, but with the BSS part it's over of 16K. Then you have some extra work to allocate and then map a segment as page 1 ($4000-$7FFF) so you can use it for the "tail of the BSS area". Some people are lazy :)

Heh yeah :)  That's what I want to do:  tell EXOS that the program is CODE+DATA+BSS bytes in size and have it allocate the pages but only load CODE+DATA bytes.  But because of the 48k limit it might be better just to do the BSS allocation at runtime so that it is possible to go beyond 48k.

Quote
since in C, I think nobody says that it's a good idea to access uninitialized variables before some value assignment ...).

The BSS segment has to be zero according to the C standard but the crt takes care of all initialization details so the loader doesn't have to worry about it.

Quote
Well, that's a hard question. As I will mention later :) in this post, some may want to use "EXOS centric" simple stream like console I/O which can be integrated into std EXOS I/O for some reason. Without even using any (console) control codes other than maybe newline or such. It's more like a C program can also use only putchar() (or some "frontend" on top of it like printf()), but others may expect a conio-level interface for some _other_ purpose. Both of them can be important and useful in some cases, hard to replace with the other!

I like the idea to create an API which can provide most of the features what EP can do. Split screen with different resolution (thanks to Nick and its LPT feature) is one of that. But not only hardware is what someone should relay on, but also the software. Eg EXOS has the channel notion to open files. For screen/display stuff I would vote for direct hardware access because of the speed. However for file I/O it's better to use it trough the EXOS (and EXDOS) of course, especially because of the great spectrum of possible "modern" storage solutions (just two examples: SD card cartridge, and the IDE HDD interface) which are totally incompatible at hardware level, but there is a common ground (implemented in software), in the form of EXDOS. For example Bruce (one of the creator of Enterprise) has the nice EPNET project to build ethernet connectivity for the EP with the help of "hardware tcp/ip chip" from Wiznet (W5300). If I know well enough the details, it's also considered to provide EXOS compatibility later, that is, you can open a channel (like a file channel ...) to open - for example - a TCP connection to a remote server on the Internet. Just supporting this channel notion through the planned C API/SDK would make it possible to support even future projects more or less.

I agree with all the above.  I've read quite a bit more and I've started to write some of the library code (I'll mention what's missing below).

I've given the ep's different video modes my own names (I don't know if something better already exists) and I'm measuring characters as 8x8 pixels:

* p2 (pixel 2 colour mode) 80x25 characters full screen
* p4 (pixel 4 colour mode) 40x25 characters full screen
* p16 (pixel 16 colour mode) 20x25 characters full screen
* a8 (attr 8 scan lines tall) 40x25 characters full screen, 40x25 attributes
* c128 (hardware characters)

a8 corresponds to the zx spectrum, a1 corresponds to the ts2068 (1 attribute byte per 8 pixels) and of course there are other aN and cN.

The crt will be able to statically declare up to one display surface per mode.  The size of each display surface would be specified in characters and could be anything from very small to very large.  Memory for these surfaces would be allocated at startup from video memory and how they are displayed would be up to the LPT.  The LPT may only display a portion or all of each surface.  The video memory address and dimensions of each display surface would be stored in global variables accessible by the C library.

The C library will operate on the video memory corresponding to each display surface directly.  The library will have to supply video primitives for each display surface type.

I'm going to write the p4 primitives first and possibly the p2, c128 and a8 modes later.  Ultimately all of them should be there but I think it will be up to the EP community if they are interested in it.  I'm picking on the a8 mode specifically because this is compatible with the zx spectrum and the zx spectrum has a sprite library that has been used by many games which could easily use this mode on the EP.  That sprite library is intended to support many video modes so it could be modified for other of the EP's modes but that is also a lot of work.

Does this sound like a good method to deal with the EP's flexibility?

For file i/o, the clib in z88dk has not finalized it yet -- all the code is present for file systems but the drivers have not been written to do file i/o yet.  The design is object oriented and operates like a stack where you would inject the target's native system at the level it can support.  If the target does not supply any disk device the idea is we will supply the entire stack including a fat driver.  But that's a long time for now.

For the first pass, I'll ignore file i/o (and don't forget you can always call EXOS directly from within C) and then second pass maybe look at connecting stdio to any sort of streaming that EXOS can support.  At the lowest level, stdio generates about a dozen messages for i/o and if those messages can be satisfied by EXOS, it can be plugged in.  I think things like the printer, serial i/o, built-in EXOS video drivers can probably plug into stdio but EXDOS (disk i/o) doesn't seem to be a candidate.  It looks like it performs one whole read.write operation and then closes the channel.  So in order to use it like a streaming device, the z88dk driver would have to cache disk blocks in ram for stdio to access.

Quote
... But that requires great amount of work, of course. Also, static linking the full feature set would result in too large binaries.

Sorry, I do not know enough about the features of sdcc and its standard library/libraries, maybe my ideas are simply odd or overkill.

z80asm is a linking assembler so it will only pull in code if the program uses it.  You can add all sorts of things to the library without worrying about it being attached to the binary all the time.

sdcc's libraries are minimal but z88dk's are fairly substantial.  The two shouldn't be operated separately :)

The EP-specific code that needs to be written includes:

* direct access to keyboard and joystick hw.   There is also an api for mice but this is the minimum.  I found details on port $b5 for reading the keyboard directly but I got a little confused with the built in joystick.

Key matrix:

Code: [Select]
;EP keyboard matrix:
 ;        b7    b6    b5    b4    b3    b2    b1    b0
 ;Row    80H   40H   20H   10H   08H   04H   02H   01H
 ; 0   L.SH.     Z     X     V     C     B     \     N
 ; 1    CTRL     A     S     F     D     G  LOCK     H
 ; 2     TAB     W     E     T     R     Y     Q     U
 ; 3     ESC     2     3     5     4     6     1     7
 ; 4      F1    F2    F7    F5    F6    F3    F8    F4
 ; 5         ERASE     ^     0     -     9           8
 ; 6             ]     :     L     ;     K           J
 ; 7     ALT ENTER   LEFT  HOLD   UP   RIGHT DOWN  STOP
 ; 8     INS SPACE R.SH.     .     /     ,   DEL     M
 ; 9                   [     P     @     0           I

I thought left, right, up, down (and space for fire) were the built in joystick.

But then I saw mention of port $b6 in connections with the joystick... how do I read the joystick directly?  There's also mention of external joysticks in the EP tech docs -- is there a standard way to directly read that hw?

* display primitives that can compute pixel addresses for different display modes given the surface declared by the crt.  The C library will use these to print and draw.

* fzx draw character primitive for each video mode.  This is the putchar for proportional fonts.

* sound.  The sound library is 1-bit oriented but it contains some really good music synthesis routines.  It should be compatible with Dave.

* drivers for fixed width and proportional font terminals.  This is mostly implemented through code inheritance.

The rest is common code.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.22. 21:04:40
sdcc is beginning to support C Embedded, which is a C language extension for embedded systems.  C Embedded specifies how to deal with bankswitched memory and sdcc is starting to do that but I haven't looked in detail at it yet.  sccz80 does have 3-byte far pointers but again it's preliminary.  This is on my to-do list so once I've studied it I will include it in the crts.  I don't think it needs more than providing a subroutine in page-0 (the 'HOME' bank) to perform bankswitching and maybe provide some trampoline code.

So page-0 is always "fixed" and not "mapped out" ever. That's a good thing, especially if you plan to use EXOS calls, and of course because interrupts, etc.

Quote
So for now, it's left to the user program to handle bankswitched memory intelligently.  What we can do with the crt, for the ep, is make sure all the video-related stuff, some key functions like memcpy, and interrupt related handlers are in page-0 so that user code can be free to place two 16k pages in page-2/3 to copy or operate on data in different banks.  The ep will be the first target that needs a special memory map for this sort of thing :)

I see.

Quote
Heh yeah :)  That's what I want to do:  tell EXOS that the program is CODE+DATA+BSS bytes in size and have it allocate the pages but only load CODE+DATA bytes.  But because of the 48k limit it might be better just to do the BSS allocation at runtime so that it is possible to go beyond 48k.

Well, you define the length of the loaded program in the type-5 EXOS header (contains CODE+DATA, so the "pre-defined" areas unlike BSS). Then you may need to check that if BSS size in addition to that size (CODE+DATA) would span into a new segment(s?). If yes, you need to allocate another segment(s). And then you fill the BSS area with zeroes (regardless you needed to allocate segments or not, because BSS could fit into the already used segments for the loaded program). Getting beyond 48K is interesting, but also problematic: if CODE+DATA+BSS bypasses 48K boundary you need modify segment mapping (port $B3) all the time between video RAM and "tail" of the BSS, especially if the program needs frequent access of screen routines, thus a video RAM segment. But if you really need to have more code+data+bss than 48K than you can't do too much. Well, maybe one thing: if you need direct VRAM access and you allocated a VRAM segment for page-3 (C000-FFFF) and it's not used fully, you can use VRAM to store eg BSS data as well. Yes, VRAM is slower, but maybe it's still faster if you can avoid memory paging all the time! It depends on the exact situation though.

For example EXOS uses a segment (or more segments, but by default one) in VRAM (segment $FF) as its own RAM area also called "system segment". It's a VRAM segment because it's also used to store LPTs, video RAM, etc, not just EXOS variables and similar things. Though it can be faster to use VRAM only for video purpose data, and "normal RAM" for other EXOS data, it would fragment the available memory map, and also the situation would be more complicated because of the needed mapping changes all the time. That system segment btw grows downwards, eg if you open an EXOS channel (let it be a file, or DISPLAY:, etc) EXOS need some RAM, and system segment usage is maintained (the lowest used address) in the form of "EXOS boundary" (technically you - as user app - can even allocate segment when all segments are used, then EXOS will provide the system segment as "shared segment" providing EXOS boundary is the address you should not use beyond).

Quote
The BSS segment has to be zero according to the C standard but the crt takes care of all initialization details so the loader doesn't have to worry about it.

Well, yes, it's only me that I hate to rely on initialized BSS, eg a variable in the global scope "int a;" should be zero according to the C standard, but the same "int a;" will not within a function (since it will be allocated on the stack). And some compilers will complain about "uninitialized variable" even if it's in the global scope, so it's initialized to zero according to the C standard anyway, if I am right ... Anyway, just ignore my comment, of course it is almost nothing to fill the BSS area with zero bytes and it seems it is expected by standards.

Quote
I've given the ep's different video modes my own names (I don't know if something better already exists) and I'm measuring characters as 8x8 pixels:

* p2 (pixel 2 colour mode) 80x25 characters full screen
* p4 (pixel 4 colour mode) 40x25 characters full screen
* p16 (pixel 16 colour mode) 20x25 characters full screen
* a8 (attr 8 scan lines tall) 40x25 characters full screen, 40x25 attributes
* c128 (hardware characters)

You can do this, but please note that EXOS usually refers vertical resolution in units of 9 pixels instead of 8. Of course if you plan to have your own routines to set up video modes (so: defining LPT) that it's your business to use 8 pixel tail characters, etc, whatever. But eg the character set definition for hardware character mode is also 8*9 pixels by EXOS (though of course, you can embed your own charset to the binary, but it also enlarges your binary of course). By the way, Nick allows any tail of characters in hardware character mode, also the definition of characters has the layout to support this (that is, eg in ch128 mode, 128 bytes for the first rasterline of the 128 characters, than again 128 bytes for the second, etc, unlike other schemes eg with Commodore 64 where the first 8 bytes are for the first character of the charset for all rasters, etc). And if you are in doubt: Nick can access the VRAM _only_ so even character set must be stored there. Of course EXOS ROM contains the charset, but it's copied into the VRAM to be used by Nick then. "Software character mode" is of course a simple gfx mode at the other hand (the "80 column text mode" is that, in contrast of "40 column text mode" which is really a text mode!). In this case the "charset definition itself" is only used by software to "draw" characters thus - of course - it's not compulsory to store it in VRAM to be able to accessible by Nick.

Quote
I'm going to write the p4 primitives first and possibly the p2, c128 and a8 modes later.  Ultimately all of them should be there but I think it will be up to the EP community if they are interested in it.  I'm picking on the a8 mode specifically because this is compatible with the zx spectrum and the zx spectrum has a sprite library that has been used by many games which could easily use this mode on the EP.  That sprite library is intended to support many video modes so it could be modified for other of the EP's modes but that is also a lot of work.

Yes, but Spectrum compatibility is limited because of the different attribute by "layout". Though it's a minor point.

Quote
Does this sound like a good method to deal with the EP's flexibility?

I think, other people should answer too. To be honest, I never had EP till 2002 or so, I get to know it as its "retro computing" state already, unlike more people here who were active even in the age of the EP. I still feel sometimes that I can't "beat" others' experience and knowledge originated from the "golden age" and not only "recently" :)

Quote
For file i/o, the clib in z88dk has not finalized it yet -- all the code is present for file systems but the drivers have not been written to do file i/o yet.  The design is object oriented and operates like a stack where you would inject the target's native system at the level it can support.  If the target does not supply any disk device the idea is we will supply the entire stack including a fat driver.  But that's a long time for now.

Well, in case of EP it is not needed and probably you can't do it either (because of the different used hw solutions, I've already written about). Internally EXDOS uses FAT12 btw, but you don't need to know that too much, if you want to use only the "file level" functions. It's interesting to hear what z88dk plans, FAT driver etc, huh. I mean it's almost an OS then, and not only a compiler with its standard library too much :) But EP has its own OS already, and not even a bad one! I don't know the goals of z88dk etc, but for me, I would vote for an ANSI-C like library eg usage of open() fopen() etc, so code can be portable between different systems at source code level, let it be an EP, or a modern PC ... But I know, it can be only *one* goal, the other can be - for example - to be able to exploit the target machine's abilities using the C language which may need its own "standard" suitable for the purpose. So it's really hard to judge, what would be better, at least it's hard for me ... Since you seem to know a way much on sdcc/z88dk etc, I wouldn't even dare to write on these too much more :)

Quote
For the first pass, I'll ignore file i/o (and don't forget you can always call EXOS directly from within C) and then second pass maybe look at connecting stdio to any sort of streaming that EXOS can support.  At the lowest level, stdio generates about a dozen messages for i/o and if those messages can be satisfied by EXOS, it can be plugged in.  I think things like the printer, serial i/o, built-in EXOS video drivers can probably plug into stdio but EXDOS (disk i/o) doesn't seem to be a candidate.  It looks like it performs one whole read.write operation and then closes the channel.  So in order to use it like a streaming device, the z88dk driver would have to cache disk blocks in ram for stdio to access.

I still think that for _EP_ C coders they would welcome EXOS-specific API as well, besided ANSI-C/z88dk/anything else. That would be a quite small and simple "glue" to call EXOS functions for the (for example) exos_CALLNAME() functions. Of course C code which use these are not so much portable anymore, but we shouldn't forget that 8 bit micros are not power machines, and often the best performing code can be written using platform specific own solutions instead of "abstraction layers" (in the form of APIs) providing cross-platform compatibility. Yes, that sounds the reverse of my previous thoughts that I would welcome ANSI-C like stuffs. Well, hard question, and both scenarios can be useful in some situations, I think!

Quote
I thought left, right, up, down (and space for fire) were the built in joystick.

Yes, they are.

Quote
But then I saw mention of port $b6 in connections with the joystick... how do I read the joystick directly?  There's also mention of external joysticks in the EP tech docs -- is there a standard way to directly read that hw?

The _internal joystick_ is just like other keys on the keyboard, even the same membrane is used. The only difference, that other keys uses buttons to be able to be operated, while up/down/left/right keys use mechanically different solution and the designers used a joystick handle to be able to use them instead of buttons. So, yes, the internal joystick can be interpreted as other keys, keyboard matrix contains them. For the _external_ joysticks, the situation is different, they are handled differently, as you mentioned with the $b6 port, they are not part of the keyboard matrix. That also mean that a software want to use internal _and_ external joystick they must use separated routine for that purposes.

You can also think about mouse, which is a "hot" topic recently, especially because software like SymbOS makes it almost "a must", and it seems many people interested in this topic anyway. You should check other topics on the forum about this :)
 
But btw the keyboard matrix: do you plan to use your own keyboard scanning routine instead of EXOS' one? Well, it can cause some problems at least since there is eg UK and BRD (and HUN) layouts defined in software, and layout can be changed. Also, there were some projects to interface with an external keyboard without the hardware level compatibility (though to be honest, it can cause problems with many EP software as well, since many of them doing direct hw access), and only on software level the compatibility is provided. I'm really unsure here what can be the best solution, in some situation there can be a significant overhead to allow EXOS interrupt, keyboard scan, than doing EXOS calls to check keyboard etc ...

Quote
* sound.  The sound library is 1-bit oriented but it contains some really good music synthesis routines.  It should be compatible with Dave.

Btw, Dave supports 6 bit D/A too. And "of course" it has got oscillators with some modulation/distortion/etc settings which are more like digital implementation (unlike with C64 SID, where there are analogue filters for example). Dave is stereo btw.

EXOS here is quite elegant btw, it again uses the channel notion, so you can open a channel (with "file name" of SOUND:). You can write quite "complex" sound definition "control codes" there, and EXOS within the EXOS interrupt will "play it" in the "background". Or something like that, honestly I have never used these ...

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/sound/Ch2.html

But in general, you can see how advanced EXOS is :) I was really surprised that a "8 bit micro" uses an OS like EXOS (biut . I don't want to say that you "must" use EXOS for SOUND at any price, just I mentioned it here for the completeness.

And feel free to write me "you're too much with those novels", I know I can write just too much :) Hopefully my long posts are not only for enlarge the database of the forum :)
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.24. 01:44:25
You can do this, but please note that EXOS usually refers vertical resolution in units of 9 pixels instead of 8. Of course if you plan to have your own routines to set up video modes (so: defining LPT) that it's your business to use 8 pixel tail characters, etc, whatever.

For the hardware modes, the native character set can be used at 9 pixels tall.  The screen size is still measured in characters.

For the other modes, the difficulty is the max common vertical screen resolution does not divide into 9.  Eg, p4 is typically max 320x200.  200 pixels is 25 chars tall if the chars are 8 pixels tall.  But if they are 9 pixels, it is 200/9 = 22.2 chars tall.  You can reduce the max vertical res to 9*22 = 198 pixels so it's not really a big deal.  The other things that are making me think 8 pixels is 8 is a power of 2 (add a register to itself three times to multiply by 8) and, most importantly, other z80 targets use height 8 pix for their fonts so doing it like this lets the EP benefit from fonts and code on other machines.

There's also a proportional font driver where fonts can be any height so the 9-pixel height specialness of the EP does not have to be lost.

Quote
Well, in case of EP it is not needed and probably you can't do it either (because of the different used hw solutions, I've already written about). Internally EXDOS uses FAT12 btw, but you don't need to know that too much, if you want to use only the "file level" functions. It's interesting to hear what z88dk plans, FAT driver etc, huh. I mean it's almost an OS then, and not only a compiler with its standard library too much :)

Yes it's meant to provide a complete system on z80 embedded systems so there are a lot of extras that other targets can select from as appropriate.

The user-level documentation I found on EXDOS mentioned that a disk channel was automatically closed after a read or write operation, so it seemed like EXDOS would not be able to support streamed i/o.  I was reading user-level documentation which was concerned with loadng and saving entire files rather than random access so it could be I was unlucky to look at the wrong place.

Would something like this be able to be efficiently implemented using just EXDOS?

Code: [Select]
while ((c = fgetc(in)) != EOF)
   fputc(process(c), out);

For this kind of common code to be efficient, the implementation has to cache several disk sectors in memory so that individual reads and writes go to memory rather than disk.  Most z80 disk implementations have been as simple as possible and perform very badly under C without assistance which is why z88dk is trying to supply disk i.o in a layered manner so that these simple systems can sit on top of a caching mechanism.


Quote
for example - to be able to exploit the target machine's abilities using the C language which may need its own "standard" suitable for the purpose. So it's really hard to judge, what would be better, at least it's hard for me ...

We don't replace the underlying system, only add to it.  So eg, a cpm system can still do file i/o by calling the bdos directly but the c standard i/o is also available to use.

Quote
The _internal joystick_ is just like other keys on the keyboard, even the same membrane is used. The only difference, that other keys uses buttons to be able to be operated, while up/down/left/right keys use mechanically different solution and the designers used a joystick handle to be able to use them instead of buttons. So, yes, the internal joystick can be interpreted as other keys, keyboard matrix contains them. For the _external_ joysticks, the situation is different, they are handled differently, as you mentioned with the $b6 port, they are not part of the keyboard matrix. That also mean that a software want to use internal _and_ external joystick they must use separated routine for that purposes.

Ok, is there any documentation on what is returned from a port read of $b6?  The only doc I've found so far is this:

http://gafz.enterpriseforever.com/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch3.html#3.7
which is using the EXOS keyboard driver to read the joystick.  The bits are obviously moved because when you read the internal joystick those bits do not correspond to the keys read from $b5.

Quote
But btw the keyboard matrix: do you plan to use your own keyboard scanning routine instead of EXOS' one? Well, it can cause some problems at least since there is eg UK and BRD (and HUN) layouts defined in software, and layout can be changed. Also, there were some projects to interface with an external keyboard without the hardware level compatibility (though to be honest, it can cause problems with many EP software as well, since many of them doing direct hw access), and only on software level the compatibility is provided. I'm really unsure here what can be the best solution, in some situation there can be a significant overhead to allow EXOS interrupt, keyboard scan, than doing EXOS calls to check keyboard etc ...

Yes, here's the untested and first pass at the code:

Code: [Select]
; ===============================================================
; Aug 2015
; ===============================================================
;
; int in_inkey(void)
;
; Read instantaneous state of the keyboard and return ascii code
; if only one key is pressed.
;
; ===============================================================

SECTION code_input

PUBLIC asm_in_inkey

EXTERN in_key_translation_table, error_znc, error_zc

asm_in_inkey:

   ; exit : if one key is pressed
   ;
   ;           hl = ascii code
   ;           carry reset
   ;
   ;         if no keys are pressed
   ;
   ;            hl = 0
   ;            carry reset
   ;
   ;         if more than one key is pressed
   ;
   ;            hl = 0
   ;            carry set
   ;
   ; uses : af, bc, de, hl

   ;EP keyboard matrix:
   ;        b7    b6    b5    b4    b3    b2    b1    b0
   ;Row    80H   40H   20H   10H   08H   04H   02H   01H
   ; 0   L.SH.     Z     X     V     C     B     \     N
   ; 1    CTRL     A     S     F     D     G  LOCK     H
   ; 2     TAB     W     E     T     R     Y     Q     U
   ; 3     ESC     2     3     5     4     6     1     7
   ; 4      F1    F2    F7    F5    F6    F3    F8    F4
   ; 5         ERASE     ^     0     -     9           8
   ; 6             ]     :     L     ;     K           J
   ; 7     ALT ENTER   LEFT  HOLD   UP   RIGHT DOWN  STOP
   ; 8     INS SPACE R.SH.     .     /     ,   DEL     M
   ; 9                   [     P     @     0           I
 
   ld bc,$09b5
   ld d,$ff
   ld hl,shift_table + 9

hit_loop:

   out (c),b                   ; select key row
   in a,(c)                    ; read key state active low
  
   or (hl)                     ; ignore shift keys in this row
   dec hl
  
   cp d
   jr nz, key_hit_0            ; if at least one key pressed in row
  
   dec b
   jp p, hit_loop              ; repeat for rows 9 to 0
  
   jp error_znc                ; if no keys pressed

key_hit_0:

   ; at least one key row is active

   ;  a = active low key result
   ;  b = row containing key press
   ;  c = $b5
   ;  d = $ff
   ; hl = shift table address corresponding to key press - 1

   ; find bit position corresponding to key press

   ld e,d

bit_loop:

   inc e
   rrca
   jr c, bit_loop
  
   cp $7f
   jp nz, error_zc             ; if multiple keys pressed

   ; make sure no other rows are active
  
   ;  e = key bit position 0-7
   ;  b = row containing key press
   ;  c = $b5
   ;  d = $ff
   ; hl = shift table address corresponding to key press - 1
  
   ld h,l
   push hl
  
miss_loop:

   dec b
   jp m, key_hit_1             ; if done checking other key rows
  
   out (c),b                   ; select key row
   in a,(c)                    ; read key state active low
  
   or (hl)                     ; ignore shift keys in this row
   dec hl
  
   cp d
   jr z, miss_loop             ; if no keys pressed in row
  
   jp error_zc - 1             ; if multiple keys pressed

key_hit_1:

   ; exactly one key is pressed
  
   ;     c = $b5
   ;     e = key bit position 0-7
   ;     d = $ff
   ; stack = LSB shift table address corresponding to key press - 1

   pop af                      ; a = LSB of shift table address for key press
  
   inc a
   sub shift_table & 0xff
   add a,a
   add a,a
   add a,a                     ; row offset into table in bytes
  
   add a,e                     ; add key bit offset into table
  
   ld e,a
   inc d                       ; de = key offset into table
  
   ; check for shift modifiers

   ; de = key offset into table 0-79
   ; hl = & key translation table
  
check_LSHIFT:

   xor a
   out ($b5),a                 ; select row 0

   in a,($b5)
   and $80                     ; LSHIFT
  
   ld hl,in_key_translation_table + 80  
   jr z, ascii                 ; if pressed

check_RSHIFT:

   ld a,8
   out ($b5),a                 ; select row 8
  
   in a,($b5)
   and $20                     ; RSHIFT
   jr z, ascii                 ; if pressed

check_CTRL:

   ld a,1
   out ($b5),a                 ; select row 1
  
   in a,($b5)
   and $80                     ; CTRL
  
   ld hl,in_key_translation_table + 160
   jr z, ascii                 ; if pressed

check_ALT:

   ld a,7
   out ($b5),a                 ; select row 7
  
   in a,($b5)
   and $80                     ; ALT
  
   ld hl,in_key_translation_table + 240
   jr z, ascii                 ; if pressed
  
   ; no shift modifiers
  
   ld hl,in_key_translation_table

ascii:

   add hl,de
  
   ld l,(hl)
   ld h,0
  
   ret

shift_table:

   defb $80 ; row 0 ignore LSHIFT
   defb $80 ; row 1 ignore CTRL
   defb $00 ; row 2
   defb $00 ; row 3
   defb $00 ; row 4
   defb $80 ; row 5 ignore unconnected
   defb $80 ; row 6 ignore unconnected
   defb $80 ; row 7 ignore ALT
   defb $20 ; row 8 ignore RSHIFT
   defb $c2 ; row 9 ignore unconnected

in_inkey() returns the ascii char corresponding to exactly one key pressed.  It processes SHIFT, CTRL and ALT and looks up ascii codes in a 320-byte table.  I didn't quite like the size of that but it can be looked at again later.  This subroutine would be used by the terminals to read input.  Related code generates a 16-bit scancode corresponding to an ascii keypress and another subroutine takes this scancode to see if the key is pressed.  This gives very fast keyboard scanning in games, eg.

We can accommodate different language keyboards easily by specifying a keyboard type in the config file and just choosing a different ascii table depending on the keyboard type.

Quote
Btw, Dave supports 6 bit D/A too. And "of course" it has got oscillators with some modulation/distortion/etc settings which are more like digital implementation (unlike with C64 SID, where there are analogue filters for example). Dave is stereo btw.

EXOS here is quite elegant btw, it again uses the channel notion, so you can open a channel (with "file name" of SOUND:). You can write quite "complex" sound definition "control codes" there, and EXOS within the EXOS interrupt will "play it" in the "background". Or something like that, honestly I have never used these ...

Yes I don't want to take away from that - I'm just looking for a way to bring what is in the z88dk library now to the EP.  The D/A can probably give volume-controlled 1-bit sound effects and music.

Quote
But in general, you can see how advanced EXOS is  I was really surprised that a "8 bit micro" uses an OS like EXOS (biut . I don't want to say that you "must" use EXOS for SOUND at any price, just I mentioned it here for the completeness.

Yes it is - that's why I'm sort of staggering around to figure out the best way to do this   I'm sure the best way will evolve over time.

Quote
And feel free to write me "you're too much with those novels", I know I can write just too much  Hopefully my long posts are not only for enlarge the database of the forum

I don't mind.. the more info the better.   Once I have something preliminary ready I'm sure it will be easier to point out how to improve things.
[/code][/code]
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.24. 11:50:06
Quote
The user-level documentation I found on EXDOS mentioned that a disk channel was automatically closed after a read or write operation, so it seemed like EXDOS would not be able to support streamed i/o.  I was reading user-level documentation which was concerned with loadng and saving entire files rather than random access so it could be I was unlucky to look at the wrong place.

I'm not sure what you mean here, where did you find this information and in what kind of context?

Quote
Would something like this be able to be efficiently implemented using just EXDOS?

Code: [Select]
while ((c = fgetc(in)) != EOF)
   fputc(process(c), out);

For this kind of common code to be efficient, the implementation has to cache several disk sectors in memory so that individual reads and writes go to memory rather than disk.  Most z80 disk implementations have been as simple as possible and perform very badly under C without assistance which is why z88dk is trying to supply disk i.o in a layered manner so that these simple systems can sit on top of a caching mechanism.

Well, that  code is not so nice anyway, since you need to issue "system calls" (or whatever we want to name them) all the time character by character, even on a modern OS on decent hardware it will be much slower than doing more bytes on the I/O by your code already. Just to mention that I had to write a log analyzer/"converter" software in C on UNIX and it was much slower using the scheme above. Anyway, that's true that still some may want to try to optimize these somewhat at least on the compiler/OS level.

Regarding your question about the implementation of this in EXDOS. Really, EXDOS is "only" an EXOS_ROM extension for EXOS. Thus, for "generic" file I/O you still use EXOS function calls (like open channel, read channel, check channel status), whatever the file is located on a disk or eg on tape. It's another question that internally, EXDOS will get the request by EXOS if it should be handled. But you even don't need to know there is something like "EXDOS" in the system for basic file I/O, those are just files, and open channels like any other similar entities (or even devices, just think about DISPLAY: or SOUND: ...). However, if you need something "special" over the "generic file I/O", like change directory, create directory whatever, that's not handled by EXOS, and then you need to "talk" with EXDOS then, since it's implementation specific and not generic (eg no "directory" notion of SOUND: device, or on the tape ...). But please note, that's more like my feelings about the structure of EXOS/EXDOS than "official specification" :)

In my opinion the code above can be done with opening two (file) channels with EXOS one for reading and one for writing. The "read character from channel" EXOS call (function 5) can be used to read a character, and "write character to channel" EXOS call (function 7) to write, to replace fgetc() and fputc(). What I am not sure about: the EOF check. According to the specification of the EXOS calls (see the URL later), "read character from channel" call will wait till a character is available for reading. Well, that's a reasonable thing with eg keyboard channel open, but with file, I don't know what happens if you hit the end of the file. Anyway, there is an EXOS call to check the channel status too: function 9, which can also return with the "end-of-file" state for you (if function 5 won't return with 0 read characters in case of EOF, that must be checked, or some other guy should tell the truth here who is more familiar with the EXOS internals than me). EXDOS internally has buffers, so what I can guess that it won't access the disk all the time if you read byte by byte only. However of course there is a price that you issue an EXOS call byte by byte still, but as I mentioned it's even problem on a decent OS running on modern hardware ...

Again, in this simple example it's not important at all that the file open (and then read, written, whatever) refers for a file in the "realm" of the EXDOS, or not, it's handled by EXOS, and it will talk with EXDOS if needed (however if you really want you can use EXDOS directly anyway even for generic file I/O only ...).

About EXOS calls:

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/kernel/Ch11.html

To be honest, I feel a problem (I mean to use EXOS) with this though. If you read the page at the URL above, you will find that file names can be used to open channels can be maximum of 28 bytes long. It does not feel a problem too much, as with FAT (no VFAT whatever) the 8+3 file name length seems to be OK. But consider the situation that you want to open a file "deeply" in a directory structure like A:\LONGDIR.1\LONGDIR.2\.....\FINAL.TXT so the file name (with full path I mean, what you pass to the EXOS open channel function) can be longer than 28 characters then, which is a no-no then. If I remember correctly I've already asked this on this forum, and the response was something similar that: "it's not so common to use absolute long paths on the EP anyway, just change directory first and access files there without the path information then".

EXOS "channel" operations btw is more like (in my opinion) open() read() etc calls common in C language with "int" typed file descriptors (fd) with the major difference that with EXOS, you must specify a channel number you want even at open(), while open() would "choose" an fd for you (the lowest unused one). It's somewhat also similar that in case of UNIX you can use C code like open("/dev/...", ...) to open a device instead of a "real file" (or maybe CON, PRN in case of DOS-style stuffs?) just that on EXOS would be something like KEYBOARD: and DISPLAY: names.

Quote
We don't replace the underlying system, only add to it.  So eg, a cpm system can still do file i/o by calling the bdos directly but the c standard i/o is also available to use.

By the way CP/M, EP also has a CP/M compatibility system, named "IS-DOS". It's an interesting stuff (though I've never used too much), in theory it supports even MSX-DOS stuffs (??), and beyond the CP/M (not v3 ...) the disk filling system in the background is still EXDOS, so unlike "original" CP/M systems (using their own file systems, often not even compatible with each other) IS-DOS - with the help of EXDOS - uses FAT12. So IS-DOS is not an "official" CP/M version from Digital Research with only a CBIOS created for the EP keeping BDOS (as far as I know!) but a system developed for the EP with the goal to be compatible with CP/M though (again, as far as I know).

Quote
Ok, is there any documentation on what is returned from a port read of $b6?  The only doc I've found so far is this:

http://gafz.enterpriseforever.com/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch3.html#3.7
which is using the EXOS keyboard driver to read the joystick.  The bits are obviously moved because when you read the internal joystick those bits do not correspond to the keys read from $b5.

Reading the external joysticks also uses the $B5 port (like the keyboard) to select what you want to scan, but after the selection is made, you must read port $B6 (unlike the keyboard, where you can read the state on $B5), and bit 0 will carry the state of the selected line. The "selection" itself (numbers are the values written to $B5), and if I recall correctly: 0 = fire, 1 = up, 2 = down, 3 = left, 4 = right, for external joy-1, and for kbd sel 5-9 the same series of assignments for external joy-2. Or something similar. I've never tried to use external joystick(s) in my programs though ... The interesting point here that other machines usually have the joystick as some kind of inputs and you can read a byte, with bits assigned to the fire and direction. On the EP however, as you can see, you must "scan" the joystick somewhat similar as with the keyboard. Maybe you can use a common routine to scan kbd and joystick (and save some CPU cycles?) that you write 0 to $B5, read $B5 to get the state of keys in kbd matrix row #0, and also read $B6 and check bit 0 of the result for joy-1 fire. Then write 1 to $B5, read $B5 to get the state of keys in kbd matrix row #1, but also read $B6 then and check bit 0 of the result for joy-1 direction "up". And so on. Thus you can save to "walk" on 0...9 writes to $B5 twice then (one run is for the kbd, one is for joysticks). As far as I know, for real not only bit 0 can be used (from value read on port $B6) but maybe bits 1, 2 too, thus you can in theory connect "tons of" joysticks to the EP128 with many lines, extra buttons, etc. I am really not sure on this though. I guess, mostly used (though I have no external joysticks at all) "official" (??) solutions uses only bit 0, hopefully on the way I've described above (or maybe not, hmm).

By the way:

https://enterpriseforever.com/hardver/dave/msg27102/#msg27102

Unfortunately, it's in Hungarian, so I am not sure how useful it is for you (and what result you'll get with google translator or something like that). But here it is:

https://translate.google.com/translate?sl=hu&tl=en&js=y&prev=_t&hl=hu&ie=UTF-8&u=https%3A%2F%2Fenterpriseforever.com%2Fhardver%2Fdave%2Fmsg27102%2F%23msg27102&edit-text=

Joysticks - again - are something I am not so experienced with ...

Another interesting thing, that mouse also works like this (well, the "official" EP mouse is said to be "terrible" - I don't know it personally - so I talk about the "common" solution instead, often named as "boxsoft mouse". It also uses control port lines to read mouse data (originally an MSX-mouse like protocol serialized to one bit transfer with a "shift" signal produced on a line on the serial port .... or something like that). It has some problem though that there is a conflict between external joystick and a mouse then. There is an on-going project (also can be found on the forum) to create a hardware solution for more modern (PS/2?) mouses with some modification to avoid the mentioned conflict.


Quote
Yes it is - that's why I'm sort of staggering around to figure out the best way to do this   I'm sure the best way will evolve over time.

Quote
I don't mind.. the more info the better.   Once I have something preliminary ready I'm sure it will be easier to point out how to improve things.

Indeed.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.24. 18:34:48
I'm not sure what you mean here, where did you find this information and in what kind of context?

I was glancing through http://ep.homeserver.hu/Dokumentacio/Konyvek/EXDOS/EXDOSeng.htm but I can see now it is mentioned that the disk channel is only opened and closed if you're loading / saving without first opening a channel.  There's no mention of seeking or random access of files.  It's just a simple reference for basic so there isn't a lot of meaty information there.  I found a reference to ISDOS on the same site (in Hungarian) which seems to have a lot more information and makes it look like ISDOS has a lot in common with cpm.  But of course ISDOS is an extension / replacement of EXDOS.

Code: [Select]
while ((c = fgetc(in)) != EOF)
   fputc(process(c), out);

Quote
Well, that  code is not so nice anyway, since you need to issue "system calls" (or whatever we want to name them) all the time character by character, even on a modern OS on decent hardware it will be much slower than doing more bytes on the I/O by your code already. Just to mention that I had to write a log analyzer/"converter" software in C on UNIX and it was much slower using the scheme above. Anyway, that's true that still some may want to try to optimize these somewhat at least on the compiler/OS level.

There are a lot of programs out there doing things this way because sometimes the top performance is not the main concern.  On modern OSes buffering is done at the FILE* level so that the c library is maintaining a 256/512/..4k block of memory for each open FILE so that i/o goes to this user-level buffer and only spills to the OS when the buffer is exhausted.  That way the very slow OS calls are avoided and are traded for a small (on big machines!) memory penalty.  That memory penalty is too high in a 64k memory space so z88dk has changed things somewhat by giving the responsibility to the driver to manage buffers for all storage access.  This way it's not one buffer per open FILE, it's a small number of buffers shared by all storage devices.  But the device driver has to be able to manage such a cache and if it can't z88dk is supposed to supply that code and disk devices will sit on top of that.  So the question is does EXDOS on its own manage such a buffer so that disk thrashing is avoided (read one byte from one file, write one byte to another -- does that mean entire sectors are read and written to access that one byte?)

Note that fuzix, an 8-bit project to bring a unix-like OS to the z80/6809/6502 is doing things like a modern machine as described above and is currently impractical on a 64k machine partly because of this.

In the sample program above the performance issue is very clear but a little more hidden is the exact same issue when using scanf for files:

Code: [Select]
fscanf(in, " %*[A-Z] %d %f", &i, &num);

This just an illustrative example and isn't really a meaningful program fragment.

The first specifier "%*[A-Z]" is supposed to throw away any group of chars from the stream in the set [A-Z].  Then it's supposed to skip whitespace, read an integer, skip whitespace and read a float.

To do any of those specifiers, the c library itself must read one char at a time from the file and decide whether to accept it or not.  That's not any different from the fgetc() case.

People who are concerned with performance normally do this in a line-oriented manner:

Code: [Select]
getline(&line, &len, in);
sscanf(line, " %*[A-Z] %d %f", &i, &num);

But getline() must *still* read chars one at a time because it needs to identify the end of the line on the stream.  So the improvement is only marginal.  (This is a much better way to do things for a different reason:  error handling and having the file pointer at a known position).

Anyway the unique thing that z88dk does is it pushes a state machine to the driver so that the driver is able to determine what is accepted by stdio as it reads chars from the device/cache.

Quote
In my opinion the code above can be done with opening two (file) channels with EXOS one for reading and one for writing. The "read character from channel" EXOS call (function 5) can be used to read a character, and "write character to channel" EXOS call (function 7) to write, to replace fgetc() and fputc(). What I am not sure about: the EOF check.

If EXOS can do it, it's no problem to do it that way.  EOF is one thing but also C allows files to be opened for updating.  That means there are two file pointers in a single file:  one where the reads are coming from and one used to append to the end of a file.  I'm not aware of any z80 disk system that is able to handle this well since it requires the system to maintain two buffers for a single file in order to avoid thrashing.  But if it's a problem, open for update can be disallowed too.

Quote
seems to be OK. But consider the situation that you want to open a file "deeply" in a directory structure like A:\LONGDIR.1\LONGDIR.2\.....\FINAL.TXT so the file name (with full path I mean, what you pass to the EXOS open channel function) can be longer than 28 characters then, which is a no-no then. If I remember correctly I've already asked this on this forum, and the response was something similar that: "it's not so common to use absolute long paths on the EP anyway, just change directory first and access files there without the path information then".

Another way to solve is to traverse the path in a loop and only change one directory at a time.  So it should be ok.

Quote
Reading the external joysticks also uses the $B5 port (like the keyboard) to select what you want to scan, but after the selection is made, you must read port $B6 (unlike the keyboard, where you can read the state on $B5), and bit 0 will carry the state of the selected line. The "selection" itself (numbers are the values written to $B5), and if I recall correctly: 0 = fire, 1 = up, 2 = down, 3 = left, 4 = right, for external joy-1, and for kbd sel 5-9 the same series of assignments for external joy-2. Or something similar.

Thanks I also found a reference through the links you gave and it gives all the info needed:
http://enterprise.iko.hu/technical/Converting_Spectrum_programs.pdf

Joystick scanning is separated from key scanning so that it can be faster.  Admittedly in this case the EP needs to scan all rows anyway but the logic to make sure only one key is pressed and applying shifts can be skipped.

Quote
Another interesting thing, that mouse also works like this (well, the "official" EP mouse is said to be "terrible" - I don't know it personally -

Ok, it's probably a joystick mouse or a mouse that needs to be polled constantly in a loop.  Yeah they aren't too useful.

Quote
so I talk about the "common" solution instead, often named as "boxsoft mouse". It also uses control port lines to read mouse data (originally an MSX-mouse like protocol serialized to one bit transfer with a "shift" signal produced on a line on the serial port .... or something like that). It has some problem though that there is a conflict between external joystick and a mouse then. There is an on-going project (also can be found on the forum) to create a hardware solution for more modern (PS/2?) mouses with some modification to avoid the mentioned conflict.

Ok if I can find something I can add it too.


Another question about the keyboard:  is there a list of standard ascii codes for keypresses returned by the EP firmware somewhere?  I'm not sure what to do about returning ascii codes for ALT keys and some special keys.  I realize the function keys are macros on the EP but in the c lib it's lower level so there is no macro expansion and key codes would have to be returned.
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.24. 19:35:31
Hello. About the mouse I think is better to wait the first batch of Entermices to reach their new owners, but the mouse reading routine can be like this:


      ld   a, (INPUT_DEVICE) ; EXOS Variable 189
      cp   1
      jp   z, loc_C28F
      cp   2
      jp   z, loc_C294
;modification here
      cp   5
      jp   z, loc_C285    ; Serial Mouse Systems is merged with the internal Joystick
      cp   6
      jp   z, loc_C285      ; Serial Mouse Systems WILL be merged with the internal Joystick
;end
      or   a
      jp   z, loc_C285
;Modification here
      ;Here begin the   Neos mouse reading
      ld   hl, X_REL   ; first   byte
      ld   a, 2      ; RTS low
      out   (0B7h),   a
      ld   b, 8      ; long delay
      call   WAIT
      call   READ_4BIT   ; read four higher bits
      rld         ; push them in (HL)
      xor   a      ; RTS high
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four lower bits
      rld         ; push them in (HL)
      ld   hl, Y_REL   ; second byte
      ld   a, 2      ; RTS low
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four higher bits
      rld         ; push them in (HL)
      xor   a      ; RTS high
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four lower bits
      rld         ; push them in (HL)
                      ;<======Here will be added the future Wheel and three spare buttons reading. FIRST TENTATIVE
      ld   hl, SW_Z_STATUS
      ld   a, 2      ; RTS low
      out   (0B7h),   a
      ld   b, 5      ; short delay
      call   WAIT
      call   READ_4BIT   ; read four higher bits
      and 15
      cp 1         ; IF THIS NIBBLE=0001 THEN THE MOUSE IS IN EXTENDED PROTOCOL
      jr z, CONTINUE_READ
      xor   a      ; RTS high
      out   (0B7h),   a           ;IGNORE THAT NIBBLE
                             ld (hl), 0. ; we don't need old values
      jr STOP_READ
      
CONTINUE_READ:
      xor   a      ; RTS high
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four higher bits, the three lower bits are the buttons. They come ready to store
      push af      ; push them in stack. they are in the lower nibble.
      ld a, (hl);
                             push af   ;save the Z counter for later.
      ld   a, 2      ; RTS low
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four bits
      rld         ;we need z displacement in 8 bit
      xor   a      ; RTS high
      out   (0B7h),   a
      ld   b, 5      ; short   delay
      call   WAIT
      call   READ_4BIT   ; read four lower bits. Z displacement
      rld         ; push them in (HL)   ;NOW WE HAVE Z displacement in (hl)
      pop af         ; restored Z counter to "a", but we have garbage on high nibble   
                             and 00Fh
                             bit 3, a
                             jr z, SIGN_DONE
                             or 0F0h
 SIGN_DONE:                                               ; now we have the sign extended to 8 bits on "a"
                             add a, (hl)
                            cp 128                              ;positive or negative?
                             jr c, POSITIVE
                             cp 248                             ;lower than -8?
                              jr nc, FINISHED             ;
                              ld a, 248                          ; -8 is the bottom
                              jr FINISHED
POSITIVE:
                              cp 8                                 ;higer than 7?
                              jr c, FINISHED
                              ld a, 7                             ; 7 is the top
FINISHED:                                                  ; the excess  of 7 or -8 has been wipped
                              ld c, a                            ;save Z addition on c
                              pop af                            ; retrieve the buttons status. They are now on first nibble of a
                              rld                                  ;buttons stored
                              ld a, c                           ;we only need the first nibble of Z counter addition
                              rld                                 ; the spare buttons status and the Z counter are now in SW_Z_STATUS
STOP_READ:
      xor   a                       ;recall buttons on row 0
      out   (0B5h),   a
      in   a, (0B6h)   ; read Mouse buttons
      and 7      ;mask
      xor 7      ;flip them all as on Enterprise a pressed key is 1 and released 0
      rl (hl)    ;Get ready the bit 7 of "hl" register pair. Inside is SW_Z_STATUS, variable number 190
      srl a   ; This is the very FIRST "srl a". The button status is now in the carry flag
            ; secondary button of Boxsoft is read on J column. Primary button of Entermice is read on K column
      push af
      ld   a, (INPUT_DEVICE)
      cp 3   ;Boxsoft interface mode buttons   
      jr nz, L_BUTTON     
      pop af  ; We need the value of "a" and "f" registers. Carry flag still stores the value of secondary button
      rr (hl) ;secondary button goes to bit 7 of SW_Z_STATUS, variable number 190
      srl a   ; Primary button of Boxsoft is on J column. This is the second "srl a"
      JR MAIN_BUTTON
L_BUTTON:   ;Entermice interface mode buttons
      pop af  ;retrieve the value of register "a". "f" is disposable, soon we will load the button on carry flag
      push af ; I still will need later the register "a" value
      srl a  ; two "srl a" because the secondary button of Entermice is read on L column
      srl a  ; the proper button status is now in the carry flag
      rr (hl) ;secondary button goes to bit 7 of SW_Z_STATUS, variable number 190
      pop af  ;retrieve the value of register "a" just after the FIRST "srl a"
MAIN_BUTTON:
      and 1
      ld   (FIRE_STATUS), a ; EXOS   Variable 188. K column if Boxsoft or L column if Entermice
      call   sub_C3A6   ; this is the "corrections and drawing" routine where the "velocity" 1.1 modification was made
      ld   a, (X_REL)
      ld   c, a
      ld   a, (Y_REL)
      or   c
      ret
   ;end   



;-------------------------------------
WAIT:               
      nop
      nop
      nop
      dec   b
      jr   nz, WAIT
      ret
      ;end
;-----------------------------------------


READ_4BIT:            
      ld   b, 4
      ld   d, 0
      ld a, (INPUT_DEVICE)
      cp 3
      jr z, L_COLUMN
      
K_COLUMN:            
      ld   a, b
      ;inc   c ;    this is not necessary
      out   (0B5h),   a
      in   a, (0B6h)
      ld c, a
      rra         ;data read from K column
      rra
      rl   d
      djnz   K_COLUMN
      jr CONTINUE

L_COLUMN:            
      ld   a, b
      ;inc   c ;    this is not necessary
      out   (0B5h),   a
      in   a, (0B6h)
      ld c, a
      rra         ;data read from L column
      rl   d
      djnz   L_COLUMN

CONTINUE:
      ld   a, d
      ret
;end



----------------------------

Ovserve, the old mouse type is INPUT_DEVICE=3. The new standard is INPUT_DEVICE=4.

I'm already working in this routine and some aspects need to be tested on a real Enterprise.

Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.24. 19:49:43
X_REL               x axis displacement since last reading, 8 bits signed
Y_REL.              Y axis displavement since last reading, 8 bits signed
FIRE_STATUS.  main mouse button
SW_Z_STATUS  high nibble: bit 7 = secondary mouse button, bits 4, 5 and 6 spare buttons
                           Low nibble Z displacement counter, 4 bits signed
                                 
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.24. 20:30:54
The mouse is read every 50 Hz  by interrupts.

The reading of the mouse is triggered by putting RTS low for  a long pause. Then the mouse sends the first nibble.
RTS is put high for a short pause and the mouse sends the second nibble.
RTS is put low for a short pause and the mouse sends the third nibble.

And so on. Two nibbles make a byte. Two bytes are read if we have a legacy mouse, but upto four if in extended mode.
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.24. 20:38:00
The control ports of the Enterprise are only for reading keypresses, for inputs, so it is needed an output signal in order to comunicate with the mouse.

The solution is to use the RTS pin signal from the underused serial port.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.25. 18:06:19
Thanks gflorez I can see how it works.

The boxsoft mouse replaces one of the external joysticks and the entermouse communicates on a different bit.

I'm not sure what this does:

Code: [Select]
      call   sub_C3A6   ; this is the "corrections and drawing" routine where the "velocity" 1.1 modification was made

Are you compensating for low precision legacy mice?


Code: [Select]
      ld   a, 2      ; RTS low
      out   (0B7h),   a
      ld   b, 8      ; long delay
      call   WAIT
      call   READ_4BIT   ; read four higher bits

I assume this first long delay resets the mouse logic so if the subroutine does not read all nibbles for whatever reason, this will make the mouse start again at the first nibble?

Are these delays specified precisely in seconds or z80 clock cycles?  I saw mention in other threads of faster z80 substitutions so if it's measured in seconds I think it's best to compute a cycle delay depending on the cpu clock rate.  There is a config option in the compiler that sets the target's clock rate for situations like this.

If you're unaware of them, there are z80 subroutines around that can busy-wait a precise number of z80 clock cycles.  This is one of them by Jan Bobrowski:

http://z88dk.cvs.sourceforge.net/viewvc/z88dk/z88dk/libsrc/_DEVELOPMENT/z80/z80/asm_z80_delay_tstate.asm?revision=1.4&content-type=text%2Fplain

You use it like this:

Code: [Select]
ld hl,500  ; at least 141
call asm_z80_delay_tstate
; here exactly 500 cycles have passed assuming no 'clock stretching'
Title: Re: Enterprise C compiler for PC
Post by: pear on 2015.August.25. 18:23:28
Maybe timings (https://enterpriseforever.com/hardware/entermice-joy-ps2-mouse-interface/msg47772/#msg47772) will help you understand more.
The mouse is polled after each interruption of video (IRQ 50Hz) (answer later in the same thread (https://enterpriseforever.com/hardware/entermice-joy-ps2-mouse-interface/msg47806/#msg47806)).
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.25. 20:49:16
What I've shown you above  are modifications done to an old driver from the 80's. It was part of a third party product named Boxsoft mouse interface bundled as a paint program. The creator assured here in this page that he only sold about 100 units.

It consisted on an adapter that implemented a standard d9 joystick port on the Enterprise, a Neos mouse, the Paintbox program and the driver itstelf.

It worked like a conventional modern mouse, but lacked velocity(acceleration). In the last modification made by the author he introduced a fix that doubled the amount of movement when greater than 1 or -1 pixels.

That  "corrections and drawing" call is not important for you as you will draw the pointer with your own routines, I think.

But now the interface has evolved to avoid some incompatibilities with programs that expect a joystick on that port.

Now  the mouse status is read on some undocumented possible switchs on the same controller port.

Also, it has been discovered that the Neos mouse is in reality a modified Msx mouse. So a Msx to ps2 mouse converter has been added to the interface. The name of the interface evolution is Entermice.

Meanwhile Prodatron, the creator of the superb multiplatform operative system named SymbOs, has made a port for the Enterprise. One of the target platforms is Msx and he has expanded its mouse protocol to manage ps2 mice(by Msx to ps2 adapter) with up to 5 buttons and wheel. He can apply easily that mouse protocol expansion also to the Enterprise port if there is already a hardware supporting it.

I have to say that ps2 mice have certain velocity in its circuits, so the feel now is almost exactly as a modern mouse.


All that improvements are included in that little routine....


Abut the timming of the delays.... They don't need to be accurate. Only the first delay is important. Then the mouse or the converter watch for all the readings done in a fixed total time.
Title: Re: Enterprise C compiler for PC
Post by: lgb on 2015.August.26. 00:19:39
I was glancing through http://ep.homeserver.hu/Dokumentacio/Konyvek/EXDOS/EXDOSeng.htm but I can see now it is mentioned that the disk channel is only opened and closed if you're loading / saving without first opening a channel.  There's no mention of seeking or random access of files.  It's just a simple reference for basic so there isn't a lot of meaty information there.  I found a reference to ISDOS on the same site (in Hungarian) which seems to have a lot more information and makes it look like ISDOS has a lot in common with cpm.  But of course ISDOS is an extension / replacement of EXDOS.

IS-DOS is written by IS (Intelligent Software) to be compatible with CP/M, so it's a CP/M in some way, but not the from the original BDOS from DR. If I remember correctly, it's compatible with CP/M version 2.2 (at least if I remember correctly, I wrote a small CP/M program to get CP/M version and then print it, and it was 0x22). It does not replace EXDOS/EXOS, but it's another layer "built top on them". So some even name iS-DOS as "the CP/M for EP" too. This means several things, for example something I've already mentioned: it uses EXDOS, thus its native file system (FAT12) with all the directory etc stuff which was not possible with a "real" CP/M 2 (if I remember correctly) only maybe in later CP/M versions (?). Once I found the disassembled BDOS source is available (well, as far as I remember, know even "officially" available?), it was quite trivial try from me, to write a stupid and short CBIOS for EP, so of  course the "original" CP/M from DR can run on EP too, but still, IS-DOS is hard to beat, because you can also use the good things for EXDOS too with it (or even EXOS commands are available from IS-DOS too directly). Native CP/M BDOS implements some file system (I don't know it too much) which sounds a horror for me, eg almost as many exact formats (especially sector "skews" and similar things) exists as CP/M platforms :shock: I just "had to" mention these as you wrote "it looks like ISDOS has a lot common with cpm". Well, no wonder, because IS-DOS is "the CP/M" for EP with extra stuffs :) Though I am not so familiar with IS-DOS to tell, if there are major/minor compatibility issues compared with a DR CP/M BDOS system ... My personal opinion only: I think CP/M compatibility was a design concept for EP, even EXDOS has some notions (without IS-DOS too, in once) to be quite similar to CP/M maybe for easier IS-DOS CP/M implementation then. Again: if I remember correctly when once I tried to dig into EXDOS a bit :)

Quote
There's no mention of seeking or random access of files.

Hmm, maybe because some should use EXOS for that (opening, then reading/writing channel, set channel status call - which allows seeks etc). EXOS internally of course will use EXDOS if the channel refers for a file on a disk, and not some other entity, like a DISPLAY: channel (which is not so much seekable of course, for example).

About your C code examples, FILE* stuffs, etc: well, as far as I can see, my views on this topic are somewhat different. Your approach is about the correct ("C standard") implementation which of course is the better one. I usually have the habit to "ignore" this (well ...) since I often feel it gives too much complexity for a 8 bit system with limited resources. I must admit, my viewpoint is not so nice at all :) I should not comment these topics further, since it seems you are quite good in it already :)

Quote
Another question about the keyboard:  is there a list of standard ascii codes for keypresses returned by the EP firmware somewhere?  I'm not sure what to do about returning ascii codes for ALT keys and some special keys.  I realize the function keys are macros on the EP but in the c lib it's lower level so there is no macro expansion and key codes would have to be returned.

Maybe this can help?

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch2.html

About function keys: I am not sure about that, of course, they are just keys like others, just maybe EXOS "translates" the keypresses for the programmed string as 'faked keypresses' (or such) when a function key is pressed?

http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch3.html
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.27. 01:14:06
Yes, there are different CPU clocks, hardware modifications, not from stock, but the compensation for that variations  is planned to be made by the firmware MCU inside the adapter.

The entermice wil be a complex piece of hardware, firmware and software mix.
Title: Re: Enterprise C compiler for PC
Post by: Alcoholics Anonymous on 2015.August.27. 04:07:16
Thanks for the information on the mouse -- I think there is enough information there.  One thing I am wondering about is if the mouse ISR will always run on VBI interrupt?  Ie- you plug in the hardware and then its ROM plugs itself into the VBI interrupt at initialization.  The reason why I ask is under a C program you may want to take control of interrupts yourself, just as you might want to do in an assembly program.  I had anticipated that the clib would supply the driver software (this is how it's done for other machines) but if the mouse firmware runs at 50Hz, it's going to be reading and clearing the mouse state itself.  If that's going to be the case then there would have to be one mouse routine that reads the built-in driver's updated variables when interrupts are owned by the EP and another that reads the mouse hw directly when the interrupts are owned by the program.

About your C code examples, FILE* stuffs, etc: well, as far as I can see, my views on this topic are somewhat different. Your approach is about the correct ("C standard") implementation which of course is the better one. I usually have the habit to "ignore" this (well ...) since I often feel it gives too much complexity for a 8 bit system with limited resources. I must admit, my viewpoint is not so nice at all :) I should not comment these topics further, since it seems you are quite good in it already :)

Well I think people don't even try to do sophisticated things in z80 or at least the number of examples is small.  EXOS is one example :)  In z88dk I'm pretty confident we could fit an OS with standard C library, FAT filesystems and all that in under 24k.  There are no shortcuts being taken -- the parts of the C library that are implemented are complete.

Something like this which I used to test the error detection of strtol:

Code: [Select]
#include <stdlib.h>
#include <errno.h>

main()
{
   char *buf = 0;
   size_t sz;
  
   while (1)
   {
      printf("\n> ");
      
      fflush(stdin);
      getline(&buf, &sz, stdin);
      
      printf("= %ld\n", strtol(buf, 0, 10));

      perror(0);
      errno = 0;
   }
}

works as expected.  There's a lot of hidden complexity there, the most obvious are the steps taken to make printf efficiently communicate with the stream.  But getline() is another big one -- it needs to efficiently gather input from the stream up to a '\n' and not only that but dynamically grow a buffer to accommodate the line being read.  getline() here is actually built on a vector<char> within the z88dk lib and growth is via realloc().  realloc() is written to be very fast -- if the allocated memory must be moved, it is moved into the largest hole in the heap so another move will not occur.  If the buffer handed to getline is 0 (NULL), realloc will begin by allocating the largest available block in the heap.

So yeah, things like vector<char> are in the library and are exposed to the user as container types modelled on C++ STL.  This is all in z80 assembly language and it's all efficiently implemented.  We never lose sight of performance, which is really what you are concerned with I think so we do both non-standard and standard C things with the library.

Quote
Maybe this can help?
http://ep.homeserver.hu/Dokumentacio/Konyvek/EXOS_2.1_technikal_information/exos/keyboard/Ch2.html

I don't know how missed that :P
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.27. 09:22:23
Yes, you can load the mouse driver or not. It is not in Rom. It works as an extension to Exos:

https://enterpriseforever.com/programming/universal-mouse-driver/?action=dlattach;attach=13253

You can load it directly from Basic or Exos. Then to initialize it you must execute ":pb".

As you don't own a mouse interface you can try the internal joystick.

Once loaded the driver and initialized, this little Basic program will set the system for you and will open the required channels:

100 PROGRAM "mouse_test.bas"
110 GRAPHICS ! Usually the video channel is number £101:
120 SET 189,0 !  internal joystick as input device
130 SET 180,101 ! Video channel to put the mouse on. Only graphics.
140 SET 183,255 ! Colour of the pointer
150 OPEN £1:"mouse:" ! Opens a channel on the mouse device

Move the keyboard joystick to see the effect. Observe that the Basic program has ended.


Title: Re: Enterprise C compiler for PC
Post by: Zozosoft on 2015.August.27. 09:27:41
Yes, you can load the mouse driver or not. It is not in Rom.
Currently :-)
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.27. 10:14:35
Hello Zozo. How it can be done, allocating memory and placing there the "modifiable" memory section?
Title: Re: Enterprise C compiler for PC
Post by: gflorez on 2015.August.27. 10:21:17
The Serial mouse part has auto-modifiable code. It has to be rewritten to put it on Rom.

Sorry, this is off-topic here....