Yes.
> Or is it possible to use C I/O libraries?
I suppose it would be, if these were available for the target, but
it's not necessarily such a big deal to write the drivers in Forth.
Andrew.
Of course you need "drivers". But ... has it ever occurred to you
that you could write them yourself?
I publish a Forth for a single board 6809 on my site below.
It is intended to be coupled with a vt100 terminal (or a serial
pc).
This is how KEY ( the "driver" for getting a key) looks:
(most of it is header, and blending in with Forth.
All the code to get a key is the 4 lines marked with %. )
; ***********
; * KEY *
; ***********
;
N_KEY: FDB 3
FCC "KEY"
KEY: FDB PH_OFFSET-C_HOFFSET*CW+*
FDB PH_OFFSET-D_HOFFSET*CW+*
FDB $0
FDB -C_HOFFSET*CW+EMIT
FDB N_KEY
; Result in D
KEY1: LDA USART_STATUS ; % Get control status of the ACIA
BITA #$02 ; % Check if buffer is empty (=Z)
BEQ KEY1 ; % If so wait.
LDB USART_DATA ; % If not, get key
CLRA ; Make it a full cell
PSHU D
LDX ,Y++ ; NEXT
JMP [C_HOFFSET*CW,X]
To answer the questions:
No, you can't always use C, in this and many cases.
No, it isn't all that hard to write a driver, and it is not
much code at all.
But yes, you have to dive deep into the manuals.
To be fair, there is also some initialisation, but it also serves
for output, EMIT :
\ reset
USART_CMD C@ DROP
\ mode 1 : 1 stopbit. no parity, 8 databits, asynchronous 16X baudratefactor
$4E USART_MODE C!
\ set mode reg 2 : internal clock, 4800 Bd )
$7C USART_MODE C!
\ RTS high, reset error, no break, enable Rx, DTR high, enable Tx
$15 USART_CMD C!
You see that the initialisation is in Forth.
You can get this 6809 Forth with source from my site below.
You can get the single board computer that it runs on for free
from the Dutch Forth chapter.
On the site is also a booting Forth for the PC but it is not quite
satisfactory,
Groetjes Albert
--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst
There are bootable non-OS Forths out there. Booting seems to be the
hard part. Look up the standard BIOS calls to see what kind of
functionality you have access to. Much of your PC's hardware will be
inaccessible because it requires a Windows or Linux driver, but the
basics will be there.
-Brad
ForthOS is a good example of a PC based Forth that does not use an
underlying OS. It *is* the OS. Works with a hard disk and/or CD drive.
I ran it with no problems in a VMWare virtual machine straight from
the ISO image.
Mark
Brad- your description of trying to run anything on x86 appears
prohibitively complex as I imagined it would be. 20 years ago writing
your own drivers for x86 was not only feasible, but normal, but all
that has changed as you refer to the new city built on over an ancient
city.
Albert- thanks for your information. Ive tried to read some of the
well documented code for Jonesforth (the site for Jonesforth is no
longer up, luckily I saved the files for it) since I have a basic
understanding of x86 assembly. And Ive been wanting to try my hand at
embedded programming (with PIC or ARM) and it looks like your Forth
may be a good way to start at learning both embedded programming and
how to use a Forth at the same time. I will contact you.
Historically, FORTH was first implemented this way on bare-metal
microprocessors. You need to provide only two hardware-specific words
(KEY and EMIT) to get the complete core FORTH word set up and running.
See www.camelforth.com for some ANSI-compliant bare-metal
implementations on a number of different processors.
Yes.
> Or is it possible to use C I/O
> libraries?
In general, no. C libraries are dependent on a specific OS, but generally
they're minimally dependent. There are many C library functions that are
completely independent of the underlying OS, but I/O functions generally are
not. They use the OS' I/O functions. I.e., if the compiler is for Windows,
it'll call a Windows function. It the compiler is for Linux, it'll call a
Linux function. But, those functions won't be there, since this is for your
to-be-written OS. DOS was not much of an OS, so with DOS C libraries, you
may get away with using C functions, e.g., if the DOS C library uses direct
writes to screen instead of using 16-bit BIOS functions, or if it's a DOS C
compiler that produces 32-bit code, it may write to the screen directly
instead of going through a PM to RM switch, call BIOS, RM to PM return. If
it's a 16-bit OS on x86, the BIOS has setup the hardware for you. However,
for x86 for 32-bits or 64-bits without an OS, you're still going to need to
initialize quite a number of support chips, e.g., keyboard, mouse, PICs,
etc., manually, just like someone coding a hobby OS. You'll need to do all
the special stuff for getting the x86 into the correct cpu mode. You'll
need to make the Forth OS bootable, etc. And, you'll definately want to
code all that code in assembly, not Forth, as it uses many special x86
instructions.
Rod Pemberton
<snip>
> And, you'll definately want to
> code all that code in assembly, not Forth, as it uses many special x86
> instructions.
>
The Forth used may have an assembler, so there is no need to leave Forth to
use assembler code. One can use all Forth facilities generating assembler.
(Forth does not have a word called DEFINATIONS ;-)
--
Coos
CHForth, 16 bit DOS applications
http://home.hccnet.nl/j.j.haak/forth.html
FlashForth is a forth system written in assembly for PIC processors.
You can study it for how an embedded Forth system can be written.
It uses assembly coded drivers for the UART.
For I/O via USB serial interface emulation it uses library code
written in C.
The prompt is then available in any dumb serial terminal.
If dedicated HW for the keyboard and display is used, then new drivers
for KEY KEY? EMIT is needed.
FlashForth is working on Microchip PIC18F, PIC24 dsPIC30 and dsPIC33
series of PIC processors.
Its available for free at
http://flashforth.sourceforge.net/
Best Regards Mike
Mike- your implementation looks fantastic. I was thinking of learning
PIC programming using C, thinking I could avoid getting bogged down in
assembly details and get quicker results with a high level language by
using the book "Programming 32-bit Microcontrollers in C" by Lucio de
Jasio. But I think C programming becomes much more difficult on bare
metal without an OS managing the stack. But your forth implementation
looks like a perfect way to learn PIC programming, I may have to pick
up a PIC board and give that a try. Some of the tutorial resources on
your page look very good as well.
I'm not sure why. Certainly, if you write code like this:
void whatever(void) {
char temporaryBuffer[1024*1024];
doSomethingWith(temporaryBuffer);
}
Then yeah, you'll find "bare metal" programming in C to be difficult.
In other words, if you're in the habit of allocating large temporary
buffers and assorted other excessively-sized whatnot on the stack and
expecting an underlying OS to juggle memory for you, then you'll be in
for an unpleasant surprise. Doctor, it hurts when I do this... so
don't do it.
As for the difficulty of targeting such "bare metal" platforms in C, I
personally don't find it difficult at all. For me, it's because
thoughtful consideration of the underlying platform is fundamental to
writing code. You don't start from a position of pretending that the
abstractions and services offered on your desktop system with a big OS
and gobs of resources are available on your microcontroller. If you
do, then yes, everything is harder, but only because you're not
respecting the platform.
This is language independent and you see it in other contexts as
well. When Google decided that Java was going to be the primary
language for applications in Android, you saw Java developers
rejoice. And when those Java developers then wrote the same kind of
code they wrote for larger systems-- code that wasn't respectful of
the underlying platform-- they found their application footprints were
large, their code was slow, and people were complaining about
batteries being drained. The problem wasn't so much with the Dalvik
VM or the Linux OS. The problem was between the keyboard and the
chair of the developer.
This is of course true, but high level languages like C are sometimes
used as portable assembler. The same is true of Forth.
If you have the word PC! added to a Forth, you can play
"Mary had a little lamb" on the built-on speaker of your dos-pc.
This is in fact assembler programming, as you have to know
exactly how your hardware reacts to storing a number into a port
and where your speaker ports are. With memory mapped I/O
(all modern microcontrollers) you get by with C! and ! and need
not even an extension to your Forth.
>Coos
No, it's just plain C programming, usually without the C libraries. Most
good C programmers can rewrite much code to not use C library code, except
for <stdio.h>, i.e., I/O. So, much C code can be made almost library
independent with just a little bit of work. A C library may only be
dependent on 19 or so OS functions, as PJ Plauger did for his book or Redhat
did for newlib. On the other hand, it could be dependent on multiple
hundreds, like Linux. Also, many C library functions are implemented in an
OS independent manner due to simplicity or happenstance, e.g., character,
memory, and string functions. File I/O functions and functions that
secretly use I/O cannot be used, e.g., printf. Functions that allocate and
free memory are dependent on the OS' memory manager. You can use OS
independent functions, if needed.
For "bare metal" C programming in C, you have:
1) the language functionality of the C compiler, i.e., C language plus some
extra's...
2) any C library functions that are OS independent, if you chose to use the
host's libraries...
3) assembly, i.e., C doesn't support special x86 instructions, etc...
etc.
> But I think C programming becomes much more difficult on bare
> metal without an OS managing the stack.
>
The stack is handled by the C compiler. If you meant that memory allocation
(heap), like malloc() and free(), are unavailable, then yes that is true.
You'll have to use auto, static, file scope variables to "allocate" memory.
Or, you'll have to implement malloc() and free() using a memory allocator.
There are a few publicly available: Doug Lea's dlmalloc, John Walker's bget,
, Richard Harter's dynamic storage allocator.
Rod Pemberton
Actually, I have yet to use a "bare metal" C compiler (Avocet, IAR,
Keil, ImageCraft, MetroWerks, etc.) that targets microcontrollers
where the printf family of functions (and scanf family) wasn't
available. On such targets where there is no operating system, I/O
amounts to the Forth equivalent of EMIT and KEY. And just like on
many Forths, these are revectorable to user functions. One may not
want to use printf/scanf for other reasons (excessive generality, the
size of the format string interpreters, etc.), but the option is
there, and it doesn't depend on an underlying OS. And in fact, these
same compilers all offer ways to customize *which* printf a system
uses. You'll often have a version of printf/scanf that doesn't
support floats/doubles and often a version that doesn't support the
more exotic format specifiers.
The same is true for memory allocation functions. All of the same
"bare metal" C compilers offer the malloc family of functions, even
without an underlying OS. What you typically do is have a symbol that
is set between the end of allocated memory and stacks. Then, memory
allocation functions provided as part of the runtime library can give
the usual malloc-family semantics. And again, one may not want to use
the malloc-family of functions (fear of fragmentation in pathological
patterns of allocation, no need for dynamic allocation for most
embedded systems), but the option is (again) there.
> > But I think C programming becomes much more difficult on bare
> > metal without an OS managing the stack.
>
> The stack is handled by the C compiler. If you meant that
> memory allocation (heap), like malloc() and free(), are
> unavailable, then yes that is true.
The OP was probably thinking of stack-allocated memory. In most
modern operating systems, the stack's memory is managed by the
operating system and can be dynamically increased as needed. That
allows some C programmers to do things like allocate huge buffers on
the stack as automatics without (much) worry. It's never been a
recommended practice, but you still see plenty of code like that
today.
It should also be mentioned that on some platforms, the C stack isn't
a stack at all. Instead, the linker looks at the call graph of the
program and statically allocates memory based on function lifetimes.
So two functions which never call each other can have overlapping
statically-allocated memory. Such allocation schemes normally
disallow recursion and have to be told about run-time function
pointers in order to have a working program. But practically, these
limitations aren't huge. They can be surprising to C programmers who
expect that the stack is indeed a stack.
As far as dynamic memory allocation, as pointed out previously, that
*is* an option, but not one that most embedded programmers find is
often useful. comp.lang.forth has traditionally hasn't made much of a
distinction between C programmers who target desktop/server systems
and C programmers who target "bare metal" microcontrollers. This is
what leads to ridiculous assertions about embedded C programmers, such
as being dependent on an operating system on that target, despite the
fact there is none.