discussion of a Forth cross-compiler

Go To Last Post
128 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello --- I just signed up here --- I'm a complete newbie in regards to AVR assembly-language. The following questions may seem simple, but I couldn't find them in the documentation that came with Atmel Studio --- most likely I just haven't found adequate documentation yet, so some links might be the best response.

 

1.) I read that an ISR doesn't have the status-register (SREG) saved for it, and that this is the programmer's responsibility. How do I do that? On the 6502 we had the PHP and PLP instructions, but there seems to be nothing like this in the AVR. I assume that SREG is memory mapped somewhere (maybe all of the registers), similar to on the 8032. Is there a map of this stuff? I'm guessing that this is the lower 128 bytes, as I noticed that we have fast versions of LDS and STS for that region.

 

2.) How big is the stack? I found the PUSH and POP instructions, but there is no indication as to where the stack is or how big it is. Does this vary from chip to chip? I want to know if it is a good idea to push data here for temporary storage, or if this is likely to cause a stack overflow. Is it possible to store the return-stack pointer into Y or Z and access the data on the return-stack with indirect-with-displacement addressing? Pushing and popping upwards of 32 registers seems rather time-consuming --- is there no way to save the machine state more quickly?

 

I'm writing a Forth cross-compiler --- I want to be able to write ISRs in Forth, which is why I'm asking these questions about how ISRs work. Later on I may delve into writing an RTOS --- in any case, task-switching on the AVR seems to be pretty cumbersome, compared to the 6502 --- but maybe I just haven't found the correct documentation yet.

 

thanks in advance --- Hugh

 

When C is your only hammer, every problem looks like your thumb. 

Last Edited: Tue. Nov 25, 2014 - 07:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome. You've been programming for decades if you know about 6502s. I came to AVRs from 6800s and HC11s. There are some great projects here in the projects section, but you have to work to look at them. I'm sure I have seen a forth for avr. I ported fig forth 6800 to the 6800 based trainer hardware we had in the mid 70s.

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome!

 

The stack is part of SRAM and depending on the size of SRAM will dictate the size of the stack(minus any variables stored in the SRAM of course).  The stack begins at the end of SRAM and decrements.  You do not have to store the stack pointer yourself.  The AVR takes care of that for you.

 

You have to PUSH the SREG when you enter the ISR, and POP it upon leaving said ISR.  You do not have to PUSH and POP all the registers.

 

The datasheet for the particular AVR will give you a memory map of how things are laid out for that device. 

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SREG is mapped to both IO and memory space.  Typically you'd move it to a register, then you can either save the register to memory, or push it, or just not use it for anything else (thus preserving SREG in the register).  Look at the end of the datasheet for addresses.

 

The stack is located in SRAM memory, referenced by SP (SPH and SPL).  Typically SP is loaded with the top memory SRAM address at the beginning of the program.  Since the stack contents are just SRAM, you can access the contents in any way you can access SRAM.

 

You can divvy up the 32 registers any way you want, but you might want to look at the avr-gcc register useage for a guide.  It breaks down the registers into save-by-caller, save-by-callee, and not saved (an arbitrary choice, not dictated by hardware).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One other note about the 32 registers, some of the lower ones are used for math routines by the AVR so as a sort of general rule many of us stick with the upper 16.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

in addition to jims remark,

there are a number of instructions that only work on the top 16 registers. So again as you are new I would start with only using the top 16 registers and learn how the avr instruction set is operating. If you have that knowledge you will also know what instructions can use what range of the registers. on the atmel website there is a avr8 instruction set document, that holds all the possible instructions on an AVR8 controller. you then have to check with the datasheet as to what instructions are actually supported on the controller you use.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign worte :

 

One other note about the 32 registers, some of the lower ones are used for math routines by the AVR so as a sort of general rule many of us stick with the upper 16.

 

And I will just comment that most people that don't push, save SFR in R2.

It's a bad idea to waste one of the hi registers for this. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) Always useful to see what a C compiler does! If I write:

#include <avr/interrupt.h>

ISR(INT0_vect) {
}

int main(void) {
}

The INT0 handler does this:

.global	__vector_1
	.type	__vector_1, @function
__vector_1:
//==> ISR(INT0_vect) {
	push r1
	push r0
	in r0,__SREG__
	push r0
	clr __zero_reg__
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 3 */
.L__stack_usage = 3
/* epilogue start */
//==> }
	pop r0
	out __SREG__,r0
	pop r0
	pop r1
	reti
	.size	__vector_1, .-__vector_1

Forget about R1 here as that's a "C thing" but the storage of SREG is done by first pushing R0 then reading SREG to it and pushing that. The opposite being done to unwind.

Is it possible to store the return-stack pointer into Y or Z and access the data on the return-stack with indirect-with-displacement addressing?

Something like:

IN R30, SPL
IN R31, SPH

Pushing and popping upwards of 32 registers seems rather time-consuming --- is there no way to save the machine state more quickly?

An intelligent ISR handler will only PUSH the registers known to be used within the ISR code itself. No need to save the complete machine state but if you are talking about implement a task switching OS then, yes, there's no alternative. You can see a very well known RTOS implementation here:

 

http://www.freertos.org/implemen...

 

(Keep following the "Next" links at the bottom of each page.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unlike compilers for bigger computers you "normally" don't pass parameters on the stack, the AVR are not good at that,

the AVR compilers pass in registers upto 16 bit I think all compilers use R25:R24.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Codevision use a data stack frame and a hardware stack.

All compilers need some form of memory model.

Even if they pass parameters in registers,   you run out after a while.    And variadic implies a stack frame.

 

There are many strategies you can use with an AVR.

Likewise,     you could do things in different ways on a 6502.

 

I am sure that there are several Forth implementions on an AVR.

You may well be able to improve them.

 

I am not sure how many people are inclined to use Forth nowadays.     It does my head in !!!!

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It does my head in

"in head my does It" surely? ;-)

 

(my first ever job offer after leaving university was to work for a company using Forth commercially - because my 3rd year project was about implementing and evaluating Forth on various CPUs - the 6809 was perfect because it had two stacks!)

Last Edited: Fri. Oct 24, 2014 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think that I ever got far with Forth.

 

However,    some years ago,    I did play with writing Postscript by hand.     It is surprising what you can get a Postscript printer to do!

 

Most normal human beings write in C or other procedural language and let a machine generate the necessary Postscript.

 

I don't think that the human brain was ever designed for stack-based languages.

But there is no doubt that machines can run them very efficiently.

 

I note that Cliff has not continued with Forth !

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

care should be taken Registers are NOT memory mapped on XMEGAS, (and the new tinyes 4,5,9,10,20,40 ..).

If you use stack for simple things it cost time, but yes as david you can run out of registers , but then you normally pass a pointer to a structure.

 

On the AVR you only have 3 16 bit pointers you can use (and not the 128 on a 6502, and on a XMEGA you can't directly make a pointer to pointer as I guess you are used to on at 6502).

On the other hand the HW stack can be placed to all RAM. (above 0x60 or 0x0100 depending of chip), and not only page 1.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

meslomp wrote:
there are a number of instructions that only work on the top 16 registers. So again as you are new I would start with only using the top 16 registers and learn how the avr instruction set is operating.

 

From my reading, I found that the lower 16 registers are used by the DES instruction, so if I want to have a Forth word that does DES encryption, then I should have all my Forth registers in the upper 16 to avoid a tangle of register swapping. Also, I noticed that the LDS and STS instructions only work with the top 16 registers. For these reasons, I put all my Forth stuff in the top 16 registers, and used the lower 16 as general-purpose (some of the Forth primitives use these for temporary storage internally). You said there were a "number" of instructions that only work on the upper 16 --- what is there other than LDS and STS? Also, JGMDESIGN said, "some of the lower ones are used for math routines by the AVR" --- is this just a convention, or does he mean that the instructions require this?

 

Another oddity that I found, is that the ADIW and SBIW instructions only work on the top 4 register pairs. Also, any indirect addressing only works on the top 3 register pairs --- this is by far my biggest hassle, as I need 4 pointers, so I have to swap one of them in and out (and there is no instruction to exchange register pairs) --- the 6502 had a lot more pointers!

 

I would like to be able to call C functions from Forth. Is there only one C compiler that I need to concern myself with? Most likely, this is going to be a tangle of register swapping because there are only 3 pointers, and we are both using all of them.

 

Note that I'm writing a Forth cross-compiler. This is not a traditional interactive Forth that runs on the AVR itself. This is a cross-compiler that runs on a desktop computer and generates an assembly-language file that is assembled with a commercial AVR assembler (Atmel Studio). It is similar to C, in that it is not interactive --- the advantage is that it will generate optimized code, whereas most Forth systems don't really do any optimization. I chose the AVR primarily because it is the last 8-bit processor still in common use, and these small processors often lack adequate memory to support a traditional on-chip Forth system, so the AVR is one of the few systems in which a cross-compiler is still worthwhile.

 

So far, I have only looked at the megaAVR, but I would also like to support the tinyAVR. Do these smaller AVR versions lack instructions that are available on the bigger AVR versions? I noticed in my reading that several of the instructions have a note saying that they aren't available on all chips. Is this going to be a problem, that my code won't run on every AVR chip? PUSH and POP, have this note, but they seem to be pretty necessary for writing any ISR --- the only alternative is to dedicate certain registers to ISR use --- if this is true, then we can't have ISRs written in Forth, but only in assembly-language, which pretty much negates the purpose of the whole exercise.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know which chip you want to use

And atmel's instructions manual are very very bad its hard to find out which chip has which instructions, and how many cycles they take, most chips don't have DES.

LDS and STS do work on all registers, it's a lot the things with a constant like LDI etc that don't work with the lower registers.  

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

I don't think that I ever got far with Forth.

 

However,    some years ago,    I did play with writing Postscript by hand.     It is surprising what you can get a Postscript printer to do!

 

Most normal human beings write in C or other procedural language and let a machine generate the necessary Postscript.

 

I don't think that the human brain was ever designed for stack-based languages.

But there is no doubt that machines can run them very efficiently.

 

I note that Cliff has not continued with Forth !

 

David.

 

Well, you're on my twit list --- I've only been here one day, and already I have found somebody who wants to tell me that I'm not a "normal human being" and that it is a mistake for me to continue with Forth, and that knowing PostScript makes him an expert on Forth although the languages are completely different.

 

Please don't have any further communication with me.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I don't know which chip you want to use

And atmel's instructions manual are very very bad its hard to find out which chip has which instructions, and how many cycles they take, most chips don't have DES.

LDS and STS do work on all registers, it's a lot the things with a constant like LDI etc that don't work with the lower registers.  

 

My mistake --- it was not LDS and STS --- it was LDI.

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You just have to sit down with the instruction set,   and choose how you want to implement things.

 

As you have noticed,    the X, Y, Z register-pairs have different uses.

Y is useful for stack frames.    Z is used by LPM, SPM i.e. accessing Flash memory.

The MUL instruction is not available on Tinys.    It uses R0, R1.

 

Why not look at existing AVR-Forth implementations?

 

Or ask about specific functions.

 

Yes,   there are several C compilers.    Each with a different memory model.

I suggest that you pick one and stick with it.     After all,    I don't think you are talking about a mass-market.

 

It is always worth looking at how Compiler writers use ASM sequences.     You can pick up useful tips.

 

David.

 

Edit.   I see that you don't want replies from twits.    My apologies.    I said that Forth was efficient.     I said that I personally did not find it intuitive.

Last Edited: Fri. Oct 24, 2014 - 09:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

Edit.   I see that you don't want replies from twits.    My apologies.    I said that Forth was efficient.     I said that I personally did not find it intuitive.

 

Okay, I accept your apology.

 

Forth is not for everybody, but neither is C for everybody. There are a lot of bad Forth implementations (everything from Forth Inc.) that have unfortunately turned people off from Forth, and I don't think it is fair to lump me in with them. There are some bad C implementations too, but C has a standard and Forth doesn't, so all C compilers are pretty much the same (except for the 8051 C compilers that don't allow addresses of local variables to be passed around).

 

I'm not trying to proselytize people into using Forth, but the other side of the coin is that I don't want to listen to people try to convince me that I'm wrong to use Forth --- to each his own.

 

BTW: My Forth will have quotations (similar to Factor), which C does not have --- this is pretty much the point of it --- these allow for general-purpose data-structures.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, JGMDESIGN said, "some of the lower ones are used for math routines by the AVR" --- is this just a convention, or does he mean that the instructions require this?

What I meant was that certain instructions automatically use the lower registers.  Mostly the math instructions.  I recall the assembler kicking up a fuss about me using certain lower registers and the only way I could get rid of the notification was by changing the register I used.  If you look at the instruction set it's called out in many cases.  AS noted already some of the documentation is not 100% but by staying in the upper 16 you greatly reduce your chances of getting bit. (no pun intended)

 

Well, you're on my twit list --- I've only been here one day, and already I have found somebody who wants to tell me that I'm not a "normal human being" and that it is a mistake for me to continue with Forth, and that knowing PostScript makes him an expert on Forth although the languages are completely different.

 

Please don't have any further communication with me.

 

Edit.   I see that you don't want replies from twits.    My apologies.    I said that Forth was efficient.     I said that I personally did not find it intuitive.

 

Okay, I accept your apology.

Good to see everyone getting along but Hugh, please do not take it personally.  Theres very few ASM'ers around here, maybe five, and you are a very unique duck in this pond by using Forth.  Either way, expect a lot of references to C.  And for the record, I have yet to be called a "normal human being" wink

 

Forth is not for everybody, but neither is C for everybody.

No argument from me on that.

I'm not trying to proselytize people into using Forth, but the other side of the coin is that I don't want to listen to people try to convince me that I'm wrong to use Forth --- to each his own.

Agreed, but I did not see anyone trying to convince you that your path is the wrong one, nor did I see you trying to convert anyone either.  Like you said "to each his own".  Where it's possible that the feeling may have come from, we get the occasional individual that has a 'revolutionary product', or is looking to hack a product to which they have no idea what they are getting into, and then post that they are going to create their own development environment(or something to that effect) and the bulk of us shake our heads and roll our eyes so I apologize if thats what you were thinking.  FRom what you have presented to date you obviously have been doing your homework so no worries.

 

Cheers!

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How will new Forth words be added?

 

I still have my old Forth compiler for the Signetics 2650 (+- 30 YO) never ended up using it much.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will like to know what your goal is ?

And do you want it to work on big and/or small AVR's

should it run fast or be small.

 

I will say that I'm one of those that know the AVR ASM (but only clasic tiny and mega parts).

Somewhere I have posted some code that emulate AVR code running on an AVR (so the code could be placed extern never finished but perhaps some ideals)
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And if you know C then write some GCC code and look at the ASM output.

Optimal code (speed) for AVR are very different from 6502

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh,

 

Welcome to the Forum.

 

If you edit your original post's Thread Title to include the word "Forth" it might attract other Forth users, and additionally be easier for others to search on, in the future.

 

JC

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

How will new Forth words be added?

 

There are two modes: HOST and TARG

 

Everything defined in HOST is compile-time code, and everything defined in TARG is run-time code. All the TARG code is compiled into an intermediate code. Also, in HOST mode, we switch over to TARG at DOES> and back to HOST after the ; so this is generates intermediate code too. After the entire program is interpreted, and all of the TARG code is turned into intermediate code, the intermediate code is optimized and then it is converted into an assembly-language file for the AVR. This last step, of converting the intermediate code into an assembly-language file, is short and simple --- this is the only part of the program that has to be rewritten if the cross-compiler is to be retargeted to a different processor --- I'm just starting with the AVR because it is the smallest processor that my language could conceivably be run on, so if I can make it work on the AVR there should be no difficulty in making it work on a bigger processor.

 

The AVR is dying out --- I doubt that anybody chooses the AVR for new projects, because there are more powerful processors available for the same amount of money --- some people currently using C on the AVR may switch over to my Forth if it generates smaller and faster code than the C compiler does, and breath some more life into a struggling AVR system. For the most part though, this AVR version is just a proof-of-concept, and I expect to focus mostly on more modern processors. The PIC24 will be next, most likely.

 

Don't worry, I know how to write a Forth cross-compiler. I wrote MFX for the MiniForth processor at Testra 20 years ago. MFX didn't have the intermediate code, but it compiled straight into machine-code and didn't do any optimization. The MiniForth didn't have very many registers though, so there wasn't all that much point in doing optimization --- modern processors have a lot of registers, so there is more opportunity for optimization. The AVR didn't even exist until 1996, so it wasn't available at the time of the MiniForth project --- the MiniForth ran a motion-control program that was ported over from their previous 80c320 version.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

And if you know C then write some GCC code and look at the ASM output.

Optimal code (speed) for AVR are very different from 6502

 

I'm aware that the 6502 is pretty slow by modern standards. I just meant to say that it was convenient to have as many pointers as you may need. Actually, it doesn't really help all that much, as it is rare to use more than 2 pointers at a time, so on the AVR they can be copied over to the X, Y or Z as necessary. Anyway, the AVR is what it is, so there is no point in wishing for more pointers --- I'll just use X, Y and Z, because that is what is available. As I said before, the AVR is the smallest processor that I expect to target, so if all this stuff works on the AVR, then it should work on anything else.

 

I wrote a 65c02 Forth cross-compiler in the early 1990s that generated code significantly faster than any C compiler generated --- I doubt that 6502 C compilers are any better today --- I'm not interested in looking at GCC-generated code for any processor, except for when it comes time to compare my AVR Forth with C on some benchmarks.

 

I'm not knocking the AVR. :-) From my study so far, the AVR seems to be pretty cool. I would rather have the AVR as a target than the 32-bit x86 --- more registers!

 

BTW: On the AVR, we can store data in memory with either little-endian or big-endian format (unlike the 6502 that required little-endian, at least for the pointers). I noticed that in the AVR register pairs, the low byte goes in the even register and the high byte goes in the odd register above it --- should I assume that when storing to memory, the convention is to use little-endian (low byte first, then high byte)? --- or do some people use little-endian and other people use big-endian?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You said there were a "number" of instructions that only work on the upper 16 --- what is there other than LDI and STS?

IIRC, none of the "immediate" instructions work on the lower registers (cpi, ldi, adiw, subi, sbci, andi, ori, sbr, cbr (sbr/cbr are synonyms for andi/ori, I think)

At one point I was making myself a lovely table, and then I figured out that it was only the immediate instructions...

 

"some of the lower ones are used for math routines by the AVR" --- is this just a convention, or does he mean that the instructions require this?

Multiply, and some other instructions, use r0/r1.  I don't think there are any other low registers with dedicated usage.

 

6502 had a lot more pointers!

The AVR (at least the MEGAs) have 3 16bit pointers, plus a stack pointer (that isn't indexible)   I thought the 6502 only had the two (X/Y) 8bit pointers (though I guess the combine in interesting ways with page0 memory values?)  Some of the lesser AVRs have fewer pointer registers, BTW.  Like a lot of "risc" processors, the AVR is like "You can do general purpose math and move results into the pointer registers as needed, and it's still faster than the old cpus (like the 6502.)"  Personally, I've always thought that Atmel was a bit dishonest when they claimed "32 general purpose registers."

 

Most AVR code (and compilers) use little-endian format for bigger data structures.  Note that "word" instructions that exist address the registers little-endian (but since there are nothing beyond byte store/load, you can put them in memory either way.)

 

if it generates smaller and faster code than the C compiler does

Good luck with that.  "In theory" the AVR was designed with C in mind, which means C compilers have it a lot easier than they did with some of the older CPUs.

Are you are of AmForth?  It's a pretty active Forth effort for AVRs (local interpreter, rather than cross compiler.)  http://amforth.sourceforge.net/

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote MFX for the MiniForth processor at Testra 20 years ago.

Is that with an L as in Telstra? 

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The AVR is dying out --- I doubt that anybody chooses the AVR for new projects, because there are more powerful processors available for the same amount of money

 

I do, and many others here do.

And if you need both ADC, EEPROM and 5V chips. the price is OK.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Years 30 !

Have forth years @ not .

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. 

Last Edited: Sun. Oct 26, 2014 - 01:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

I wrote MFX for the MiniForth processor at Testra 20 years ago.

Is that with an L as in Telstra? 

 

No --- I spelled it correctly: http://www.testra.com/

They have since changed the name from MiniForth to RACE --- and they upgraded from the Lattice isp1048 to an FPGA --- I visited them a few weeks ago and was told that they still use MFX (running under the obsolete UR/Forth in a DOS-extender!).

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

 

Quote:

 

The AVR is dying out --- I doubt that anybody chooses the AVR for new projects, because there are more powerful processors available for the same amount of money

 

 

 

I do, and many others here do.

And if you need both ADC, EEPROM and 5V chips. the price is OK.

 

Good! Maybe somebody will want to use my Forth system. :-)

 

Is it true that the assembler doesn't use a linker, but it compiles directly into an executable? This seems to imply that I can't distribute object files, but have to distribute source-code.

 

I'm not adverse to distributing AVR assembly-code --- most of this is pretty straightforward (it is hard to mess up DUP and SWAP, etc.) --- so I'm not giving away any great secrets. Is it appropriate to post code on this forum? Maybe people could comment on the quality of the code --- this is my first-ever effort at AVR assembly code.

 

When C is your only hammer, every problem looks like your thumb. 

Last Edited: Mon. Oct 27, 2014 - 12:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

if it generates smaller and faster code than the C compiler does

Good luck with that.  "In theory" the AVR was designed with C in mind, which means C compilers have it a lot easier than they did with some of the older CPUs.

Are you are of AmForth?  It's a pretty active Forth effort for AVRs (local interpreter, rather than cross compiler.)  http://amforth.sourceforge.net/

 

 

C needs fewer pointers than Forth does, because it uses the return-stack for local variables. In the old days we had processors such as the 6808 that had only two pointers (the return-stack and the H:X pair), but they had indexed addressing on the return-stack pointer so they supported C frames. Forth needs three pointers (the return-stack pointer, the parameter-stack pointer, and a general-purpose pointer), so it would be very difficult to implement Forth on a 6808. The AVR has three pointers, X Y and Z, so it is fine for Forth. Similarly, the 6809 was good for Forth, but the 6812 was not because it didn't have the U register that the 6809 had --- this was despite the fact that the 6812 came after the 6809 and was supposed to be an improvement.

 

I previously said that I needed 4 pointers, but I have simplified the design (abandoned floating-point) so now I only need 3, which the AVR conveniently has. I don't think anybody really uses floating-point on micro-controllers. The PIC24 has a lot better support for arithmetic (it has division), so I may go with floating-point on that one.

 

As for amForth, I'm not familiar with it. It is a local interpreter, as you say --- it can do this because it generates indirect-threaded-code rather than machine-code, and so it doesn't need to have an AVR assembler built-in to the compiler. I want to generate machine-code however, for speed, so I have to write a cross-compiler --- it is possible to do this with an on-chip Forth system, but it is way more complicated than I want to get into (plus, the AVR is a stepping-stone, and not something that I want to get stick with forever).

 

A local interpreter is very useful though! This is useful for testing code. A lot of boards are not to spec at all --- software won't work if it is written according to the hardware spec --- the programmer just has to figure out what the hardware is doing through trial-and-error. You write short test functions and execute them, and you observe (usually with an oscilloscope) what the effect on the outside world is. Forth is far better than C for this, as there is no edit-compile-link-debug cycle, but you just type in your function and it is ready to use. This is what amForth would be useful for --- my system won't do this.

 

On the subject of a local interpreter, what is the deal with writing to FLASH on the AVR? This can be done, but only in 256-byte pages? Writing to FLASH is necessary for a local interpreter.

 

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is it true that the assembler doesn't use a linker, but it compiles directly into an executable?

The Atmel assembler doesn't use a linker, but you could use the Gnu assembler instead (slightly different syntax), which does, if you wanted to ship object files.

 

what is the deal with writing to FLASH on the AVR? This can be done, but only in 256-byte pages?

Page-at-a-time writes are typical for program FLASH memory on microcontrollers (not to be confused with EEPROM.)  On the AVR, this can (additionally) only be done from the "boot section."  Exact page size, as well as the location and max possible size of the boot section, vary depending on which chip you're using.

 

You might want to look into being compatible with AMForth.  Like I said, they've been quite active (impressively so), and it looks like a relatively advanced (forth 200x/etc) implementation...  A compiler is a nice alternative to an interpretive environment.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since this thread is more about compiler(s) that an AVR ISSUE I am going to move this to the Compilers forum

 

Thanks,

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't get me started about Forth, I'll just say that if I had a good solid Forth system that would run on Avrs I would be one "happy camper"!  I still ship and/or support 6502, 8031 and 80x86 systems I developed starting in the early '80s. I eventually settled on  the LMI products, UR/Forth for PC applications and their metacompiler for embedded systems.  What got me hooked initially were the Rockwell 6502 MCUs with the built in Forth kernel. Right now industrial 6502 Forth systems are running in the most severe environments on the planet and have been for many years. "C" is OK but Forth is just plain bad-ass 8)

Tom Pappano
Tulsa, Oklahoma

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

Is it true that the assembler doesn't use a linker, but it compiles directly into an executable?

The Atmel assembler doesn't use a linker, but you could use the Gnu assembler instead (slightly different syntax), which does, if you wanted to ship object files.

 

It is not just that I want to ship object files. More importantly, I want to be able to link in C libraries --- I would write wrappers for them as Forth primitives --- how is this possible without a linker? By C libraries, I mean support for general-purpose I/O such as TCP/IP and USB --- maybe this stuff isn't available on the AVR anyway --- so it is a non-issue.

 

I get the impression that the Atmel Studio assembler was provided solely for the purpose of supporting inline assembly code in C programs, which is why it doesn't have a linker.

 

This whole business of not having a linker seems rather weird to me. I'm also unimpressed with Atmel Studio because it is slow as molasses. OTOH though, I want to go with whatever assembler is most popular, so if Atmel Studio is generally considered to be the standard for the AVR, maybe I should stick with it. I've already written code in Atmel Studio, but not very much --- I should decide which assembler I want to use, before I get too far into the project.

 

westfw wrote:
You might want to look into being compatible with AMForth.  Like I said, they've been quite active (impressively so), and it looks like a relatively advanced (forth 200x/etc) implementation...  A compiler is a nice alternative to an interpretive environment.

 

I wouldn't describe Forth-200x as being "advanced." They don't have quotations. What they have are Payson-faked quotations, which are just syntactic sugar for :NONAME. What I will have in my language are true quotations, that have access to the parent function's local variables. They have a lot of other problems as well. ANS-Forth was mandated to allow SwiftForth to be compliant without any change in SwiftForth, and Forth-200x is mandated to not break any ANS-Forth programs (as if there were any) --- I really see ANS-Forth and Forth-200x as a marketing scheme from Forth Inc. to make everybody believe that SwiftForth is the standard of the entire Forth community.

 

I do know ANS-Forth fairly well: http://www.forth.org/novice.html

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tpappano wrote:

Don't get me started about Forth, I'll just say that if I had a good solid Forth system that would run on Avrs I would be one "happy camper"!  I still ship and/or support 6502, 8031 and 80x86 systems I developed starting in the early '80s. I eventually settled on  the LMI products, UR/Forth for PC applications and their metacompiler for embedded systems.  What got me hooked initially were the Rockwell 6502 MCUs with the built in Forth kernel. Right now industrial 6502 Forth systems are running in the most severe environments on the planet and have been for many years. "C" is OK but Forth is just plain bad-ass 8)

 

How important is it to you to have an interactive system? Mine won't be interactive --- it is just a cross-compiler similar to C --- I may be able to write an on-chip Forth that is compatible later on, but that won't be for a while.

 

BTW: I wrote MFX in UR/Forth. Testra used UR/Forth for everything. Their motion-control program had been written in LMI's cross-compiler for the Dallas 80c320 prior to getting ported over to the MiniForth. Testra has the source-code to UR/Forht that Ray Duncan gave to them, but they signed a non-disclosure statement, so I wasn't able to look at the source-code when I was employed there --- this didn't really matter, as I had already disassembled the heck out of the system anyway, and I had plenty of "unlawful carnal knowledge" of UR/Forth, some of which I used in MFX. LMI was out of business at the time that I worked there, which was about 2 years prior to the AVR coming out.

 

Are these 6502 systems that you mention actually 6502 chips, or are they FPGAs with a 6502 core? Why does it matter if it is a "severe" environment? Are they more resistant to environmental wear?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

More importantly, I want to be able to link in C libraries --- how is this possible without a linker?

It's not.  C compilers tend to come with their own assemblers and linkers.  AMForth (again) is an interesting example of building an Atmel Assembler application out of multiple source files (lots of .asm files ".include"ing other .asm files.  :-(

 

I get the impression that the Atmel Studio assembler was provided solely for the purpose of supporting inline assembly code in C programs, which is why it doesn't have a linker.

No, that's sort-of backwards.  C is inherently library-based and requires a linker.  The Atmel assembler is probably "weak" because they were encouraging people to use C for a lot of stuff, anyway.  The Gcc assembler is sort of ugly and designed (I think) primarily for being a Compiler sub-program, but it's functional enough once you get used to it.  The big problem is that the syntax doesn't quite match the published Atmel code.   (It cold be worse.  The ARM version of gcc assembler uses "@" as the comment character...)

 

 I want to go with whatever assembler is most popular, so if Atmel Studio is generally considered to be the standard for the AVR

Atmel Studio actually includes both the Atmel assembler and the Gnu assembler (assuming that you have also install the gcc C compiler, anyway.)

(possibly up to 3 versions: avrasm was an old dos-interface assembler.  avrasm2 is newer and mostly compatible with newer OS support.  and avr-as is the gnu assembler.)  It's not clear how popular Atmel Studio is; a lot of people seems to skip it and use command-line tools with their favorite editor.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I get the impression that the Atmel Studio assembler was provided solely for the purpose of supporting inline assembly code in C programs, which is why it doesn't have a linker.

No, that's sort-of backwards.  C is inherently library-based and requires a linker.  The Atmel assembler is probably "weak" because they were encouraging people to use C for a lot of stuff, anyway.  The Gcc assembler is sort of ugly and designed (I think) primarily for being a Compiler sub-program, but it's functional enough once you get used to it.  The big problem is that the syntax doesn't quite match the published Atmel code.   (It cold be worse.  The ARM version of gcc assembler uses "@" as the comment character...)

 

GAS is notorious for being ugly, and also for lacking error-checking so a programmer's typo doesn't get caught and GAS just produces bad code. From what I've read, GAS was designed to be a back-end for C compilers, so the lack of error-checking isn't an issue because the C compiler doesn't generate typos. It shouldn't be an major issue for me either, because I will be generating code too --- although it might make for a steep learning curve, if I'm generating bad code and don't realize that my syntax is screwed up.

 

My Forth actually started out being for the ARM/Cortex-M3 (using GAS), but the customer dropped the project when he realized that it wasn't going to be interactive --- although I had explained clearly that it was a cross-compiler. The customer was going to write the ARM primitives, and I was going to write the Forth compiler that generates the intermediate code. We got far enough to be able to compile simple Forth colon words and <BUILDS DOES> words. 

 

Anyway, I don't know ARM assembly-language, so now that it is my own project I'm switching to the AVR --- I don't know AVR assembly-language either, but AVR assembly-language is much easier to learn. Also, a cross-compiler for a big 32-bit processor doesn't make much sense because such a big processor can easily support an on-chip Forth system --- a cross-compiler makes more sense for a small system like the AVR that may not have enough memory for an on-chip Forth system and/or has a cumbersome system of writing to FLASH that would complicate compilation on-chip.

 

BTW: The comments that I saw in GAS for the ARM were C++ish // rather than @ as you said. I agree that @ would be rather jarring to the eye --- why not just use ; like every other assembler in the world?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The cortex Mx series range from AVR level to much larger. I wouldn't discount the viability of a cross compiler for these, nor would I say ARM is any harder than AVR - it would be more flexible methinks. It's always a bit of a culture shock coming from an accumulator based architecture to a RISC one with lots of registers.

 

You can always skip the pain of ASM and compile to C as an intermediate code..........

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

also for lacking error-checking so a programmer's typo doesn't get caught and GAS just produces bad code.

I don't think it's that bad.  I've done a couple of things with gas, and I manage to get plenty of error messages!  The big "lack" is that all symbols created default to being "extern", so you don't get the usual warnings about undefined symbols until link time (and if you happen to do math that the linker can't do on a mistyped (assumed external) symbol, you get mysterious messages about not being able to perform that operation on that symbol.)

 

Some of the new "8-bit replacement" ARM microcontorllers (Cortex M0, M0+) have as little as 4k of flash, so a good tight-output compiler could indeed be useful.  (A lot of the C libraries developed by vendors pre-date these small chips, and are pretty bloated.  (one of the reasons for one of my gas projects!  ARM in all-assembler!  Whee!)

 

https://github.com/WestfW/struct... "Structured assembler" macros for gas on several CPUs.

https://github.com/WestfW/Minima... (far from complete.)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How important is it to you to have an interactive system? Mine won't be interactive --- it is just a cross-compiler similar to C --- I may be able to write an on-chip Forth that is compatible later on, but that won't be for a while.

Not being interactive is no deal killer, but it is a nice feature that can speed up development.  What I did on my projects was simply include the interactive compiler source with the kernel source when I metacompiled the target system code.  I could then interactively write and test new words and/or load screen files directly on the target system.  When I had something I was happy with I could just recompile without including the "compiler layer" and ship it.  As I recall, Duncan's metacompiler licensing prohibited releasing systems that were capable of compiling.

 

I mostly used the GTE G65SC102 which was a 6502 with an improved and reliable crystal oscillator circuit.  Many years out of production but I still have a bunch.

 

The severe environment thing is just an interesting side note. 

Tom Pappano
Tulsa, Oklahoma

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I get the impression that the Atmel Studio assembler was provided solely for the purpose of supporting inline assembly code in C programs, which is why it doesn't have a linker.

You need to know a bit of history about Atmel to understand where we are now. Studio 6 (well 6.2) is just the latest in a long line of versions of Studio. There was Studio 5 (Ugh!), Studio 4, Studio 3 and so on. When Atmel first started making a dev environment for their AVrs it had just a single very limited assembler. It's a two pass, non-linking assembler and dates from around the turn of the millenium. They improved it and made a second version that's generally known as Asm2. This had improved features like a (kind of!) C pre-processor bolted onto the front that allows #define's and #ifdef's and so on.

 

At some stage someone at Atmel recognised how popular the independently developed avr-gcc C compiler happened to be so they developed a "wrapper" that would allow it to be integrated into Studio (4). For years (2005..2010) people went shopping for their C compiler independent of Atmel/Studio and a guy called Eric Weddington started to build what was principally a Unix tool (gcc) for Windows in a distribution called "WinAVR". So everyone downloaded Studio (including its two Atmel developed assemblers) from Atmel then went on to downloading/installing WinAVR separately. The GCC plug-in in Studio would recognise when a machine had WinAVR installed so would then offer to create C as well as Asm projects inside Studio.

 

Now it just so happens that the way avr-gcc (like most C compilers) works is that it's really a C to Asm converter. But the Asm it creates (for AVR) is not in the Atmel Asm1/Asm2 syntax but avr-gcc as a package comes with both C (and C++) compilers but also a package called "binutils" and in that is avr-as which is an AVR port of the GNU as assembler. That is the assembler for which the C compiler creates Asm code. That assembler creates linkable object modules (ELF) and these are then fed to another component of binutils: avr-ld which is the GNU ld linker for AVR. Atmel, by their work on the avr-gcc plug-in for Studio 4 were obviously keen on seeing avr-gcc integrated into their IDE so when they took Microsoft Visual Studio 2010 as the basis of creating Studio 5 they didn't just create a GCC plug-in to interface to an external copy of avr-gcc but made the decision to bundle avr-gcc (and avr32-gcc) in with Studio 5. It (the IDE not the compiler!) was a bug fest and tarnished their reputation for 2-3 years but then they finally brought out Studio 6 which not only fixed things but bundled a third GCC with it so it can now do avr-gcc, avr32-gcc and arm-gcc for Cortex parts.

 

And that's what you have now. So when you come to "create new project" in Studio 6 you have the option of C (avr-gcc) or C++ (avr-gcc) or Asm (Atmel Asm 2).  However C/C++ use avr-gcc and it uses avr-as so there's nothing to stop you creating a "C" (or even "C++") project but then using nothing but avr-as in it. Or, perhaps, more usually, some combination of C and avr-as assembler. You put C source in .c files, C++ source in .cpp files and avr-as source in .S files. avr-gcc is a "compiler driver" (not just the compiler) and it knows by the .c/.cpp/.S alone whether to pass the file to be built to the C compiler or the C++ compiler (curiously called avr-g++ in fact!) or the GNU assembler, avr-as. As well as C/C++ executables you also have the option to create C or C++ (and hence avr-as) static libraries which are linkable ELF .a files. The usual downside of .a for AVR use though is that they have to be built for one of the AVR architectures like AVR2 or AVR5 or whatever. So you end up building something like 17 variants is you want to provide the same code to all the different AVR targets. The architectures differ in things like Tiny have no MUL opcode - so their libraries cannot use MUL. At he other end of the scale the "big ones" need to use ELPM rather than LPM to access their code space and things like that. This issue and the fact that -ffunction-section and -gc-sections now exist mean that use of .a on AVR is very rare. In fact about the only place you see .a's are for the sys libs like libm.a, libc.a and libgcc.a

 

So, anyway, if you want to integrate C and Asm your choice is clear - you use avr-as not Atmel Asm 2 as your linking assembler.

I want to go with whatever assembler is most popular, so if Atmel Studio is generally considered to be the standard for the AVR, maybe I should stick with it.

That's a very unwise decision. If you want to easily integrate C and Asm pick avr-as not Atmel Asm2. I once showed a way to build a project that integrated avr-gcc and Asm2 code using a binary linkage. It was posted to the old Freaks site but should have been migrated to this new site. It is just about "do-able" but it is a monumental PITA.

How important is it to you to have an interactive system?

Surely the interactive nature of Forth is its main attraction? It's great that at run time you can just throw together a quick sequence to fire up the PWM on a timer pin or whatever. If it's only to be compiled what kind of masochist is going to choose the tortured syntax of Forth over C/C++. (as I say, I did a 3rd year university project on Forth implementations so I am quite familiar and short of manacles and hot irons nothing would persuade me to use Forth if I didn't have to - but the interactivity and ability to grow the dictionary at run time is the very thing that makes it worth battling with the syntax. (disclosure: I've never like HP RPN calculators either!)

 

Last Edited: Tue. Oct 28, 2014 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I try to ask again :)

Which size of AVR is your target?

Main thing I guess : how big is your "kernel"?

Remember AVR go from 1/2K of flash to 256K+ 

and 32 byte of RAM to 16K+

By only have a cross compiler one could hope that it could work on relatively small AVR's.

You have to look for different code generation depending of size.

256 byte of RAM (8 bit data pointer).

8K of flash (4K instructions), RJUMP can reach anywhere.(it wrap around)

64K of flash const data can stay in 16bit pointer.

128K of flash (64K instructions), 16 bit PC.

On some you can place the soft stack in registers but not Xmega and new 16 reg tiny's.

 

About the simple ASM, we need some background.

IAR was in over when the final instructions set was defined, and there IAR assembler was free, so Atmel only needed a small and quick assembler that worked  (had some errors for a long time I remember I had to insert nop's to get it to work on my first project there was an error around the 4k rjump mapping point.) 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A "compiler" option for Forth that would do the equivalent of -gc-sections (omit all the words not actually used by an application) would be pretty interesting even if it still produced the threaded code/word based "binary."

I dunno.  I've done Forth-like interpreters for playing with libraries (without implementing any standard forth.  More of an RPN caclulator, I guess.)  And I've written postscript hacks.  But I've never really programmed in forth itself.

 

(Has anyone ever done a non printer-oriented postscript?  It always seemed to be like postscript fixed a lot of the things that used to bother me about forth itself...)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok now I have been playing with a Jupiter ace emulator, and seen what it can do in 1K of forth RAM,(the other 2K is  video and character RAM).

and it has 8K of ROM where big parts are for the video, tape  FP etc

 

So I see a local interpreter forth running on a 2K AVR and up, hooked up to a terminal. Perhaps fill all the flash up with good forth words for an embedded system, and then place new words in EEPROM.

or for 8K flash have a bootloader, so you can move/compile words from eeprom to flash, and have FP.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's nice to see esoteric languages being dredged up and bandied about. I had thought Forth has died a slow death years ago.

Then again, Halloween is coming, maybe it's a zombie :)

Keith Vasilakes

Firmware engineer

Minnesota

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Perhaps we should build a forth computer over AtomicZombie's video setup, but I guess it will be hard to add the terminal IO's to a tiny85 :)

 

edit

I did not think, only 1 IO is needed (the video show the output), so a terminal output is only needed to save the program, and then the video don't need to work.

Last Edited: Wed. Oct 29, 2014 - 09:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I try to ask again :)

Which size of AVR is your target?

Main thing I guess : how big is your "kernel"?

Remember AVR go from 1/2K of flash to 256K+ 

 

I don't know yet. A cross-compiler is mostly useful on small targets, because a big target can support an on-chip interactive Forth system, so I want make my kernel as small as possible so my language can be used on the small systems that would not be supported by an on-chip interactive system such as amForth.

 

I would like to get an interactive system going later on that is compatible --- this will be the first program that I write using the cross-compiler.

 

clawson wrote:

I want to go with whatever assembler is most popular, so if Atmel Studio is generally considered to be the standard for the AVR, maybe I should stick with it.

That's a very unwise decision. If you want to easily integrate C and Asm pick avr-as not Atmel Asm2.

 

Well, it appears that I need to switch to AVR-AS from Atmel ASM2.

 

To provide a smooth transition from C to my Forth, it is necessary to link Forth modules with C modules --- have a mixed-language application during the transition.

 

The following is my list of register dedications (still in ASM2). I would be interested in knowing how well this will work with C, as I can move things around as necessary to avoid any clashes that would result in a lot of register-swapping to call C functions from Forth.

 

; This is the product of MUL etc..  It can also be used as a general-purpose register-pair.
.equ PRD0    = R0
.equ PRD1    = R1

; This is a general-purpose double.
.equ GP2    = R2
.equ GP3    = R3
.equ GP0    = R4
.equ GP1    = R5

; This is a the high word for Z, so it can be used as a general-purpose double.
.equ Z2        = R6
.equ Z3        = R7

; This is ROS (third-on-stack).
.equ ROS2    = R8
.equ ROS3    = R9
.equ ROS0    = R10
.equ ROS1    = R11

; This is SOS (second-on-stack).
.equ SOS2    = R12
.equ SOS3    = R13
.equ SOS0    = R14
.equ SOS1    = R15

; Everything above this is used by the DES instruction, and also does not work with LDI etc..

; These are reserved for a fast-ISR, or for the RTOS if there is one.
.equ ISR00    = R16
.equ ISR01    = R17
.equ ISR10    = R18
.equ ISR11    = R19
.equ ISR20    = R20
.equ ISR21    = R21

; This is TOS (top-of-stack).
.equ TOS2    = R22
.equ TOS3    = R23
.equ TOS0    = R24                        ; ADIW and SBIW will work on TOS1:TOS0. Also, this typical for passing parameters into C functions.
.equ TOS1    = R25

; This is the parameter-stack pointer.    This has to be X, so indirect addressing will work (but no displacement).
.equ X0        = R26
.equ X1        = R27

; This is the local-frame pointer.        This has to be Y so indirect-with-displacement addressing will work
.equ Y0        = R28
.equ Y1        = R29

; This is the general-purpose pointer.    This has to be Z so it can be used for program-memory as well as data-memory, and by CALLI and JMPI.
.equ Z0        = R30
.equ Z1        = R31

; We have a "fat stack" --- it is 2 cells wide, rather than 1 cell.

; The stack or locals can contain any of the following data types and sizes: double(2), string(2), xt(2), single(1), pointer(1).

; It is the programmer's responsibility to use the appropriate operator on the data.

 

clawson wrote:

How important is it to you to have an interactive system?

Surely the interactive nature of Forth is its main attraction? It's great that at run time you can just throw together a quick sequence to fire up the PWM on a timer pin or whatever. If it's only to be compiled what kind of masochist is going to choose the tortured syntax of Forth over C/C++. (as I say, I did a 3rd year university project on Forth implementations so I am quite familiar and short of manacles and hot irons nothing would persuade me to use Forth if I didn't have to - but the interactivity and ability to grow the dictionary at run time is the very thing that makes it worth battling with the syntax. (disclosure: I've never like HP RPN calculators either!)

 

I agree that the interactive nature of Forth is its main attraction. As I said before, hardware is almost never to spec --- it is typically necessary to figure out what it does by guess and by golly. A cross-compiler is what I'm writing however --- it does have the advantage of producing optimized code --- I expect to generate faster-executing code than C generates.

 

I'm very unimpressed by your statement "I did a 3rd year university project on Forth implementations so I am quite familiar" --- I think your Forth knowledge is novice-level at best, and likely not even that --- I run into people all the time who claim to be Forth experts due to some school-boy paper project, but who have never written a Forth application, and who make troll statements to the effect that a Forth programmer is a "masochist." 

 

My Forth will have quotations, that C lacks. These allow for general-purpose data-structures. A quotation is defined inside of a colon definition, and it has an xt (execution token) similar to a colon word or any other kind of definition. When the quotation is executed however, it has access to the parent function's local variables. The purpose of this, is that functions (called "higher order functions") can be written to traverse a data-structure and they take the xt of a quotation as a parameter and they execute it for every node that the traverse over. The parent function, that calls the higher-order function,  gets information back from the quotation stuffed into its local variables.

 

The way that this is typically done in C, is that a struct is defined and allocated on the heap, and it holds all the data that would normally be stored in locals, and the address of this struct is passed into the higher-order function along with the pointer to the quotation (C doesn't have quotations though, so the "quotation" is just another function at the same global scope as the parent function), and information is passed back inside of this struct. Similarly, if a function is to return more than one datum, this is typically done in C by returning a struct on the heap, rather than just put multiple data on the parameter-stack as is done in Forth. This unnecessary use of structs results in some incredibly "tortured syntax" as well as inefficient code (any use of the heap is slow, and if the heap gets fragmented the whole program can crash because MALLOC won't work anymore) --- I am very unimpressed! --- I think that most C programmers are not much beyond BASIC programmers in regard to their knowledge of computer-science, and the majority of them know almost nothing about functional programming.

 

I've heard that the recent versions C++ have something similar to quotations now, but C++ didn't have anything when I worked as a C++ programmer. I'm not interested enough in C++ to learn about what features have been pasted onto the latest versions. I've heard the Java lacks quotations too, but that the upcoming version will have something. I'm not interested in Java at all --- it is notorious for cut-and-paste of boiler-plate code, which is totally the opposite of Forth philosophy. I'm not really interested in any language other than Forth --- I've never found anything that comes close.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My Forth will have quotations,

Never heard of them.  Got a pointer to online documentation?

 

The register conventions used by avr-gcc are described here:

http://www.nongnu.org/avr-libc/u...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What you describe about quotations sounds very much like lambda functions in many other languages. Is that basically what they are?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh, you really know how to win friends and influence people! Is this a demonstration of Asperger traits? You abuse those that make generalisations about forth then spurt out a heap of generalisations yourself! For me, a programming language is a tool, not a way of life or a badge i wear to differentiate myself. I think the last time i talked about forth was back in the days of the 65f11. Nevertheless, this discussion has piqued some interest - especially the mention of the Jupiter Ace.

 

Regarding the C vs Forth debate regarding code efficiency - what endows Forth with the ability to generate more efficient code?

Back in the day Forth was clearly faster than basic and free C compilers were thin on the ground. Now we have a big computing hammer that can apply a zillion optimisations in a blink of an eye. Obviously, these optimisations would benefit Forth as well. 

Let's say we implement a red/black tree in asm, C and Forth. Is Forth going to be of advantage in code efficiency or ease of coding? 

Considering I was paid to write Php code today, does that mean i wouldn't know recursion even if it bit me?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I expect to generate faster-executing code than C generates.

I simply don't believe you can do that. TIL is not the magic pill that suddenly makes things go faster. At the end of the day if you write:

c = a + b

or

a b +

or whatever in any language it's going to become:

retrieve A (LD or LDS probably)
retrieve B
ADD Rn, Rm

it's going to be an "ADD" whatever HLL syntax was used to suggest the operation in the first place.

I think your Forth knowledge is novice-level at best, and likely not even that

Yeah you are probably right. But how long do you have to do something that seems terrible and counter-inutuitive until it starts to become acceptable? Procedural languages like C/C++ just seem "natural" by comparison.

it has access to the parent function's local variables.

Like a class in C++? Or something else?

I think that most C programmers are not much beyond BASIC programmers in regard to their knowledge of computer-science

I guess that makes you an utter genius - well done! - I aspire to get there one day but C/C++ really hamper my understanding of computer science :-(

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

comments to your layout.

I don't totally understand why you have 4 byte reserved for stack elements, do you have a special double stack action for 32 bit?

you have 2. and 3. stack element in registers (I assume normally only 16 bit used),  that will give a lot of move of words, but I guess it speed things up when there only is a few elements on the stack.

The C compiler often have something like 4 16bit variables and 3 8 bit, in registers and it loads them direct to the correct place, I don't think your structure will have any change to be as fast, but on the other hand a factor of 2 or even 3 in size should be possible.

Where do you put your loop counter(s) it should be in registers I think. 

What do you mean with fast ISR? for R16-R21 (the AVR don't have SW ISR's if that is what you mean). 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your programming of Forth is weak and confused, only my programming is true Forth!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:

What you describe about quotations sounds very much like lambda functions in many other languages. Is that basically what they are?

 

Yes; these are lambda functions. I'm using the term "quotation" because I learned about this in Factor where that term is used, but they would be called "closures" in Lisp.

 

Note that Lisp (as usual) over-complicates the subject. In Lisp, the parent's local-frame is stored on the heap. The local-frame can outlive the parent function and closures defined in a function can still be used after that function has gone out of scope; the local-frame only gets GC'd when it is no longer in use anywhere, by either closures defined inside the function or by the function itself. This is grossly inefficient! This is also a solution to a non-problem --- who wants to use closures after the parent function has gone out of scope? In my language, quotations will abort with an error-message if they are used after the parent function has exited. My local-frames are just held on a stack (the Y pointer), which is much more efficient. I won't have GC at all, as this is totally out-of-place in a micro-controller (because it introduces unexpected delays of many milliseconds, and micro-controllers are real-time).

 

How do you know what lambda functions are? You couldn't have learned this in the context of C programming --- you must have learned this in the context of some other language, but C is the only language available for the AVR. 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I don't totally understand why you have 4 byte reserved for stack elements, do you have a special double stack action for 32 bit?

 

Using a "fat stack" is a new idea that I'm trying out for the AVR; I've never heard of this being done before, and I didn't do it in MFX. This slows down stack-juggling words (DUP OVER SWAP etc.) because they have to move 4-byte cells around rather than 2-byte cells. Words like + and D+ only access the data that they need (16-bit or 32-bit respectively), so there is no difference in speed with these. There are some advantages:

1.) I don't need a second set of stack-juggling words (2DUP 2OVER 2SWAP ETC.) as in ANS-Forth, which reduces the size of the kernel and also gives the programmer less to learn.

2.) When single and double values are mixed together on the same stack, as in ANS-Forth, stack-juggling becomes complicated; this is the primary reason why ANS-Forth has a bad reputation being hard-to-read. I avoid this complication entirely.

3.) Reducing the amount of stack-juggling (as described in #1 and #2 above) simplifies optimization considerably. Programs that use a lot of double data may be faster in this scheme than they would in an ANS-Forth-style scheme with all of its excessive and unnecessary stack-juggling.

4.) I only need one stack-pointer (X) for both single and double data (in the ARM version I had separate stacks each with its own stack-pointer). This is important on the AVR because it has a shortage of pointer registers. 

 

sparrow2 wrote:

Where do you put your loop counter(s) it should be in registers I think. 

 

Anywhere from 0 to 3 of the top values on the stack may be held in registers (ROS SOS and TOS). There are up to 16 versions of all the primitives, depending upon how many values they expect to be in registers and how many values they leave in registers, and each of these versions has a cost associated with it. The optimizer chooses the which version to use depending upon which versions were used around it, to minimize the cost of the entire function (it is the "travelling salesman" problem which is intractable, so it is not guaranteed to be a minimal, but should be pretty good).

 

In regard to loop indices or counters or whatever, they will hopefully spend most of their time in registers.

 

I don't have DO loops like in ANS-Forth --- they are horribly over-complicated! --- my language is actually much simpler than ANS-Forth because I remove an order of magnitude more features than I add. Getting rid of the double stack-jugglers (2DUP 2OVER 2SWAP etc.) is just one example of me discarding a lot of cruft.

 

Jeff Fox told me that Charles Moore had made the comment that ANS-Forth was 100 times more complicated than necessary. Not long afterward, the Forth-200x project began --- him and Jeff Fox assumed that the name Forth-200x meant that it would be 200 times more complicated than necessary, which is the logical next step up from being 100x --- only much later on did they discover that the name meant that it was supposed to be released in the 2000 decade. Of course, now it is 2014 and the Forth-200x project is still lurching forward, getting more and more complicated. For example: N>R and NR> are totally useless, and they can be implemented in ANS-Forth in 2 to 5 minutes depending upon the typing speed of the programmer, yet they were put in the standard and now every student who learns Forth-200x has to learn about them too (a "WTF?" moment for most if not all of them).

 

sparrow2 wrote:

What do you mean with fast ISR? for R16-R21 (the AVR don't have SW ISR's if that is what you mean). 

 

I will have two kinds of ISR:

1.) A fastISR is one that is written in assembly-language and it has to use only the ISRxx registers. It does not save and restore registers with PUSH and POP, but it just goes ahead and uses these registers because it is guaranteed that they won't be in use by the main program. Also, a fastISR can't be interrupted by another fastISR because otherwise they would clobber each other's registers. 

2.) A slowISR is one that is written in Forth. This will have to save and restore all of the registers (except the ISRxx registers) with PUSH and POP because all of them are used by Forth. These can interrupt each other --- I assume that the AVR has a hierarchy of interrupts, like most processors.

 

Does C not have anything like my fastISRs? If C doesn't, then I can't either because I need to guarantee that the ISRxx registers aren't being used in the main program that would include both Forth and C code.

 

If C doesn't have fastISRs, then I may just not bother with allowing C functions to be called from Forth --- that would be like tying a boat anchor around my neck! --- a lot of micro-controller programs spend up to 50% of their time in ISRs, so having a fastISR available can boost the speed of the whole system considerably. I can do without C --- if there are any C libraries around that have useful code in them, then they will just have to be ported over to Forth --- are there any?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

what kind of masochist is going to choose the tortured syntax of Forth over C/C++. (as I say, I did a 3rd year university project on Forth implementations so I am quite familiar and short of manacles and hot irons nothing would persuade me to use Forth if I didn't have to

 

clawson wrote:

I expect to generate faster-executing code than C generates.

I simply don't believe you can do that. 

 

...

I think your Forth knowledge is novice-level at best, and likely not even that

Yeah you are probably right. But how long do you have to do something that seems terrible and counter-inutuitive until it starts to become acceptable? Procedural languages like C/C++ just seem "natural" by comparison.

 

You certainly do have strong opinions on a subject that you know nothing about, and you are willing to use strong language against someone who does know about the subject (I've been called an "idiot" before, but you're the first to call me a "masochist") .

 

Anyway, you are on my twit list --- I can really do without your relentless negativity --- if you don't like being on my twit list, then use your authority as a moderator to kick me off the forum.

 

Kartman wrote:

Your programming of Forth is weak and confused, only my programming is true Forth!

 

You're on my twit-list too --- go back to watching "South Park."

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

My Forth will have quotations,

Never heard of them.  Got a pointer to online documentation?

 

I can show you an example. Download my novice package: http://www.forth.org/novice.html

Look at LIST.4TH first. This is an implementation of single-link lists. Look at EACH --- this is a higher-order function. It takes an XT as a parameter and the pointer to the head-node; it traverses the list and EXECUTEs the XT for every node in the list. The idea here is that the list can be any data-type, and EACH will work on it. The XT has to be to a function that is appropriate to the data in the list.

 

Another example is ASSOCIATION.4TH. This is an implementation of an LLRB tree. Once again, we have higher-order functions that take an XT of a function that the EXECUTE for every node in the list.

 

The purpose of all this, is that general-purpose data-structures can be implemented, and they can contain any type of data. The person using the data-structure doesn't have to know how it is implemented, or even have the source-code. Also, the internal workings can be changed. Ffor example, rewrite ASSOCIATION.4TH to use a RB tree rather than an LLRB tree for some extra efficiency, and this won't affect any of the code that uses ASSOCIATION.4TH.

 

In C and ANS-Forth, it is typical to use cut-and-paste to put the data-structure traversing code into the middle of the application program wherever it is needed. This bloats out the source-code for the application program and also introduces a lot of opportunity for error. For example, in my slide-rule program, I use EACH over 30 times. Using traditional techniques, I would have had to cut-and-paste the code for traversing a list that many times. A big mess! With my language, having quotations, the application program will be much simpler --- all that complicated low-level stuff such as the implementation of an LLRB tree, can be hidden away in a library --- the application programmer can use it, without ever looking at the source-code. The application programmer can focus his mind on his application program, without having to concern himself with low-level details regarding esoteric subjects such as LLRB-tree implementation that will only confuse and distract him.

 

Note that I used the term "toucher" for the quotation in the documentation, because I wasn't familiar with the terminology at the time. Also, it is not a true quotation anyway --- it doesn't have access to the parent function's local variables, but it is just a global-scope function --- this limitation is due to the fact that the novice-package was written in ANS-Forth (overcoming this limitation is largely why I'm designing my own language now).

 

Languages such as Factor and Lisp have lambda functions, but they also have dynamic-OOP and GC and other features that make them unsuitable to micro-controllers --- my language will bring lambda functions to the micro-controller world, while leaving behind inefficient ultra-high-level ideas such as dynamic-OOP and GC that can't be used on an 8-bit micro-controller such as the AVR (Slava Pestov told me that the ColdFire was the smallest processor he could imagine Factor running on --- this was when I asked him about porting Factor to the 8-bit eZ80).

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh: After all the verbal harassment you have put up with on various forums over the years, one would think you would a bit thicker skinned than this. As a result, I think you are overly sensitive to anyone that disagrees with you. You are taking some of these comments from some of the most experienced (and helpful) forum members way to seriously. Some of Cliffs comments are little more than hyperbole. (it's just Cliif being Cliff)

 

One of our members has a tag line that says; There are ways to disagree without being disagreeable.

Try it.

 

I personally would like to see more discussions about forth and hope this does not degenerate to the level I have seen on Google groups

 

Rick

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The C compilers I know of don't have registers for the ISR routines, those registers could be spend better(or at least just be lower reg's.). (remember there are at least 4 common used C compilers for the AVR).

 

Just out of curiosity how will C code like this

PORTB |= 0x02 ; //set bit

PORTB&=~0x02; //clear bit

run in your forth. The C compilers just make the SBI and CBI instructions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rick, nicely put. I was about to raise my hand to put a stop to this impending train wreck. Imperious comments like:

How do you know what lambda functions are? You couldn't have learned this in the context of C programming --- you must have learned this in the context of some other language, but C is the only language available for the AVR. 

Well Hugh, for most of us the world doesn't begin and end with the AVR. Many of us are paid professionals that don't sit in little holes and actually create some output. Any spotty kid who has done javascript would know a lambada function or 'closure'.

Your idea of a fastisr might work counter to the requirement of efficiency - allocating a slab of registers for the isr is going to be a tad restrictive. It would work on something like an am29500 style of architecture.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

The C compilers I know of don't have registers for the ISR routines, those registers could be spend better(or at least just be lower reg's.). (remember there are at least 4 common used C compilers for the AVR).

 

Well, PUSH and POP each take 2 cycles, so saving and restoring can be time-consuming. I think a fastISR could boost the speed of a system considerably --- it depends upon the application though, as this is mostly going to help on something that is pushing a lot of data though the I/O and spends most of its time in ISRs. I got this idea from the PIC24 that allows the bottom 4 registers to be swapped out with an alternate set in 1 cycle --- so the PIC24 actually has 20 registers rather than 16, although 16 is all that you can access at any time.

 

The ARM has a similar system, although I don't know ARM assembly well enough to really comment on that. I have a book on ARM assembly-language that says the original inspiration for the ARM was to have fast ISRs. The ARM was an upgrade from the 6502 that has fast ISRs (each ISR has its own section of the zpage, so only the X Y A and P 8-bit registers have to be saved and restored). This was for an upgrade to the BBC Acorn. The MC68000 was considered, but it had way too much interrupt latency (and it drew a lot of current). The 65c816 was tried, but dropped because it was too limited in memory compared to the MC68000 (the 65C816 was actually pretty good for ISR speed and power consumption though). Then the ARM was invented (ARM originally meant "Acorn Risc Machine", but this later got changed to "Advanced Risc Machine" when the Acorn died out) --- the ARM had 32-bit registers and a lot of memory like the MC68000, and it had fast ISRs and low power-consumption like the 6502, so it was the best of both worlds. If the AVR had existed in those days, the Acorn folks might have used it though, and not bothered to invent the ARM. ;-)

 

I put the ISRxx registers in the top so the DES instruction could execute and a fastISR could interrupt it in the middle of what it is doing (DES is pretty time-consuming, so it is likely to get interrupted). This would be a good example of needing a fastISR, because you would be trying to push a lot of data through the AVR as quickly as possible --- all that is necessary is to input and output the data through a buffer --- writing such speed-critical ISRs in Forth would kill the system's speed, and it is not necessary anyway as they are so short and simple that they can be written in assembly-language easily.

 

sparrow2 wrote:

Just out of curiosity how will C code like this

PORTB |= 0x02 ; //set bit

PORTB&=~0x02; //clear bit

run in your forth. The C compilers just make the SBI and CBI instructions.

 

Strictly speaking, that is not C code. You are assuming that the C compiler knows that PORTB is an I/O port rather than a CHAR variable. Unfortunately, neither ANSI-C nor K&R have any way to declare I/O ports. The designers of these standards assumed that C would be used on desktop computers and that all I/O would be hidden away inside of libraries of non-standard code and/or taken care of by the OS. Back in the early 1980s, C was closely associated with Unix --- at that time, I expected that C would always be a mini-computer language, and that Forth would become the micro-computer language --- due to a lack of leadership in the Forth community however, Forth died out and C was contorted to work on micro-computers.

 

Anyway, all Forths have a +! word that adds a cell-sized value to a value in a memory location. Most Forths also have a +B! word that does the same with bytes. My Forth will have these, but will also have logical versions:

and! andB!

or! orB!

xor! xorB!

 

I haven't studied up on AVR I/O yet. Just glancing over the documentation, I get the idea that I/O is memory-mapped and is in the lower 64 bytes. IN and OUT work on all of this. We also have SBI and CBI that you mentioned that only work on the lower 32 ports. True? 

 

I haven't really given a lot of thought to the subject of I/O yet. I wonder if it would be possible to write an API for I/O that would work on any processor and allow programs to be portable with minimal processor-specific code needing to be rewritten for each target? The various processors are different, but there is a lot of similarity between them. I've never heard of any language doing this (maybe ADA does, but I don't know anything about ADA). Unlike the C designers, I'm not assuming that my language will be used on desktop computers or that there will be an OS --- so I can bake in an I/O API if I want to (and if I can think of an way to do it that makes sense).

 

I'll have to give some thought to the idea of an I/O API being part of the language --- I'm open to suggestions --- getting input on questions like this is why I joined this forum, as I don't really have much experience with micro-controller programming myself.

 

P.S. On a related topic, the PIC24 originally had only 8-bit I/O ports, despite the fact that it is a 16-bit processor. Do any new versions have 16-bit I/O ports? 

 

P.P.S. Is there an Ada for the AVR? Just curious --- I'm not really volunteering to learn Ada --- afaik, nobody has ever volunteered to learn Ada, but it is only learned by people who have already been hired by the Pentagon and are required to learn it for their job (not likely to be me!).

 

P.P.P.S. Does anybody care about DES anymore? Or has AES obsoleted it? Are there any processors that have AES baked in, similar to how the AVR has DES baked in?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Strictly speaking, that is not C code. You are assuming that the C compiler knows that PORTB is an I/O port rather than a CHAR variable. Unfortunately, neither ANSI-C nor K&R have any way to declare I/O ports.

 

 

what kind of nonsens is that! PORTB is just a 100% normal volatile pointer. 

 

And why do you want to use DES nearly none of the AVR's have that instruction

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

 

Hugh, you best do some more reading - the interrupt handling on say an Arm7 is somewhat different to a Cortex Mx series. As a historical note, 8051's had 4 switchable register banks which were normally used for fast interrupt handling. The AM29500 had similar tricks with register windows.

Since you've managed to annoy a few of us, lets analyse some of your statements:

 

"Forth would become the micro-computer language --- due to a lack of leadership in the Forth community however, Forth died out and C was contorted to work on micro-computers."

"as I don't really have much experience with micro-controller programming myself."

 

Can we logically assume that based on these statements you don't have much Forth programming experience?? Of course, I am pulling your chain. My conclusion holds about as much water as some of your assertions.

 

If you expect to be dealing with a bunch of C red necks that worship the AVR and don't know one end of cyclomatic complexity from their Turing machines, then you've come to the wrong place. If you stop beating your chest telling us how good your are and how dumb we are, you might get a more favourable reception. I welcome discussion on Forth but not the way you want to discuss it. Stick to the facts and stay away from making sweeping statements. 

 

If I'm on your twit list, then I'm in esteemed company. I would be honoured to work with such twits. If we were twix, would that make us twice as good??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

Strictly speaking, that is not C code. You are assuming that the C compiler knows that PORTB is an I/O port rather than a CHAR variable. Unfortunately, neither ANSI-C nor K&R have any way to declare I/O ports.

 

what kind of nonsens is that! PORTB is just a 100% normal volatile pointer. 

 

VOLATILE is in ANSI-C and it indicates that the memory location may change behind the scenes --- this doesn't necessarily imply that it is an I/O port (afaik, the standard document makes no mention of I/O ports whatsoever) --- another possibility is that it is a semaphore used by the OS.

 

According to the AVR manual, the SBI and CBI instructions only work on the I/O ports, and only on the lower 32 of the total 64 I/O ports. If the C compiler is compiling SBI and CBI, then it must somehow know that PORTB is one of the lower 32 I/O ports --- presumably there was some kind of declaration for PORTB other than VOLATILE that indicated this, or VOLATILE has been overloaded to imply more than the standards says that it implies --- either way, this is a non-standard extension of C.

 

sparrow2 wrote:

And why do you want to use DES nearly none of the AVR's have that instruction

 

DES just seemed pretty cool --- also, I'm interested in point-of-sale terminals, where encryption is required.

 

The documentation says that a lot of the instructions are not available on all versions of the AVR (PUSH and POP for example). I have no idea what is common or uncommon --- I'm writing a cross-compiler that I hope will be used on a wide variety of AVR chips, so I'm trying not to exclude very many chips. For example, I'm making >R R@ R> etc. an optional extension to my language, so that they will only be provided in versions of the cross-compiler for AVR chips that have PUSH and POP instructions --- making them an optional extension is a big hint to the programmer that if he wants a portable program, he ought not to use them, or at least that he checks that they are available on every chip-specific version of the compiler that he ever expects to work with.

 

C doesn't have optional extensions, which makes life difficult for compiler writers --- you can't just let the camel stick his head inside the tent, but you have to let the whole camel in.

 

BTW: Forth programmers are always arguing about whether particular Forth programs are ANS-Forth or not, or if a compiler is ANS-Forth compliant or not. This is a major preoccupation of ANS-Forth programmers, and everybody is expected to know the ANS-Forth standards document by heart --- do C programmers not particularly care if their programs are ANSI-C or not?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:

Note that Lisp (as usual) over-complicates the subject. In Lisp, the parent's local-frame is stored on the heap. The local-frame can outlive the parent function and closures defined in a function can still be used after that function has gone out of scope; the local-frame only gets GC'd when it is no longer in use anywhere, by either closures defined inside the function or by the function itself. This is grossly inefficient! This is also a solution to a non-problem --- who wants to use closures after the parent function has gone out of scope?

It's a common practice in Lisp to use a function long after its parent has gone out of scope. For example, a function could return an iterator or generator function that behaves differently depending on the arguments passed to the parent function.

 

(defun create-iterator (start)
  (lambda () (let ((current start)) (incf start) current)))

 

This very simple example defines a "create-iterator" function that returns a function that returns a number one higher than the previous each time it's called, starting at the number given as an argument to the create-iterator function. This simple idea can be extended to retrieve the next item in a list, the next result in a database query, the next card in a deck of cards, the next (pseudo-)random number, etc. A real-world example is a regular-expression library called CL-PPCRE, which has a function that compiles a regular expression from a string to some internal format and returns a function that can be used to match strings against that regular expression. That's just the tip of the iceberg when it comes to higher-order functions.

 

If you couldn't use a function after its parent function goes out of scope, you would have to pass some context as an argument to a statically-defined function every time you call it, which is something you lament about C. You also couldn't use a lambda function as a callback if it can possibly be called outside the scope of the containing function. Again, you'd have to use a statically-defined function as a callback function with separate context instead. A closure's environment is little more than the same context that you have to lug around one way or another anyway. So it's six of one or half-dozen of the other. I prefer the way it's done transparently and automatically as in Lisp.

 

The ability to use a function outside the scope of its parent makes it easy to make objects--which contain both data and behavior--somewhat like you would find in many OOP languages; in fact some OO systems in languages like Lisp are built out of closures, as closures are a very powerful primitive.

 

Common Lisp fully supports both types of higher-order function (one that can take a function as input or return a function), whereas from your descriptions, Forth quotations seem to support only functions that take a function as input.

 

Hugh Aguilar wrote:

How do you know what lambda functions are? You couldn't have learned this in the context of C programming --- you must have learned this in the context of some other language, but C is the only language available for the AVR.

I and many others here are not limited to C on AVRs (and C is not the only language available for the AVR, by the way). I'm familiar with a range of languages--C, BASIC (C64 BASIC and QBASIC), Java, assembly languages (68k, Z80, x86), Perl, Common Lisp, Bash, PostScript, JavaScript, etc. I learned about lambda functions from Lisp, though I probably used closures and lambda functions in JavaScript before I understood that's what they were.

 

Lisp may be larger than Forth, but there's an implementation of Scheme (a dialect of Lisp) called PICOBIT that can run on 8-bit microcontrollers with less than 20 kB of ROM. This includes support for closures, a dynamic garbage collector, and even multithreading! The PICOBIT authors also wrote a network stack (TCP, UDP, ARP) in Scheme that takes up only 3.1 kB and a tiny Web server that takes about 1 kB of program space when compiled with PICOBIT. Granted, PICOBIT runs in a VM that takes about 15kB of ROM (more or less depending on which features, such as floating-point, are built in), but according to the PICOBIT whitepapers you can get about a 3:1 size reduction in program size compared to an equivalent C program thanks to the compact PICOBIT bytecode.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:

According to the AVR manual, the SBI and CBI instructions only work on the I/O ports, and only on the lower 32 of the total 64 I/O ports. If the C compiler is compiling SBI and CBI, then it must somehow know that PORTB is one of the lower 32 I/O ports --- presumably there was some kind of declaration for PORTB other than VOLATILE that indicated this, or VOLATILE has been overloaded to imply more than the standards says that it implies --- either way, this is a non-standard extension of C.

From what I understand, PORTB is a preprocessor macro, defined in a header file for the specific AVR model, that expands to basically an appropriately-typed address reference, something like *(volatile unsigned char *)0x10 (I don't know off the top of my head how PORTB actually is defined but it should be similar to that). The compiler knows that it can use SBI and CBI instructions on all addresses below 0x20, so it does. It doesn't have to know anything else about the address. This is a kind of thing that any C compiler might do as an optimization for any architecture that has inconsistencies or special cases in their instruction sets. It's not an extension to the language because there's no change to the language itself.

 

There are actual non-standard extensions to the language itself, such as __attributes__, but these are necessary to alter the normal handling of functions or objects. One attribute is "naked" when applied to an ISR function to tell the compiler not to add the regular ISR function prologue and epilogue (the prologue and epilogue in most cases Do The Right Thing, but in some cases a programmer needs to leave them off). ISRs in particular are non-portable anyway, so there's little risk in making a program non-portable by using a "naked" ISR.

 

Hugh Aguilar wrote:

BTW: Forth programmers are always arguing about whether particular Forth programs are ANS-Forth or not, or if a compiler is ANS-Forth compliant or not. This is a major preoccupation of ANS-Forth programmers, and everybody is expected to know the ANS-Forth standards document by heart --- do C programmers not particularly care if their programs are ANSI-C or not?

I for one care whether my programs are standards-compliant and portable. My C programs are almost always standard and portable to other systems, except for a few bits (such as ISRs) that aren't going to be portable across systems anyway. Those bits can usually be modified or rewritten for another system. The rest are modules (such as linked lists or somesuch) that can be used on other systems unmodified. (That's a big reason I don't like to write assembly language most of the time, even for such small systems.)

Last Edited: Fri. Oct 31, 2014 - 12:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

They should not allow computer scientists to document languages:

A quotation is a sequence of literals and words. Quotations do not close over any lexical environment; they are entirely self-contained, and their evaluation semantics only depend on their elements, not any state from the time they were constructed. So quotations are anonymous functions but not closures.

Sheesh!  (and such clever naming.  I mean, a web seach for "forth quotation" leads you right to a description of the concept, rather that to a bunch of Shakespere.  Not!)  I guess I thought that this sort of thing was fundamental to Forth and Lisp (and more kludgey in C); being able to pass around code (or pointers to code) as data (anonymous code being less important?)

 

 PORTB is just a 100% normal volatile pointer. 

I don't see how you can say that, since the code generator has to pick one of three different ways of accessing the data, depending on the value and type (constant or not) of the pointer (and the value of the operand and the operation being performed.)

OTOH, you could accurately say "that's just an optimization issue.")

 

I get the idea that I/O is memory-mapped and is in the lower 64 bytes.

IO is memory mapped, but it's more complicated than that.

ALL IO registers are accessible via the memory instructions, load/store.  This includes the IO beyond the first 64 bytes (newer bigger AVRs have up to 512 byte allocated for IO registers.) (LD/ST - two cycles each.)

The first 64 bytes are (additionally) accessible (more quickly) via IN/OUT instructions. (one cycle each)

The first 32 bytes are (additionally) accessible via some bit set/clear/test instructions.  (two cycle atomic instructions to set/clear any single bit.)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:

Hugh Aguilar wrote:

 

Note that Lisp (as usual) over-complicates the subject. In Lisp, the parent's local-frame is stored on the heap. The local-frame can outlive the parent function and closures defined in a function can still be used after that function has gone out of scope; the local-frame only gets GC'd when it is no longer in use anywhere, by either closures defined inside the function or by the function itself. This is grossly inefficient! This is also a solution to a non-problem --- who wants to use closures after the parent function has gone out of scope?

 

It's a common practice in Lisp to use a function long after its parent has gone out of scope. For example, a function could return an iterator or generator function that behaves differently depending on the arguments passed to the parent function.

 

(defun create-iterator (start)
  (lambda () (let ((current start)) (incf start) current)))

 

This very simple example defines a "create-iterator" function that returns a function that returns a number one higher than the previous each time it's called, starting at the number given as an argument to the create-iterator function. This simple idea can be extended to retrieve the next item in a list, the next result in a database query, the next card in a deck of cards, the next (pseudo-)random number, etc. A real-world example is a regular-expression library called CL-PPCRE, which has a function that compiles a regular expression from a string to some internal format and returns a function that can be used to match strings against that regular expression. That's just the tip of the iceberg when it comes to higher-order functions.

 

If you couldn't use a function after its parent function goes out of scope, you would have to pass some context as an argument to a statically-defined function every time you call it, which is something you lament about C. You also couldn't use a lambda function as a callback if it can possibly be called outside the scope of the containing function. Again, you'd have to use a statically-defined function as a callback function with separate context instead. A closure's environment is little more than the same context that you have to lug around one way or another anyway. So it's six of one or half-dozen of the other. I prefer the way it's done transparently and automatically as in Lisp.

 

The ability to use a function outside the scope of its parent makes it easy to make objects--which contain both data and behavior--somewhat like you would find in many OOP languages; in fact some OO systems in languages like Lisp are built out of closures, as closures are a very powerful primitive.

 

Common Lisp fully supports both types of higher-order function (one that can take a function as input or return a function), whereas from your descriptions, Forth quotations seem to support only functions that take a function as input.

 

We already have :NONAME in ANS-Forth (I'll have it too) that defines an anonymous function; its XT can be passed around as a parameter. Also, named colon words have an XT that can be passed around as parameters (as I do with my pseudo-quotations in the novice package). All of these can have local variables in the usual way. It is a common technique to store XTs in structs to provide some OOP-like "methods" for that struct --- also jump tables (an array of XT values) are common.

 

Doesn't this do most of what you are describing can be done with a closure after its parent has gone out of scope? It seems over-complicated and inefficient to do this with closures that are holding their local variables in a heap struct that will eventually need to be GC'd.

 

I don't know what generators are in Lisp (I don't really know all that much Lisp). In Icon (http://www.cs.arizona.edu/icon/i...), we had generators that would pause in the middle of execution and let another function execute for a while, and then they would take up again where they left off when they were executed again. Is this what you are describing in Lisp? In this case, :NONAME isn't going to work. I'm not really sure if my quotations could be rigged to do this --- I haven't given the subject any thought --- Icon was interesting, but it was also somewhat high-level for me, and I never really got into it. I have coroutines in the novice package, but I don't see that they do anything that couldn't be done much more simply with ye olde colon words --- the subject pretty much baffled me, at least in regard to how to make it do anything useful in Forth.

 

I won't say that Lisp-style closures have no purpose at all; maybe they do, and I just haven't gotten far enough into Lisp to figure that out --- I just don't think this stuff has any place in a real-time micro-controller --- GC is a non-starter for me, as it is very unForth-like, and it introduces sporadic delays that wreak havoc with a real-time system. Maybe Lisp-style closures are cool in their own way, but I don't intend to implement anything like that --- I'm just going to do a very straightforward implementation in which the quotations abort with an error-message if they are executed after the parent has gone out of scope --- all I'm trying to accomplish is to allow for general-purpose data-structures similar to my LIST.4TH and ASSOCIATION.4TH, but smoothed over a lot. I'm competing against C, not Lisp! ;-)

 

christop wrote:

Lisp may be larger than Forth, but there's an implementation of Scheme (a dialect of Lisp) called PICOBIT that can run on 8-bit microcontrollers with less than 20 kB of ROM. This includes support for closures, a dynamic garbage collector, and even multithreading! The PICOBIT authors also wrote a network stack (TCP, UDP, ARP) in Scheme that takes up only 3.1 kB and a tiny Web server that takes about 1 kB of program space when compiled with PICOBIT. Granted, PICOBIT runs in a VM that takes about 15kB of ROM (more or less depending on which features, such as floating-point, are built in), but according to the PICOBIT whitepapers you can get about a 3:1 size reduction in program size compared to an equivalent C program thanks to the compact PICOBIT bytecode.

 

I'll look into PICOBIT. I'm always willing to learn new things, and it sounds pretty cool. Does this run on the AVR? Is there a list somewhere of all the languages that are available for the AVR? 

 

At Testra they made the MiniForth; it was a "Forth engine" that ran Forth largely in hardware. Some guys at one time approached them on the subject of building a "Lisp engine" that would run Lisp largely in hardware. The customer backed out of the project and it never got off the ground. I have read about Lisp-engines being built, but I've never met anybody who actually had experience with such a thing. It is an interesting idea though!

 

P.S. Does any AVR chip support TCP/IP or USB?

 

P.P.S. Does anybody care about floating-point on the AVR? I originally planned on supporting this, but I have since decided to forget about it on the AVR and wait until I do the PIC24 implementation. I've never actually heard of anybody using floating-point in any micro-controller application, but I suppose somebody uses it somewhere.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

christop wrote:

 

Hugh Aguilar wrote:

According to the AVR manual, the SBI and CBI instructions only work on the I/O ports, and only on the lower 32 of the total 64 I/O ports. If the C compiler is compiling SBI and CBI, then it must somehow know that PORTB is one of the lower 32 I/O ports --- presumably there was some kind of declaration for PORTB other than VOLATILE that indicated this, or VOLATILE has been overloaded to imply more than the standards says that it implies --- either way, this is a non-standard extension of C.

From what I understand, PORTB is a preprocessor macro, defined in a header file for the specific AVR model, that expands to basically an appropriately-typed address reference, something like *(volatile unsigned char *)0x10 (I don't know off the top of my head how PORTB actually is defined but it should be similar to that). The compiler knows that it can use SBI and CBI instructions on all addresses below 0x20, so it does. It doesn't have to know anything else about the address. This is a kind of thing that any C compiler might do as an optimization for any architecture that has inconsistencies or special cases in their instruction sets. It's not an extension to the language because there's no change to the language itself.

 

It is not an "extension" to C, because it doesn't add any new words. It is very non-standard though, because it implies that certain addresses are I/O ports, whereas the standard doesn't say anything about I/O ports at all. A person who knows C and reads this code, is not going to know that in some cases this is I/O and in some cases this is memory, unless he already knows assembly-language --- but if he knows assembly-language, then why not just write the program in assembly-language? What is the point of using a high-level language if it is going to have all this carnal knowledge embedded in it?

 

I could do what you are describing --- have my andB! and orB! figure out that they should use SBI and CBI when they are given an address that is known at compile-time, and is in the correct range. This is terrible language design though! Charles Moore's proverb is: "Let the dictionary do the deciding." This means, that every word should do only one thing (and hopefully do it well!).  Words don't do different things depending upon different circumstances (compile different code depending upon if the address is known at compile-time, and what that address is). The programmer decides what he wants done and uses the appropriate word. So, I would feel much better about having Forth words called SBI and CBI that compiled these assembly-language instructions --- that way the programmer knows exactly what he is getting -- also, if he uses these outside their I/O area, his compilation will abort with an error message, so he knows about the bug right away and can fix it. In Forth, it is very bad style to have a word that examines its parameters and does different things depending upon what they are (usually accomplished with IF statements or a CASE statement) --- there are some exceptions (I already mentioned that jump tables were used sometimes) --- for the most part however, this is a big philosophical difference between Forth and C, that in Forth every word is supposed to do only one thing, and you have different words with different names to do different things. This btw, is also why I consider dynamic-OOP to be the anti-thesis of Forth, and why I'm not much interested in Factor and Lisp (and Python, Ruby, etc.) that are all dynamic-OOP.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

P.S. Does any AVR chip support TCP/IP or USB?

 

All AVRs could possibly run tcp/ip of some form. It is software. If you meant Ethernet, then no AVR8 has ethernet hardware on chip, however, it is reasonably common to connect ethernet MAC chips as well as ethernet co-processors (like wiznet). Certain members of the AVR8 support USB either as host or device.

 

P.P.S. Does anybody care about floating-point on the AVR? I originally planned on supporting this, but I have since decided to forget about it on the AVR and wait until I do the PIC24 implementation. I've never actually heard of anybody using floating-point in any micro-controller application, but I suppose somebody uses it somewhere.

It is not uncommon to use floating point. With the processor performance these days, the 'cost' of floating point has dropped. Years ago I would actively avoid FP, now I would weigh up the cost to determine if it is acceptable.

 

If you want an idea of what uses people put the AVR to, Google Arduino. That should give you a cross section of applications that an AVR8 class of cpu is used for.

 

It is not uncommon to run a pre-emptive RTOS on the larger AVRs. As for 'real time' - that is a rather nebulous term. One application might be sub microsecond in regards to determinism whereas another might be ms. I did a lot of industrial control apps that flashed lights, clicked relays and got input from switches. Real time for these was in the 10's of ms.

 

What languages are available for the AVR? Basic, C,C++,Pascal, Forth, ADA and probably more. What do most people use? asm,C,C++ methinks.

With the cost of AVRs rising and the bigger Cortex Mx ARMs becoming cheaper, languages such as Javascript,Lua and Java are emerging. Nevertheless, I'd hazard to suggest that in this class that C/C++ dominates - especially where the vendors give out free toolsets for C/C++ with RTOS, filesystem, tcp/ip/ usb etc. People follow the path of least resistance. Unless you can dangle a big carrot with Forth, I doubt it will gain traction.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

The first 32 bytes are (additionally) accessible via some bit set/clear/test instructions.  (two cycle atomic instructions to set/clear any single bit.)

 

Is there any RTOS available for the AVR? I'm undecided if I want to support an RTOS in my language, as I've never used an RTOS and don't really know much about the subject.

 

Also, I don't know what the T flag in SREG is for. The documentation I read didn't make this clear, at least to me.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

T 'transfer' flag. general purpose flag. Supported by a handful of instructions.

Is there any RTOS for the AVR? How many do you want? One of the more popular RTOS's is freertos.

 

Google AVR + whatever you want to know

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does any AVR chip support TCP/IP or USB?

Is there any RTOS available for the AVR?

Does anybody care about floating-point on the AVR?

Yes, to all of the above.  Maybe you should read up on "Arduino", one of the big microcontroller "development model" successes of the last decade, who figured out what a lot of people wanted to do and made it easier, rather than creating a "better" IDE/Language/compiler using the usual "if I make it, they will come" model.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Kartman,  its funny I had the exact same thoughts last night. Nothing like showing up, proclaiming oneself to be a genius with a very thin skin on one hand, and quite dismissive/blunt on the other. I thought Asbergers as well....

 

I did have the same thought though.  Back 20 years ago, even then, the C compilers were rather crude, and I wouldn't be surprised if honed Forth could occasionally beat it. Nowadays, I'd ask to see proof before accepting anyone's say so.  FWIW, I've been hanging out at Parallax forums for the Prop and Prop2.  While watching it go through redesign after redesign, I've been looking at picking up Forth.

They've got 3 distro, with one being mostly ANS compliant, one being a true speed demon, and another in the middle.

The interactive nature of it sure seems cool, however the RPN mind-blending just seems to be antithetical to any sort of RAD.

 

 

Last Edited: Fri. Oct 31, 2014 - 08:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fred, it's a cross i bear. 

I'm always interested in looking at other methods and techniques to solve problems. Having looked at javascript and lua on cortex m3 class processors recently to get a feel for what they offer, a fresh look at Forth might be in order. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:

It is not an "extension" to C, because it doesn't add any new words. It is very non-standard though, because it implies that certain addresses are I/O ports, whereas the standard doesn't say anything about I/O ports at all. A person who knows C and reads this code, is not going to know that in some cases this is I/O and in some cases this is memory, unless he already knows assembly-language --- but if he knows assembly-language, then why not just write the program in assembly-language? What is the point of using a high-level language if it is going to have all this carnal knowledge embedded in it?

Memory-mapped I/O is not that unusual, and any programmer who can write low-level software to drive hardware should be familiar with the concept.

 

If you look at the history of C, you'll find that it was originally used to implement Unix on the PDP-11. The PDP-11 architecture had memory-mapped I/O ports much like the AVRs do today, and the device drivers found in Unix used the same technique of using preprocessor macros to hide the actual device I/O addresses behind the scenes. The compiler of the day did essentially what they do today when it encountered an I/O port access--it emits code to access the memory just the same as it does for a "regular" memory location. I don't know a whole lot more about the PDP-11, such as whether it had any "special" regions of its address space that can be accessed with fewer instruction cycles, but that's beside the point. AVRs do have special addresses where some instructions are valid (such as CBI and SBI in the lower 32 bytes), and the C compiler backends take advantage of that as a matter of optimization. If the AVR didn't have those special areas, the compilers wouldn't have anything to take advantage of and would treat it like any other memory access.

 

Anyway, the I/O port definitions really are not part of the language. They're part of the library that Atmel created to go with the compiler suite for the convenience of us programmers. They could have been exported as functions instead (as they are in Arduino--see the digitalWrite and analogRead functions), but it's much smaller and faster to read from or write to a one-byte register than to call a function that does the same thing. Either way, the I/O ports are documented, and as I said, low-level software programmers should be familiar with how they work. If you actually do release a Forth compiler for AVR, wouldn't you add a support library for that kind of functionality too? Would you also call that library an "extension" to the Forth language?

 

Hugh Aguilar wrote:

I could do what you are describing --- have my andB! and orB! figure out that they should use SBI and CBI when they are given an address that is known at compile-time, and is in the correct range. This is terrible language design though! Charles Moore's proverb is: "Let the dictionary do the deciding." This means, that every word should do only one thing (and hopefully do it well!). Words don't do different things depending upon different circumstances (compile different code depending upon if the address is known at compile-time, and what that address is). The programmer decides what he wants done and uses the appropriate word. So, I would feel much better about having Forth words called SBI and CBI that compiled these assembly-language instructions --- that way the programmer knows exactly what he is getting -- also, if he uses these outside their I/O area, his compilation will abort with an error message, so he knows about the bug right away and can fix it. In Forth, it is very bad style to have a word that examines its parameters and does different things depending upon what they are (usually accomplished with IF statements or a CASE statement) --- there are some exceptions (I already mentioned that jump tables were used sometimes) --- for the most part however, this is a big philosophical difference between Forth and C, that in Forth every word is supposed to do only one thing, and you have different words with different names to do different things. This btw, is also why I consider dynamic-OOP to be the anti-thesis of Forth, and why I'm not much interested in Factor and Lisp (and Python, Ruby, etc.) that are all dynamic-OOP.

I'm getting the impression that Forth is like an assembly language for a generic stack-based machine. Anything you do in assembly language is usually directly mapped to an actual machine instruction, and it doesn't try to do anything "fancy" under the hood. Does that describe a Forth program well? I can see the benefits and appeal to that, where higher-level languages don't even let you play with the stack(s) directly. On the other hand, high-level languages generally do a good job at hiding complexity that I believe the programmer shouldn't have to deal with themselves, such as how to pass function arguments and keeping track of local variables and the like, and let the programmer deal with high-level concerns such as data flow and overall program design. In the case of C, the existing compilers usually does a very good job at picking the smallest or fastest instruction or sequence of instructions for any given high-level operation. Since a compiler can do such a good job at hiding this mundane "carnal knowledge" of the architecture from me as a programmer, I prefer that it does.

 

Regarding PICOBIT, I haven't played around with it too much, and it doesn't seem to be going anywhere recently. There's just not much interest in both Scheme and AVRs, I guess. :(

 

I also discovered another Lisp system for the Lego MindStorms called XS Lisp. It uses more memory than PICOBIT (the MindStorms has 32 kB of ROM and 32 kB of RAM), but it also has an interactive REPL. Removing that interactivity may reduce its memory requirements quite a bit.

Last Edited: Fri. Oct 31, 2014 - 11:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm getting the impression that Forth is like an assembly language for a generic stack-based machine.

Sort of.  But only if most programmers of the assembly language used a standard library of high-level macros, and the standard development methodology involved writing more high-level macros.  If you start to study Forth, you get exposed to the low-level "words" that are like you "stack machine assembly", but I'm pretty sure that that's how most Forth programmers actually write code.

 

Postscript (which is very Forth-like) is probably a good example.  You wouldn't think that a "low-level" language like Forth would be usable for doing page layout, but ... it actually works pretty well, by the time you have "words" like "findfont" and "clippath".

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

Does any AVR chip support TCP/IP or USB?

Is there any RTOS available for the AVR?

Does anybody care about floating-point on the AVR?

Yes, to all of the above.  Maybe you should read up on "Arduino", one of the big microcontroller "development model" successes of the last decade, who figured out what a lot of people wanted to do and made it easier, rather than creating a "better" IDE/Language/compiler using the usual "if I make it, they will come" model.

 

 

Well, I looked at the Arduino site and clicked on the "What is Arduino?" button. This is what it said:

"Arduino is an open-source electronics platform based on easy-to-use hardware and software. It's intended for anyone making interactive projects."

 

The "projects" they have in mind are: "The making of an animatronic baby alien," "Control your Halloween props with Arduino," etc.. Pretty fun stuff if I were 15! When I was 15 though, I didn't have the money for expensive hobbies like this, so it would have been lost on me then too. That kind of thing could have been done on the 65c02 in the 1980s when I would have enjoyed it, although the baby alien might move as if it were constipated --- the AVR is a better baby-alien than the 65c02 ever was.

 

I'm expecting my language to be used for real-world stuff. MFX was used for motion-control boards. These were in a laser etcher; it couldn't have any delay when it changed direction, because the laser would burn a hole in the material, so it had to be able to change directions extremely quickly. That was 20 years ago, and the AVR doesn't have this kind of performance even today (although the PIC24 does). Anyway, the AVR is a stepping-stone toward more powerful processors that can be used in the real world --- I'm primarily interested in the AVR because it is the last 8-bit chip, so if my language can work on the AVR, it can work on anything --- it is intended to be a proof-of-concept.

 

I've never heard of any language providing lambda functions in the micro-controller world --- I don't think that "reading up" is going to help me at all; I have to just write it myself. MFX was similar --- "reading up" wouldn't have helped, because it was something new; I had to just write it myself. 

 

Since you guys are into having fun (nice hair, btw), I hope that you can have fun with my language --- the AVR version is just for fun --- versions for other processors will be commercial.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I'm getting the impression that Forth is like an assembly language for a generic stack-based machine.

Sort of.  But only if most programmers of the assembly language used a standard library of high-level macros, and the standard development methodology involved writing more high-level macros.  If you start to study Forth, you get exposed to the low-level "words" that are like you "stack machine assembly", but I'm pretty sure that that's how most Forth programmers actually write code.

 

For a long time, I thought of Forth as being a kind of macro-assembly-language. In my 65c02 cross-compiler, each word just generated a sequence of 65c02 instructions much as a macro would do, except that there was some peephole-optimization between the words. I had my own 65c02 assembler underneath, so I was generating machine-code --- I wasn't generating a source-file for an assembler, like I'm doing now --- if I was going to have an interactive AVR system, then I would need to write my own AVR assembler in Forth so I could go straight to machine-code and be able to run the words in the REPL immediately.

 

Nowadays I'm more interested in optimization, which involves generating an intermediate code. This also implies portability, because the intermediate code can be retargeted to a different processor fairly easily --- most of the job is in writing the high-level that works with the intermediate code --- the low-level job of converting intermediate code into an assembly-language source-file is simple and straightforward.

 

Anyway, I had mentioned Charles Moore's proverb: "Let the dictionary do the deciding." This is about philosophy, not code generation. Making each word do one thing, rather than different things depending upon the context that it is called in, is about making the language simple and understandable. I would never overload a word to do both storing data into memory variables, and accessing I/O ports, because these are totally different concepts. C overloads a lot of words to mean different things in different contexts; it is actually one of the worst languages for that. In Forth, every word just means one thing, and there is very little context-sensitivity.

 

I'm still interested in designing an API for micro-controller I/O. The idea is that abstract concepts such as parallel ports and serial ports etc. would be represented, and this would be portable between processors. The library internals would have to be rewritten for each processor, but the application programmer wouldn't be exposed to the low-level processor-specific nuts-and-bolts. When I suggested CBI and SBI words in Forth, I didn't really mean that they would be AVR-specific --- I meant that the would be abstractions of the concept, that would generate processor-specific code internally for a variety of processors --- these concepts are common to all micro-controllers, pretty much. As I said in my previous post, I don't want to make a career out of the AVR, or any other processor for that matter --- I want the programs to be portable between processors. I'm not aware of any language that offers any kind of portability of programs in the micro-controller world --- C totally exposes the hardware to the user; it is not abstractifying the hardware at all.

 

When I left available the ISRxx registers for the fastISR or RTOS, I was doing something that has never been done before. AFAIK, every language just grabs up all the resources of the processor for itself --- then later on somebody wants to write an ISR or an RTOS and they have to save-and-restore the entire processor state because they can't be guaranteed that any of the resources haven't already been used by the main-program --- that isn't cool!

 

westfw wrote:

Postscript (which is very Forth-like) is probably a good example.  You wouldn't think that a "low-level" language like Forth would be usable for doing page layout, but ... it actually works pretty well, by the time you have "words" like "findfont" and "clippath".

 

I learned a little bit of PostScript when I wrote my slide-rule program. I didn't like PostScript and didn't feel inspired to learn more. It is totally different from Forth in philosophy. Other than the parameter stack, there isn't much similarity at all. I also learned Factor because I thought that it would be Forth-like as it also has a parameter-stack, but it was also totally different from Forth in philosophy. I learned a lot of good ideas from Factor, so I'm not saying that Factor is a bad language --- but I didn't feel inspired to continue in Factor either --- if I was going to get into dynamic-OOP, I would go with Racket or CLOS, but I'm not really much inspired toward any of this ultra-high-level programming stuff.

 

BTW: The idea of Forth written in Scheme has already been done: http://zwizwa.be/staapl/staapl.html

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems there's a lot you haven't heard of. Lua provides lambda functions as does javascript. We've coped without lambda functions in C for many years, how are these going to be of great benefit in an embedded system?

The AVR being the last 8 bit processor? The HCS12x comes to mind as post AVR, as does the PIC18. There's probably others.

 

Hugh, you seem to mix the concepts of the language and the implementation. The use of registers is implementation specific - it's not mandated by the language. Imagecraft for AVR allows you to set aside a couple of registers so you could possibly handcraft isrs using assembler. The general concept of RISC was to have large number of registers to avoid expensive memory read/writes. Allocating a chunk of regs for exclusive isr use means it costs you in performance for the mainline code. Of course, this is a tradeoff. The general push these days is to avoid the use of assembler - the use of assembler obviously is optimal for performance but works against portability. In the days of the 6502 you had little choice. Now we have the choice of multi-hundred MHz micro controllers with FP support in hardware and lots of ram.

Using intermediate code means you use a 'one size fits all' tradeoff that means you need architecture specific optimisations - why not just generate architecture specific code to begin with? We had the UCSD P System many moons ago that promised a lot - that died and a few years and the idea of intermediate code was resurrected with Java. At this point we weren't too worried about code or size efficiency as we had fast processors with lots of ram. Now we have a number of languages based on intermediate code execution. A number of these have been ported to micro controllers - there's Java that runs on the Lego Mindstorm controllers. Thus for a number of applications, the requirement of absolute efficiency is secondary. The processors are fast enough to cover the in-efficiency - even in micro controllers. Applications that once were coded using hand crafted assembler on 1 and 2 MHz micro controllers no can run on processors at 10 or 100 times the clock rate and coded in C (or other higher level languages). The net result is the same - the job performed is similar. The advantages are the ability to run numerous tools to check and simulate the code and the ability to move to another architecture without much effort (hardware differences aside).

 

As for the language abstracting the i/o, should that not be the responsibility of the language or libraries managed by the IDE? Arduino uses the latter approach - it has a raft of 'standard' libraries that implement the abstraction you talk of. This has been ported to a number of different processors and architectures. The IDE manages this and hides the evil. Behind the scenes it is just C/C++. MBED does a similar thing but the IDE manages the libraries rather than hides the evil. Both these IDEs are free with Arduino being 100% open source and MBED closed source for the compiler and ide. The libraries are open source for the most part. Libraries like Atmel's ASF attempt to abstract the hardware. So, I think you're trying to solve a problem that has been solved already and trying to mix in a language that is not popular. It's hard to see where the value add is here.

 

Last Edited: Sat. Nov 1, 2014 - 07:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How do ASM2 and the C compiler generate debug-information for the debugger? I might be able to do that with my cross-compiler, so I could do source-level debugging of Forth code in Atmel's debugger. I assume there is a file generated along with the executable file that includes pointers to machine-code associated with pointers to source-code. Is there documentation somewhere as to what format this file is supposed to be in?

 

When I wrote my 65c02 cross-compiler, I also wrote a source-level debugger for it. I was able to single-step through Forth code and see my source-code as I was doing it. I don't really like debuggers, and now I would rather have a REPL --- still though, a debugger is better than nothing, and Atmel Studio does have a debugger already, so I might was well take advantage of it.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh, i believe it is in the ELF file.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I assume there is a file generated along with the executable file that includes pointers to machine-code associated with pointers to source-code. Is there documentation somewhere as to what format this file is supposed to be in?

avr-gcc uses DWARF2 (at present).

 

I don't think Atmel document the debug format for Asm2 though.

 

For avr-gcc just specify -save-temps when you build and each .c file will result in a generated .s file. In this example the simplest of avr.c files was compiled to create avr.s:

#include <avr/interrupt.h>

uint64_t foo = 0xBABEFACEDEADBEEF;

int main(void) {
}
	.file	"avr.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
	.text
.Ltext0:
	.cfi_sections	.debug_frame
	.section	.text.startup,"ax",@progbits
.global	main
	.type	main, @function
main:
.LFB0:
	.file 1 "avr.c"
	.loc 1 5 0
	.cfi_startproc
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
	.loc 1 6 0
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
.global	foo
	.data
	.type	foo, @object
	.size	foo, 8
foo:
	.byte	-17
	.byte	-66
	.byte	-83
	.byte	-34
	.byte	-50
	.byte	-6
	.byte	-66
	.byte	-70
	.text
.Letext0:
	.file 2 "/home/uid23021/windows/avr8-gnu-toolchain-linux_x86_64/avr/include/stdint.h"
	.section	.debug_info,"",@progbits
.Ldebug_info0:
	.long	0x95
	.word	0x2
	.long	.Ldebug_abbrev0
	.byte	0x4
	.uleb128 0x1
	.long	.LASF7
	.byte	0x1
	.long	.LASF8
	.long	.LASF9
	.long	.Ldebug_ranges0+0
	.long	0
	.long	0
	.long	.Ldebug_line0
	.uleb128 0x2
	.byte	0x1
	.byte	0x6
	.long	.LASF0
	.uleb128 0x2
	.byte	0x1
	.byte	0x8
	.long	.LASF1
	.uleb128 0x3
	.byte	0x2
	.byte	0x5
	.string	"int"
	.uleb128 0x2
	.byte	0x2
	.byte	0x7
	.long	.LASF2
	.uleb128 0x2
	.byte	0x4
	.byte	0x5
	.long	.LASF3
	.uleb128 0x2
	.byte	0x4
	.byte	0x7
	.long	.LASF4
	.uleb128 0x2
	.byte	0x8
	.byte	0x5
	.long	.LASF5
	.uleb128 0x4
	.long	.LASF10
	.byte	0x2
	.byte	0x81
	.long	0x65
	.uleb128 0x2
	.byte	0x8
	.byte	0x7
	.long	.LASF6
	.uleb128 0x5
	.byte	0x1
	.long	.LASF11
	.byte	0x1
	.byte	0x5
	.byte	0x1
	.long	0x37
	.long	.LFB0
	.long	.LFE0
	.byte	0x3
	.byte	0x92
	.uleb128 0x20
	.sleb128 2
	.byte	0x1
	.uleb128 0x6
	.string	"foo"
	.byte	0x1
	.byte	0x3
	.long	0x5a
	.byte	0x1
	.byte	0x5
	.byte	0x3
	.long	foo
	.byte	0
	.section	.debug_abbrev,"",@progbits
.Ldebug_abbrev0:
	.uleb128 0x1
	.uleb128 0x11
	.byte	0x1
	.uleb128 0x25
	.uleb128 0xe
	.uleb128 0x13
	.uleb128 0xb
	.uleb128 0x3
	.uleb128 0xe
	.uleb128 0x1b
	.uleb128 0xe
	.uleb128 0x55
	.uleb128 0x6
	.uleb128 0x11
	.uleb128 0x1
	.uleb128 0x52
	.uleb128 0x1
	.uleb128 0x10
	.uleb128 0x6
	.byte	0
	.byte	0
	.uleb128 0x2
	.uleb128 0x24
	.byte	0
	.uleb128 0xb
	.uleb128 0xb
	.uleb128 0x3e
	.uleb128 0xb
	.uleb128 0x3
	.uleb128 0xe
	.byte	0
	.byte	0
	.uleb128 0x3
	.uleb128 0x24
	.byte	0
	.uleb128 0xb
	.uleb128 0xb
	.uleb128 0x3e
	.uleb128 0xb
	.uleb128 0x3
	.uleb128 0x8
	.byte	0
	.byte	0
	.uleb128 0x4
	.uleb128 0x16
	.byte	0
	.uleb128 0x3
	.uleb128 0xe
	.uleb128 0x3a
	.uleb128 0xb
	.uleb128 0x3b
	.uleb128 0xb
	.uleb128 0x49
	.uleb128 0x13
	.byte	0
	.byte	0
	.uleb128 0x5
	.uleb128 0x2e
	.byte	0
	.uleb128 0x3f
	.uleb128 0xc
	.uleb128 0x3
	.uleb128 0xe
	.uleb128 0x3a
	.uleb128 0xb
	.uleb128 0x3b
	.uleb128 0xb
	.uleb128 0x27
	.uleb128 0xc
	.uleb128 0x49
	.uleb128 0x13
	.uleb128 0x11
	.uleb128 0x1
	.uleb128 0x12
	.uleb128 0x1
	.uleb128 0x40
	.uleb128 0xa
	.uleb128 0x2117
	.uleb128 0xc
	.byte	0
	.byte	0
	.uleb128 0x6
	.uleb128 0x34
	.byte	0
	.uleb128 0x3
	.uleb128 0x8
	.uleb128 0x3a
	.uleb128 0xb
	.uleb128 0x3b
	.uleb128 0xb
	.uleb128 0x49
	.uleb128 0x13
	.uleb128 0x3f
	.uleb128 0xc
	.uleb128 0x2
	.uleb128 0xa
	.byte	0
	.byte	0
	.byte	0
	.section	.debug_aranges,"",@progbits
	.long	0x1c
	.word	0x2
	.long	.Ldebug_info0
	.byte	0x4
	.byte	0
	.word	0
	.word	0
	.long	.LFB0
	.long	.LFE0-.LFB0
	.long	0
	.long	0
	.section	.debug_ranges,"",@progbits
.Ldebug_ranges0:
	.long	.LFB0
	.long	.LFE0
	.long	0
	.long	0
	.section	.debug_line,"",@progbits
.Ldebug_line0:
	.section	.debug_str,"MS",@progbits,1
.LASF2:
	.string	"unsigned int"
.LASF10:
	.string	"uint64_t"
.LASF3:
	.string	"long int"
.LASF0:
	.string	"signed char"
.LASF8:
	.string	"avr.c"
.LASF7:
	.string	"GNU C 4.8.1 -fpreprocessed -mmcu=atmega16 -g -Os"
.LASF6:
	.string	"long long unsigned int"
.LASF1:
	.string	"unsigned char"
.LASF9:
	.string	"/home/uid23021"
.LASF11:
	.string	"main"
.LASF4:
	.string	"long unsigned int"
.LASF5:
	.string	"long long int"
	.ident	"GCC: (AVR_8_bit_GNU_Toolchain_3.4.3_1072) 4.8.1"
.global __do_copy_data

The actual source annotation done by the debugger results from the .file and .loc statements embedded in the Asm there.

 

.file 1 "avr.c" says "add a file number 1 to your table called avr.c". Then ".loc 1 5 0" says the following opcodes were generated by file number 1 at line 5. So when the debugger comes across this it will then open avr.c and read line 5 and put it against that following block of opcodes.

 

I wrote this which is able to do this process on .s files such as this to add source annotation to them:

 

https://spaces.atmel.com/gf/proj...

 

The rubric there explains some more about this.

Last Edited: Mon. Nov 3, 2014 - 10:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GNU avr-as can generate both ELF or COFF format.

 

AVRASM2 uses a different debug format in its OBJ file.

 

Atmel Studio can parse OBJ, ELF, COFF when debugging.

 

AFIK,   the Atmel OBJ is proprietary.     It is unfortunate that uses the same extension as many other manufacturer's object formats.

 

David (twit)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Responses from the three twit brigade!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

Responses from the three twit brigade!

Maybe you three should create your own media empire and call it 'Twitter'.  OOPS! Already taken,

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I will like to know what your goal is ?

And do you want it to work on big and/or small AVR's

should it run fast or be small.

 

I think that my goal will be to generate code for small AVRs, and to generate code that is more compact than what C generates so a smaller less-expensive chip can be used. It will also generate fast code compared to a threaded Forth, but small size will be more important that speed.

 

I have been reading over the manual, and I just discovered that addressing with a displacement is not available on the megaAVR, but is only available on the xmegaAVR. This is very bad news! This really kills quotations, unless I want to only support the xmegaAVR, which is the exact opposite of where I'm going (smaller). I'm going to redesign the cross-compiler without quotations --- I will save quotations for the PIC24 which will be the next project. 

 

I also note that PUSH and POP are not available on all AVR chips. I assume this means they aren't available on the small ones, so I'm also redesigning the cross-compiler to not use these. Are there any other instructions that are not available on the small chips, that I should avoid?

 

The lack of addressing with displacement was a real shock to me, as even the 6502 had that. This really kills a lot of possibility. I think now that this AVR Forth will have to be a very bare-bones Forth implementation, and all the cool features will have to wait for the PIC24 implementation later on. I'll drop double-precision (32-bit) arithmetic on the AVR version too, as there is no support for division, and it would just be too slow to be realistic --- even 16-bit arithmetic is going to be slow if it involves division.

 

sparrow2 wrote:

I will say that I'm one of those that know the AVR ASM (but only clasic tiny and mega parts).

Somewhere I have posted some code that emulate AVR code running on an AVR (so the code could be placed extern never finished but perhaps some ideals)

 

You are saying that you have written a simulator for the AVR chips? This runs under Windows? Atmel has a simulator, but I haven't tried it out yet.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just discovered that addressing with a displacement is not available on the megaAVR

Do you mean something like 

 

ST (STD) – Store Indirect From Register to Data Space using Index Z
Description:
Stores one byte indirect with or without displacement from a register to data space. For parts with SRAM, the data space
consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM,
the data space consists of the Register File only. The EEPROM has a separate address space.

.

.

.

ST (STD) – Store Indirect From Register to Data Space using Index Y
Description:
Stores one byte indirect with or without displacement from a register to data space. For parts with SRAM, the data space
consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM,
the data space consists of the Register File only.

  PUSH and POP are not available on all AVR chips.

It has been available in ALL the chips I have used in the past 15 years, can you point to a part number? I may have missed something.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just checked the datasheet of the brain dead, 6 pins, ATtiny4/5/9/10 they still have push and pop.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just discovered that addressing with a displacement is not available on the megaAVR,

Most  megaAVR have LDD Rd,Y+q and STD Rd, Z+q addressing with displacement, but they're relatively crippled (only y and z as index registers, and q<=63) (more useful for structure access than array access.)  I hadn't noticed that the xmega was any better?

The usual claim of RISC architectures is that you don't need all the fancy address modes of the CISC era if  you can do the math to implement those address modes "manually" in about the same number of cycles.   There's some truth to that, but the AVR is not a good example given that it has so many limits on which registers can be used for indexing and pointer-width math.

 

PUSH and POP are not available on all AVR chips. 

I think PUSH/POP are only unavailable on some very small "legacy" chips that are unlikely to be used by anyone in a modern design (attiny11/12/15/28, at90s1200.)  I don't know if they're even sold any more.  These were chips that didn't have any RAM (just the 32 registers.  Low-end PIC competitors.)

For more modern designs (even the otherwise weird attiny4/5), there is some RAM along with PUSH and POP.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Just checked the datasheet of the brain dead, 6 pins, ATtiny4/5/9/10 they still have push and pop.
These don't:

  • AT90S1200
  • ATtiny11
  • ATtiny12
  • ATtiny15
  • ATtiny28

 

From http://en.wikipedia.org/wiki/Atmel_AVR_instruction_set

 

Note that none of these parts have any SRAM, and are no longer produced.  They are examples of the earliest AVR ever produced.  I wouldn't sweat it.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are saying that you have written a simulator for the AVR chips? This runs under Windows? Atmel has a simulator, but I haven't tried it out yet.

No it was a AVR emulator, running on an AVR. (just for fun and never finished) But that way I could run code from RAM or intern/extern EEPROM.

 

  

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Didn't Cliff write one a while back as well?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

I just discovered that addressing with a displacement is not available on the megaAVR

Do you mean something like 

ST (STD) – Store Indirect From Register to Data Space using Index Z
Description:
Stores one byte indirect with or without displacement from a register to data space. For parts with SRAM, the data space
consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM,
the data space consists of the Register File only. The EEPROM has a separate address space.

 

It has been available in ALL the chips I have used in the past 15 years, can you point to a part number? I may have missed something.

 

I got the impression that STD and LDD were only available on the XMEGA because I read this for LDD:

Quote:

i) Rd ← (Y) 
(ii) Rd ← (Y) Y ← Y + 1
(iii) Y ← Y - 1 Rd ← (Y)
(iv) Rd ← (Y+q)

...

Cycles:

(i) 1(2)
(ii) 2
(iii) 3(2)
Cycles XMEGA:

(i) 1(1)
(ii) 1(1)
(iii) 2(1)
(iv) 2(1)

This seems to indicate that (iv), addressing with displacement, is only available on the XMEGA, because it is not specifically listed for the other parts. STD is somewhat similar, but not the same. This is speculation on my part --- I'm assuming that absence of evidence is evidence of absence, which isn't a good way to determine what features are not available.

 

js wrote:

  PUSH and POP are not available on all AVR chips.

It has been available in ALL the chips I have used in the past 15 years, can you point to a part number? I may have missed something.

 

I'm just speculating because the manual says: "This instruction is not available in all devices. Refer to the device specific instruction set summary."

 

Doesn't Atmel provide a list of what features are available on what processors? I don't want to refer to any device-specific data-sheet, because I'm not targeting any specific device --- I just want to cover all bases, especially the small chips as my new goal is to optimize primarily for size.

 

I have given some more thought to the subject of local variables and quotations. I can implement locals even without addressing-with-displacement by storing all of them in registers. This is actually better, because it results in faster code. The downside is that I would be limited to 6 locals as I don't have a lot of registers available (and this is getting rid of most of the ISRxx registers). Even if I do have addressing-with-displacement as you say, I may ignore it anyway and go with registers --- speed is important, and the 6-local limit isn't all that onerous. People can put data in a struct and pass the pointer to the struct if they have more than 6 data, and this improves readability anyway --- if a person thinks that he needs more than 6 locals, he is likely doing something wrong, and he needs to rethink the problem.

 

PUSH and POP are much more important. If these are available as you say, then that will allow me to have features that would otherwise be impossible, or at least very inefficient.

 

So, your post was pretty encouraging --- the situation is better than I had believed from my reading of the manual.

 

When C is your only hammer, every problem looks like your thumb. 

Last Edited: Thu. Nov 6, 2014 - 12:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why are you relying on impression?  Have you looked at the link from my post above (#94)?  LD/LDD and ST/STD were added in the 2nd generation of the AVR core.  All AVR since the AT90S2313 have those instructions.  The only exception to that are the 'brain dead' ATtiny4/5/9/10, which lack LDD/STD (but still have LD/ST).

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you have to look at the each AVR to see what it have of instructions.

Atmel is very very bad about writing data-sheets.

but all chips with RAM have the instructions, (other than tinys  with only 16 registers, but they have memory mapped flash).

Have in mind on xmega's you can't address the registers with a pointer, as you can on others.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Didn't Cliff write one a while back as well?

Yes, but like Sparrow I never completed mine either.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So does this one pass ASM mean that you can't make forward declarations?

 

On a Jupiter Ace you had the word/function redefine that made it possible to have forward "call's" (not sure of the term).

 

 

 

Last Edited: Thu. Nov 6, 2014 - 06:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

So does this one pass ASM mean that you can't make forward declarations?

 

Yes. 

 

For mutually recursive functions, one of them must be vectored. See VECTOR and DEFER in my novice package:

http://www.forth.org/novice.html

This is essentially a variable with a pointer to a function in it --- to call the function you fetch the pointer and EXECUTE it.

 

A vector is also useful when there is some reason to believe that somebody in the future may want to change what a function does and have all the code that uses that function change too, without having to recompile the program. One of the problems with ANS-Forth is that they didn't vector any of the functions, and there are many that the user may want to change. For example, the function that converts a string into a number could be revectored to support a new syntax for a number ($4000 would be a hex number, for example, which is currently supported in some Forth system such as VFX but is not ANS-Forth compliant). Now the Forth-200x is coming up with something along these lines, but the concept was well known 30 years ago (it was in FIG-Forth) and should have been put in ANS-Forth in 1994.

 

sparrow2 wrote:

On a Jupiter Ace you had the word/function redefine that made it possible to have forward "call's" (not sure of the term).

 

Some Forth systems allow any Forth function to be patched later so that it will do something else, and the program doesn't have to be recompiled. This is most likely what you are referring to on the Jupiter Ace. This was easy to do on ITC (indirect-threaded-code) systems, which the Jupiter Ace was --- it is more complicated to do on DTC (direct-threaded-code) or STC (subroutine-threaded-code). This is not in ANS-Forth --- that would have been another good solution, but the ANS-Forth committee did nothing at all.

 

When C is your only hammer, every problem looks like your thumb. 

Last Edited: Thu. Nov 6, 2014 - 10:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So does this one pass ASM mean that you can't make forward declarations?

It depends.  Lots of one-pass assemblers (the gnu assembler included) permit forward declarations.  Arguably, the gnu assembler gets to use the linker as its second pass, anyway, but I think you can write single-pass assemblers that don't need a linker.  You just need a symbol table that keeps track of "undefined", and a "fixup" that happens when a symbol is defined.

 

I don't see whether the Atmel assembler is one or two passes from skimming the documentation.   "avra", which is mostly compatible with the Atmel assembler, is a two pass assembler.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

So does this one pass ASM mean that you can't make forward declarations?

It depends.  Lots of one-pass assemblers (the gnu assembler included) permit forward declarations.  Arguably, the gnu assembler gets to use the linker as its second pass, anyway, but I think you can write single-pass assemblers that don't need a linker.  You just need a symbol table that keeps track of "undefined", and a "fixup" that happens when a symbol is defined.

 

I don't see whether the Atmel assembler is one or two passes from skimming the documentation.   "avra", which is mostly compatible with the Atmel assembler, is a two pass assembler.

 

As a practical matter, I don't really care if an assembler is one-pass or two-pass, because I can easily arrange functions to be defined before they are used --- mutual recursion is pretty rare in micro-controller programs --- and it is an inefficiency of only few clock cycles anyway, to do a vectored call rather than a normal call.

 

What I mostly look for in an assembler is a powerful macro language. I haven't examined avra at all yet --- how does it compare to ASM2?

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't examined avra at all yet --- how does it compare to ASM2?

It's supposed to be "compatible" (but open source and multi-platform.)  I don't remember whether it has any useful extensions.

 

Since you have PIC24 on your list as well, I'll encourage you again to look at the gnu assembler.  Because I'm pretty sure that the PIC24 assembler IS the gnu assembler, and anything you learn about the macros doing AVR will carry over to pic24.

 

The gcc assembler is reasonably powerful; macros can recurse or define other macros, for example.  I find it a bit ugly and less than elegant compared to some other assemblers, but it is pretty capable.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

Since you have PIC24 on your list as well, I'll encourage you again to look at the gnu assembler.  Because I'm pretty sure that the PIC24 assembler IS the gnu assembler, and anything you learn about the macros doing AVR will carry over to pic24.

 

MicroChip provides two assemblers for the PIC24 --- I think you are referring to the older one, that has now been obsoleted. I used the older one for the PIC16 a long time ago, and I'm pretty sure that was GAS; it worked fine for me.

 

westfw wrote:
The gcc assembler is reasonably powerful; macros can recurse or define other macros, for example.  I find it a bit ugly and less than elegant compared to some other assemblers, but it is pretty capable.

 

A feature that ASM2 seems to be lacking, is temporary locals. I'll just quote the FASM manual as it describes what it has, which is what I would like to have in ASM2 or AVR-AS:

Quote:

The label whose name begins with dot is treated as local label, and its name is
attached to the name of last global label (with name beginning with anything but dot)
to make the full name of this label. So you can use the short name (beginning with dot)
of this label anywhere before the next global label is defined, and in the other places
you have to use the full name. Label beginning with two dots are the exception - they
are like global, but they don't become the new prefix for local labels.
The @@ name means anonymous label, you can have defined many of them in the
source. Symbol @b (or equivalent @r) references the nearest preceding anonymous label,
symbol @f references the nearest following anonymous label. These special symbol are
case-insensitive.

 

With my cross-compiler, I generate my own labels, so I can give everything a unique label. This is fine for function names, and also fine for IF ELSE THEN etc. control-structures.

 

It is a hassle though, for primitives that do internal branching (?DUP MIN MAX etc.), because I would like to just paste this code in --- I can't do this simply though, but I have to fix the labels so they are unique, which is a lot of tedious work for me.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm pretty sure the 8-bit PIC assemblers were never gnu...  I haven't used or researched the PIC24 enough to notice that there were two assembler, much less tell you which one is which.

 

In gnu assembler, temporary local labels are numbers that you then include a forward or backward indicator when referenced:

loop:
0:  add x,#1
      cmp x, 40
      jmp 0f      ; Jumps forward to 0 (to "lexit")
     add y, #1
     jmp 0b       ; Jumps backward to 0 (to "loop")
0:
lexit: ret

The structured assembler macros I referenced earlier use these extensively, incrementing the number used for each label to achieve nesting.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

I'm pretty sure the 8-bit PIC assemblers were never gnu...  I haven't used or researched the PIC24 enough to notice that there were two assembler, much less tell you which one is which.

 

I remember that MicroChip was using gnu but they weren't giving away the source-code, which I thought was a violation of the GPL. This was for the PIC24. If there C compiler is based on GCC, then their assembler would have to be GAS. Most likely then, what I was using on the PIC24 was GAS, and what they had on the PIC16 was their own. I don't know if they had a C compiler for the PIC16 or not; that is a pretty low-level chip without any support for high-level languages. I'll have to do some research on this --- if it is true that their PIC24 assembler is GAS, then that is a reason to use GAS on the AVR as a stepping stone into PIC24.

 

I want to be able to use the debugger and simulator and all that stuff that comes with Atmel Studio. If GAS generates the necessary debugging information, then maybe I should switch over from ASM2. I haven't really found any show-stoppers with ASM2 though. 

 

I haven't located the documentation for GAS, much less begun to read it --- I'll look into it though --- I should know about it before I dismiss it.

 

westfw wrote:

In gnu assembler, temporary local labels are numbers that you then include a forward or backward indicator when referenced:

loop:
0:  add x,#1
      cmp x, 40
      jmp 0f      ; Jumps forward to 0 (to "lexit")
     add y, #1
     jmp 0b       ; Jumps backward to 0 (to "loop")
0:
lexit: ret

The structured assembler macros I referenced earlier use these extensively, incrementing the number used for each label to achieve nesting.

 

If your control-structures supported nesting, then that is pretty good --- I'll look into this too. This isn't really necessary for my cross-compiler though, as it generates control-structures on its own --- it might make the generated assembly-code look prettier though.

 

Right now, I'm just writing code and not really doing any research --- I don't want to get bogged down in researching various approaches and not get any code actually written. :-)

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If there C compiler is based on GCC, then their assembler would have to be GAS. 

No.  After all, the avr C compiler is gcc, and the avr assembler is ASM2...  GAS is perfectly willing to be "yet another assembler" for any given architecture.

 

If GAS generates the necessary debugging information

Hmm.   That's an interesting question.  GAS has extensive directives for generating debugging information (after all, all the C debugging info can/does have gas as an intermediate step.)  But I don't know whether it generates as much debugging information as ASM2 does, from a simple program.

 

I haven't located the documentation for GAS

And that's one of the problems with GAS.  You won't find a manual for the avr gas implementation.   Instead, you get generic gas documentation (or: there are some nice write-ups for non-AVR GAS usage), and a page to two of "here are the avr-specific parts."  But: https://sourceware.org/binutils/...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
GAS is perfectly willing to be "yet another assembler" for any given architecture.

 

If GAS generates the necessary debugging information

Hmm.   That's an interesting question.  GAS has extensive directives for generating debugging information (after all, all the C debugging info can/does have gas as an intermediate step.)  But I don't know whether it generates as much debugging information as ASM2 does, from a simple program.

 

I haven't located the documentation for GAS

And that's one of the problems with GAS.  You won't find a manual for the avr gas implementation.   Instead, you get generic gas documentation (or: there are some nice write-ups for non-AVR GAS usage), and a page to two of "here are the avr-specific parts."  But: https://sourceware.org/binutils/docs/as/index.html

 

I think that I will stick with ASM2 as it seems to be Atmel's preferred method. Because this is a cross-compiler rather than a traditional Forth with a REPL, I will be relying on Atmel's debugger for all debugging, so I want to use ASM2 that does work in the debugger, and also that will be familiar to the users. The AVR version is just a run up to the PIC24 and ARM versions that will be more professional, so I want to keep it as simple as possible, which means using Atmel's recommended assembler.

 

The cross-compiler generates either unoptimized or optimized code. The unoptimized should be pretty readable; every Forth word will be an RCALL to a function with a readable name --- code with literal values or branches will be inlined, but it should all be pretty obvious. The user can debug this as he would hand-written assembly-language. The optimized code will be less readable as registers will be used a lot rather than just the stack, but presumably the user will have already tested and debugged his code by the time that he wants to generate an optimized version of his program.

 

Would you be interested in seeing the assembly code for the kernel? The cross-compiler isn't ready yet, but it is possible to write Forth words as hand-written assembly --- just think of the parameter stack as a parameter-passing-protocol --- in assembly, the programmer generally has some kind of protocol for parameters, rather than put them in registers willy-nilly.

 

My design has changed a lot since the time when I showed the register dedications. I am holding locals in registers now, rather than memory. This should result in significantly faster speed, although the downside is that I only have 6 locals max (ANS-Forth specifies a minimum of 8, although most people never use more than 4 in even the most complicated functions).

 

On the AVR there is a huge difference in the speed of accessing a register or accessing memory --- on the PIC24 there is not much difference, so I may go back to having locals in memory for the PIC24 version.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will look at it.

If it's for speed I would go for IJMP  not RCALL, (but I don't know your structure).

 

Now I'm hooked on making a small forth my self that can run direct, and be small rather than fast. (but it looks like I don't have time before Christmas :( ).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

I will look at it.

If it's for speed I would go for IJMP  not RCALL, (but I don't know your structure).

 

Now I'm hooked on making a small forth my self that can run direct, and be small rather than fast. (but it looks like I don't have time before Christmas :( ).

 

I don't know what you mean by "run direct." Do you mean a traditional on-chip Forth with a REPL? If so, then it would be cool if you made it compatible to mine, rather than to the brain-dead ANS-Forth or Forth-200x standards. Mine is a cross-compiler, so it is going to generate very small code. This is because of ghosting (words are only materialized if they are used), and because the compiler isn't on the target. The kernel can actually be common to both the cross-compiler and the on-chip Forth system, as this is just an ASM2 file.

 

I can actually have both near (RCALL and RJMP) and far (CALL and JMP) functions. In some cases, the far functions could actually be near, but there is no way for me to know this at compile-time. I will just put all the far primitives at the top of the program and will make the big clunky functions (such as double-precision arithmetic) far. The user can also specify his colon words as NEAR or FAR, and make the speed-critical and/or common functions NEAR. This is one of the advantages of a cross-compiler over an on-chip compiler --- code doesn't have to be compiled sequentially like in a traditional dictionary --- it can be rearranged by the cross-compiler.

 

Everybody who is interested, send me a PM with your email address and I will email the source-code. I promise not to spam you, but will only email you if you request. I will only respond to people who I think want to make a positive contribution --- those who want to call my code "unnatural" or "abhorrent" can do so without the source-code --- that will be their "cross to bear."

 

 

Here is a new description of the register dedications:

 

; This is the product of MUL etc..  It can also be used as a general-purpose register-pair.
.def PRD0    = R0
.def PRD1    = R1

 

; This is the top-of-stack for the return-stack.
.def RTOS0    = R2
.def RTOS1    = R3

 

; This is local-F
.def LF0    = R4
.def LF1    = R5

 

; This is local-E
.def LE0    = R6
.def LE1    = R7

 

; This is local-D
.def LD0    = R8
.def LD1    = R9

 

; This is local-C
.def LC0    = R10
.def LC1    = R11

 

; This is local-B
.def LB0    = R12
.def LB1    = R13

 

; This is local-A
.def LA0    = R14
.def LA1    = R15

 

; The registers above this point are used by DES. 
; The registers above this point also don't work with LDI or any instruction with immediate values.

 

; These are for use by fastISRs or by the RTOS if there is one. They could be converted into local variables if 6 turns out to be not enough.
.def ISR0    = R16
.def ISR1    = R17
.def ISR2    = R18
.def ISR3    = R19

 

; This is ROS (third-of-stack).
.def ROS0    = R20    
.def ROS1    = R21

 

; This is SOS (second-of-stack).
.def SOS0    = R22
.def SOS1    = R23

 

; This is TOS (top-of-stack).                     ADIW and SBIW will work on TOS1:TOS0. 
.def TOS0    = R24                        
.def TOS1    = R25

 

; This is the local-stack pointer.               This has to be X, so indirect addressing will work (no displacement needed).
.def X0        = R26
.def X1        = R27

 

; This is the parameter-stack pointer.      This has to be Y so indirect addressing will work with a displacement
.def Y0        = R28
.def Y1        = R29

 

; This is the general-purpose pointer.      This has to be Z so it can be used for program-memory as well as data-memory, and by CALLI and JMPI.
.def Z0        = R30
.def Z1        = R31

 

; Each primitive has some of the following versions, each with its own xt. 
; x00     expect                           leave                                     neither            
; x01     expect                           leave                 TOS              producer
; x02     expect                           leave          SOS TOS              producer        
; x03     expect                           leave   ROS SOS TOS             producer        
; x10     expect                TOS     leave                                    consumer
; x11     expect                TOS     leave                 TOS             neither        This is required as these will be compiled in unoptimized code.
; x12     expect                TOS     leave          SOS TOS             producer
; x13     expect                TOS     leave   ROS SOS TOS             producer
; x20     expect         SOS TOS     leave                                   consumer
; x21     expect         SOS TOS     leave                 TOS             consumer        This is required as this will be the CFA in the XT used by EXECUTE.
; x22     expect         SOS TOS     leave          SOS TOS             neither            
; x23     expect         SOS TOS     leave   ROS SOS TOS             producer
; x30     expect  ROS SOS TOS     leave                                   consumer
; x31     expect  ROS SOS TOS     leave                 TOS             consumer    
; x32     expect  ROS SOS TOS     leave          SOS TOS             consumer
; x33     expect  ROS SOS TOS     leave   ROS SOS TOS             neither     

 

; The x21 version is our default for EXECUTE because this is assumed to be the most common for colon words. 
; It doesn't matter what is the most common for primitives, because they have multiple versions and the most appropriate will be compiled.
; Colon words don't have multiple versions though, so they need a default that is efficient.

 

; The functions should not call or jump into each other. This is so they can be ghosted.
; It is okay for different versions of one function to fall into each other though, as they can all get materialized together.

 

; The T flag is reserved for use by the RTOS.
; The T flag is checked by PAUSE. PAUSE gets compiled automatically in places where there is minimal state to save.
; If PAUSE finds the T flag set, the task will relinquish control. 

 

; There can be up to 6 locals, all of which are stored in registers (LA..LF)
; The parent's locals are held on the local-stack during the colon word. 

 

; We have quotations.

; If a quotation doesn't have locals, and the higher-order function doesn't either, then the quotation can use the locals of the parent.
; For this reason, it is best if higher-order functions use >R rather than locals for temporary storage. >R and locals use different stacks.

 

; A function can initially be tested using global variables, but then it can be rewritten as a quotation for improved speed.
; This is only for functions that are called by only one function, and are not general-purpose at all --- factoring just helps with testing.

 

 

Each primitive can have up to 16 versions in the kernel. Each primitive is required to have x11 and x21. Most have about a half dozen versions. The cross-compiler will know what versions are available for each primitive, and how much each version costs (roughly in terms of clock cycles). It will compile the least expensive version whenever possible. If there is no version of a primitive available that matches the configuration left by the previous primitive compiled, it may have to compile conversion functions between the user's functions to convert how many parameters are in registers and how many are in memory. In some cases, some of the versions of a primitive won't be in the kernel because they are very short, and they will just be inlined. Also, any primitive (such as LIT) that has embedded data, will have to be inlined. Also, some pairs of primitives can be combined together into a "combo." For example, an OVER followed by a ! can be compiled as a single primitive OVER_! --- this results in both faster and smaller code.

 

For simplicity, it is best to initially just write the Forth system to generate unoptimized code; all primitives are compiled as x11 --- later on, the Forth system can be rewritten to do optimization in that it compiles various versions of the primitives in an effort to minimize the cost. This may not even be necessary at all for the on-chip system --- the user can just be told that, after their program is debugged on the interactive system, it can be compiled for optimization with the cross-compiler. The cross-compiler runs on a desktop computer that is very fast and has a huge memory, so it can try out various ways to compile the code and use whichever one is the least expensive --- this is similar to the Alpha-Beta algorithm used in games such as chess, in that it does an exhaustive search of the possible code-sequences, but it has heuristics so it tries out the presumably better code-sequences first, and it weeds out a lot of code-sequences that are discovered to be worse than the best-so-far. You can't do this kind of optimization on an AVR because it is too slow and has too little memory --- but on a desktop computer, exhaustive search is a viable plan.

 

I'm planning on making the RTOS an integral part of the language. PAUSE will be compiled at places where there is minimal state to save and restore, and in such a way as to prevent long periods of time between PAUSE being used --- the compiler can do this transparently, without the user having to manually scatter PAUSE throughout his code --- the user can also explicitly provide a PAUSE, which would be done primarily when a delay is needed (PAUSE takes one parameter, which is the minimum number of milliseconds to pause, and which will be zero for all of the PAUSE statements that are compiled transparently by the compiler).

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One thing you are missing is a register that always is zero.

 

I think that our goal's are different, I would make a small version, and my first try would be forth79 , and implement it like my jupiter ace (I have a good emulator, and was actually a part owner of one back in 83), and add some words for the HW.

To make the code small, I was thinking of making it token based, with real name in eeprom and code in RAM, that should make some very compact code, at a ok speed, my hope was a 2k version(2313), or a 4k with FP(mega48).

When you get higher up in size, you can live with less compact code.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

One thing you are missing is a register that always is zero.

 

Why would I need that? The CLR instruction is only 1 clock cycle, so I can use one of the general-purpose registers.

 

What is a register containing zero actually used for? So far, the only use I have found for CLR was to zero out the local variables that aren't initialized from the stack; this is done so the uninitialized locals always get initialized to the same thing (zero) so that, if the programmer forgets to explicitly initialize them before using them, the program always does the same thing --- likely not what the programmer wants if if forgot to initialize it, but the program will always fail in the same way --- consistency is important in finding bugs, as there is nothing worse than a program that does different things each time that it is compiled depending upon what garbage data might have been in memory previously.

 

Off the top of my head, I can't think of any other use for a register containing zero. I would be interested in finding out what you are thinking of, as I don't want to discover this for myself late in the development of the system when it would be great hassle to fix the problem.

 

sparrow2 wrote:

I think that our goal's are different, I would make a small version, and my first try would be forth79 , and implement it like my jupiter ace (I have a good emulator, and was actually a part owner of one back in 83), and add some words for the HW.

To make the code small, I was thinking of making it token based, with real name in eeprom and code in RAM, that should make some very compact code, at a ok speed, my hope was a 2k version(2313), or a 4k with FP(mega48).

 

The RCALL only requires 2 bytes. So, assuming that my generated programs fit in 4KW (8KB) and that I use RCALL rather than inline-code almost entirely, my "tokens" are 2 bytes. I expect that most programs will fit in 4KW, as that is pretty big --- if they don't fit, then I will have a mixture of near and far functions as I described previously --- if there are far functions, these will be the big clunky ones like double-precision arithmetic that aren't used very much and/or don't have to be very fast, so performance should still be pretty good.

 

If you have a token-based system in which the tokens are 1 byte, then you have 256 primitives, which is plenty. The problem however, is that calling a colon word now takes 3 bytes (rather than 2 as in my system). Assuming that Forth code mostly consists of calls to colon words rather than primitives (this is common because factoring is emphasized so much in Forth), your code could conceivably be larger than mine --- it is not going to be significantly smaller.

 

Also, I would not describe a token-based system as having "okay speed" --- it is going to be about an order of magnitude slower than a system such as mine that compiles into machine-code --- "abysmal speed" would be a more accurate description of most threaded Forth system (PolyForth comes to mind).

 

It seems to me that our goal is the same --- primarily small-size, and secondarily okay-speed --- what is your goal if not that?

 

By FP you mean floating-point? I still don't know what that is used for in micro-controller programs --- I've never seen it used, anyway --- I'm not planning on providing floating-point on the AVR, although I might on the PIC24 that has better support for arithmetic (it has divide). Actually, I don't really know what double-precision integers are used for in a micro-controller either, as all of the data that you get from ADCs are going to be 12-bit or 16-bit typically --- if none of your data is 32-bit, then you don't really need 32-bit integers except for some intermediate values (such as the famous */ word uses).

 

sparrow2 wrote:

When you get higher up in size, you can live with less compact code.

 

I don't understand this statement. 

 

Doesn't the problem of bloaty code increase proportionately with the size of a program? Why would the problem of bloaty code be more serious with small programs rather than big programs? If anything, the opposite is true, as there is a minimum size for FLASH (4KW) but there is no minimum size for programs. Most programs don't come anywhere near 4KW in size no matter what compiler you use, as most programs don't do very much, and many are actually a replacement for analog electronics --- this is why the PIC12 is still used today --- as an analogy: a lot more hunting is done with a .22LR than a .44-magnum. ;-)

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since zero is used so frequently in most code, having a 'zero register' around all the time saves having to zero one each time you need it.

 

It's handy for stuff like this:

add r18, r16
adc r19, __zero_reg__
adc r20, __zero_reg__
adc r21, __zero_reg__

I wouldn't say that's it's required however.  Just handy.  I imagine it makes life as a compiler writer a bit easier.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

about zero I don't need to add more (you find out when you get to the low level).

 

The problem on a small system like 2313 is the amount of RAM for an interactive system. 
So with a token based system new words (placed in RAM) need to be small. So one way is to place
the wordname in eeprom, and only have a token in the "code". That means that a definition 
take a tad more space (but not in RAM), but the use of a word take less (one byte).

 

You will need double otherwise you really can't make many calculations, or at least make */ and 
then why not the rest. (if you need to be able to print it is an other story).

 

I want my system for prototyping so I need it, and if speed don't matter it's not a big deal. (I can't read 115200 baud data anyway :) )

The really big benefit with forth is that you can program new words without loosing the value of the variables etc. (the down side is that it can end up with some ugly code).

 

What I was trying to say with a bigger system is that : 

when you build up you own words in forth, each word can do more and more, so on a 8K+ system it can hold std words, and your forth libs (not sure if it's the correct word to use), so you don't need many extra words to make a "big" program.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

The problem on a small system like 2313 is the amount of RAM for an interactive system. 

So with a token based system new words (placed in RAM) need to be small. So one way is to place
the wordname in eeprom, and only have a token in the "code". That means that a definition 
take a tad more space (but not in RAM), but the use of a word take less (one byte).

 

Is it possible to compile machine-code into RAM and then transfer it over to the FLASH so that it can be executed in FLASH? I think you have to transfer 256 bytes at a time.

 

If your system is going to be compatible with mine, then it would have to generate machine-code rather than byte-code --- otherwise they can't use the same kernel --- they would be completely different systems.

 

As I said before, a colon word typically has a lot of calls to other colon words --- these are 2 bytes in machine code (an RCALL opcode), but would be 3 bytes in byte-code (the one-byte token plus two bytes for the address), so byte-code isn't necessarily going to save memory --- all that byte-code does for you is to allow you to execute code that is in RAM, whereas machine-code has to be in FLASH.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is it possible to compile machine-code into RAM and then transfer it over to the FLASH so that it can be executed in FLASH? I think you have to transfer 256 bytes at a time.

 

All that have a boot loader section can do that, today that is almost all, i think that it's only a mega48 of all relevant chips that can't.

The size of the a flash page are different from chip to chip, a small chip like a 2313 have a page size of only 32 bytes.

If your system is going to be compatible with mine, then it would have to generate machine-code rather than byte-code --- otherwise they can't use the same kernel --- they would be completely different systems.

I'm sure that they will be completely different in structure, (for me it's a part of the fun to do it my self) , and look at AVR's as HW that can be programmed, where I guess that you are a "real" programmer.

(but as long our words have the same function why should we care?)

 

For a long time I have been thinking of making a token based system to  compress all the big interface code (mmi etc) than don't need to run fast.

The AVR are plenty fast but the C compiler's make some very big code. 

It's partly because of the non indexing structure of the AVR, that it gets so big, and here a stack structure will make it possible to save a lot of space.

As I said before, a colon word typically has a lot of calls to other colon words --- these are 2 bytes in machine code (an RCALL opcode), but would be 3 bytes in byte-code (the one-byte token plus two bytes for the address), so byte-code isn't necessarily going to save memory --- all that byte-code does for you is to allow you to execute code that is in RAM, whereas machine-code has to be in FLASH.

It's in the definition of the colon words I will place my tokens, so if you in a definition use DUP I would only store the token (one byte). for the tokens in the kernel(flash) I would make a lookup table, for where the code are (and make a ijmp I guess), for new words, I was planning to make a table in eeprom, all the system need to know is that token upto nnn are placed in flash and the rest in the eeprom.

Remember that when you define a word it's ok that it's not easy to find which token DUP have(it could just be bit 7 in the name list that mark word begin, and then count how many words it has passed before it get's to DUP), and from there on DUP is only known by it's token (vlist etc. don't need to be fast and will just do the same reversed).

 

Perhaps this is a bit of a odd setup but it's the way I can think off where the RAM are used most efficient.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

If your system is going to be compatible with mine, then it would have to generate machine-code rather than byte-code --- otherwise they can't use the same kernel --- they would be completely different systems.

I'm sure that they will be completely different in structure, (for me it's a part of the fun to do it my self) , and look at AVR's as HW that can be programmed, where I guess that you are a "real" programmer.

(but as long our words have the same function why should we care?)

 

It would be useful for them to be compatible, because my cross-compiler lacks the interactive REPL that Forth traditionally has (and which, according to some, is Forth's only virtue). If they were compatible, then programmers could interactively test code on your system, and then recompile their code on my system for improved speed (because my cross-compiler is running on a desktop computer, it can do a lot more optimization). Interactive testing would especially be useful for code that interacts with the I/O ports --- in my experience, the spec sheets for the board are never correct --- you have to just experiment with the hardware to figure out what it does.

 

Why Forth-79? There have been 3 standards since that time! Anyway, my Forth is not compatible with any standard, because I have lambda functions that have never been done before.

 

sparrow2 wrote:

For a long time I have been thinking of making a token based system to  compress all the big interface code (mmi etc) than don't need to run fast.

The AVR are plenty fast but the C compiler's make some very big code. 

It's partly because of the non indexing structure of the AVR, that it gets so big, and here a stack structure will make it possible to save a lot of space.

 

Well, the AVR does have indexing, but only with 63 as the maximum index, which is pretty small. This doesn't bother me in Forth, because I don't put structs on the stack --- I require the user to put structs somewhere else (the heap) and only put a pointer to the struct on the stack. In C it is common to put the whole struct on the stack. This is going to result in the C compiler not being able to use the indexed addressing mode. I suppose the generated C code would load a literal value into a register, and then add that register to Y, and then restore Y afterward --- this is going to be both slow and bloaty, which is why I expect my Forth to be competitive against C despite what the C enthusiasts on this forum have said.

 

BTW: My reading of the documentation is that this index is always positive, in the range of [0,63] --- is that correct? Most processors (the x86, anyway) sign-extend the index. 

 

sparrow2 wrote:

It's in the definition of the colon words I will place my tokens, so if you in a definition use DUP I would only store the token (one byte). for the tokens in the kernel(flash) I would make a lookup table, for where the code are (and make a ijmp I guess), for new words, I was planning to make a table in eeprom, all the system need to know is that token upto nnn are placed in flash and the rest in the eeprom.

Remember that when you define a word it's ok that it's not easy to find which token DUP have(it could just be bit 7 in the name list that mark word begin, and then count how many words it has passed before it get's to DUP), and from there on DUP is only known by it's token (vlist etc. don't need to be fast and will just do the same reversed).

 

Perhaps this is a bit of a odd setup but it's the way I can think off where the RAM are used most efficient.

 

In most micro-controllers, FLASH is pretty big (several KW in size), but it is RAM that is limited (often less than 1 KB in size). In general, FLASH is about an order of magnitude larger than RAM. If this is true of the AVR, then storing your colon words in RAM is a bad idea. RAM is precious and should be reserved for the application data.

 

Note that you have to store all of your colon words in either RAM or in FLASH, but you can't have a mixture. The reason is that the AVR uses different instructions for accessing RAM (LD) or FLASH (LPM), so your NEXT code has to assume one or the other --- it can't know that some colon words are in RAM and some in FLASH.

 

You can do whatever you want --- I'm just suggesting that you use the same design that I'm using because it allows for bigger programs on the same chip --- also, compatibility would benefit both systems as it gets all the Forthers congregated together.

 

BTW: Have you used amForth? Does it not do what you want? It has an interactive REPL --- I think so anyway, but haven't actually tried it yet.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:
Well, the AVR does have indexing, but only with 63 as the maximum index, which is pretty small. This doesn't bother me in Forth, because I don't put structs on the stack --- I require the user to put structs somewhere else (the heap) and only put a pointer to the struct on the stack. In C it is common to put the whole struct on the stack. This is going to result in the C compiler not being able to use the indexed addressing mode. I suppose the generated C code would load a literal value into a register, and then add that register to Y, and then restore Y afterward --- this is going to be both slow and bloaty, which is why I expect my Forth to be competitive against C despite what the C enthusiasts on this forum have said.

 

Actually, ADIW and SBIW could be used to temporarily adjust Y and then restore it again --- still, pretty slow and bloaty.

 

A lot of processors (the 6808 and 6812, for example) were specifically designed for C, and so implementing Forth goes against the grain, but in the case of the AVR the opposite is true.

 

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:
this is going to be both slow and bloaty, which is why I expect my Forth to be competitive against C despite what the C enthusiasts on this forum have said.

Most of whom wouldn't ever pass a large struct (or any other large data) to a function by value.  This isn't 'big iron'.  And it's a bad idea there too.

 

The AVR was designed with C in mind, by analysing existing code bases and identifying what types of architectural choices would be of greatest value.  Wide-reaching indexing wasn't deemed important enough because no self-respecting C programmer would pass a 64-byte struct by value.  Instead they pass a 2-byte pointer.  That's why C has the -> struct dereference operator.

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Sun. Nov 23, 2014 - 03:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why Forth-79? There have been 3 standards since that time!

Just that it was where I stopped using forth (and I have only used it for fun!), and I have a very good jupiter ace emulator (that use forth-79), so I can test that the different words get implemented correct.

If I get a full 79 up running I guess it's easy to change it to the newer standards.

 

Sorry that I wasn't clear with indexing. I was thinking of indexing in general terms. Let's say that you will use the value of register r14 for an addition. Then there are no way to do so without use of a  dedicated add instruction where r14 is a part.

In forth it would be nice to make a pointer to r14, and then add it to the top of the stack (that would be a register aswell). (I know that the stack is 16bit this is just to tell about the structure).

On non xmegas you can use a pointer to r14, and then make a load to the top of the stack where the addition are made.

 

About RAM use.

RAM is the easy and fast place to have new words, so that was I wanted to make that part small by using the eeprom for some of the things. I had no plans on write new words direct to flash, but rather a  word to make a "savetoflash", or perhaps it would rather be a save to terminal, and that way make a new flash file with a PC tool.

As I remember, but have to play with it, you could make relative big programs in 1k RAM on a jupiter.

 

To deal with two formats "next" just need to know token upto nnn are in flash and the rest are in eeprom(and RAM).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

I had no plans on write new words direct to flash, but rather a  word to make a "savetoflash"

Here is a pic24/dspic forth that does just that.  Well commented and understandable asm.

 

http://www.rs-online.com/designspark/electronics/knowledge-item/forthdspic-user-manual-source-code-vsn-0-52

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sparrow2 wrote:

Why Forth-79? There have been 3 standards since that time!

Just that it was where I stopped using forth (and I have only used it for fun!), and I have a very good jupiter ace emulator (that use forth-79), so I can test that the different words get implemented correct.

If I get a full 79 up running I guess it's easy to change it to the newer standards.

 

Forth-79 had some quirks. It is not going to be that easy to change to a new standard, because some of the words in Forth-79 worked differently --- this will require you to tediously go through your programs and find where those words are used --- I'm not familiar enough with Forth-79 to be able to tell you which words worked differently (some arithmetic stuff, and maybe some other stuff).

 

Unless you have big Forth-79 programs from your Jupiter Ace days that you want to port to the AVR, it would be better to go with a modern standard. Also, unless you have big programs in any standard that you want to port to the AVR, you could just ignore all standards altogether like I do.

 

sparrow2 wrote:

About RAM use.

RAM is the easy and fast place to have new words, so that was I wanted to make that part small by using the eeprom for some of the things. I had no plans on write new words direct to flash, but rather a  word to make a "savetoflash", or perhaps it would rather be a save to terminal, and that way make a new flash file with a PC tool.

As I remember, but have to play with it, you could make relative big programs in 1k RAM on a jupiter.

 

RickB told you that there is a PIC24 Forth that compiles into FLASH. That is because the PIC24 has instructions for writing single words into program memory (they take 2 clock cycles rather than 1 for RAM, but otherwise they are pretty much the same) --- the AVR doesn't (it can load a byte from program memory with LPM but has no instruction to store a byte). The AVR requires that a block of memory (256 bytes) be written all at once. If I were writing a Forth for the PIC24, which I will eventually, it would be a traditional on-chip Forth similar to what you are writing (except that it generates machine-code rather than threaded-code), because the PIC24 has support for writing into program memory. I'm writing a Forth for the AVR though, which doesn't have very good support for writing into program memory, and that is why I'm writing a cross-compiler. This is an AVR forum though, so why are we discussing the PIC24 at all?

 

[WARNING: You are on notice. Personal attacks will not be tolerated. Next one and you will be banned without another warning. Moderator]

 

sparrow2 wrote:

To deal with two formats "next" just need to know token upto nnn are in flash and the rest are in eeprom(and RAM).

 

That is possible, but it will result in a very slow NEXT --- threaded Forth systems are about an order of magnitude slower than machine-code Forth systems, and this kind of complication will only make the situation worse (also note that LPM is a 3-cycle instruction, which is pretty slow).

 

Speed may not be an issue for you though. If you want a Forth just so you can have a REPL to experiment with the hardware, then it doesn't have to be fast --- you are just going to be writing short test functions to twiddle the bits on the I/O ports while you use an oscilloscope to observe what happens outside --- so long as it runs fast enough to keep up with your typing speed, then you are fine.

 

AFAIK, amForth does have a REPL --- it very likely does everything that you want already --- I'll look into it myself, but I suggest that you do too before you invest too much work in writing your own Forth.

 

BTW: I might need to get the address of the registers. How is that done? This works on everything except the xMEGA AVR chips?

 

When C is your only hammer, every problem looks like your thumb. 

Last Edited: Mon. Nov 24, 2014 - 04:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW: I might need to get the address of the registers. How is that done? This works on everything except the xMEGA AVR chips?

On standard AVR's the registers are memory mapped on RAM addr. 0-31. So normal LD and ST instructions will work.

 

The problem is that xmega's sooner or later will take over because they are cheaper (a chip like xmega8E5 is close to $1), and about 2-3 times faster (32 MHz and many instructions are one clk faster).

And the newer xmegas have some new instructions where at least swap with element on "stack" could be usefull.

 

one clk (or rather about 5 total with check), extra for LPM don't kill anything for me, and remember that a rcall with is ret take 7 clk! (on most of the chips)

as long I can run words at in less than 100 clk it still would be usefull (160KHz words in my setup). And about 25 clk should be the avg for the simple kernel words.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hugh Aguilar wrote:

RickB told you that there is a PIC24 Forth that compiles into FLASH. That is because the PIC24 has instructions for writing single words into program memory (they take 2 clock cycles rather than 1 for RAM, but otherwise they are pretty much the same) --- the AVR doesn't (it can load a byte from program memory with LPM but has no instruction to store a byte). The AVR requires that a block of memory (256 bytes) be written all at once. If I were writing a Forth for the PIC24, which I will eventually, it would be a traditional on-chip Forth similar to what you are writing (except that it generates machine-code rather than threaded-code), because the PIC24 has support for writing into program memory. I'm writing a Forth for the AVR though, which doesn't have very good support for writing into program memory, and that is why I'm writing a cross-compiler. This is an AVR forum though, so why are we discussing the PIC24 at all?

 

[WARNING: You are on notice. Personal attacks will not be tolerated. Next one and you will be banned without another warning. Moderator]

 

I made a mistake there --- that wasn't a sock-puppet of Rickman --- it was a different Rick, and he wasn't attacking me. He had said that he knew me from comp.lang.forth, and there is only one person named Rick over there (Rickman), so I assumed that he was Rickman who follows me around making snarky remarks to the effect that all code I write is done wrong somehow. RickB tells me now that he reads comp.lang.forth but has never posted on the forum, which is why he was unknown to me.

 

Now RickB is really mad that I thought he was Rickman, and continues to demand that I be banned --- but I apologize.

 

He also says that I should get rid of my "twit list." I'm not going to. This would effectively be the same as admitting that I'm "unnatural" and "abhorrent," and having admitted that much, I would be required to admit to an ever-growing list of crimes against humanity --- it would become like the "self criticism" sessions done in hard-core communist countries --- I can't take one step down that path of appeasement, because there is no turning back, and there is no real limit to how far that path goes. 

 

The whole idea of language wars seems foolish to me. I do have a smart-alecky tagline ("When C is your only hammer, every problem looks like your thumb."), but other than that I don't attack C programmers. I don't care if people program in C; I've been employed as a C programmer myself. I've seen a lot of C code that could be described as "abhorrent" --- but that is usually from a bad programmer who would make a mess out of any language --- it is possible to write C code that isn't completely abhorrent (this largely involves not writing any general-purpose code, as doing so involves faking up lambda functions by holding local variables in a struct on the heap, which can get pretty ugly pretty quickly). It is not necessary for programmers of different languages to attack each other on the internet.

 

When C is your only hammer, every problem looks like your thumb. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

He also says that I should get rid of my "twit list." I'm not going to. This would effectively be the same as admitting that I'm "unnatural" and "abhorrent," and having admitted that much, I would be required to admit to an ever-growing list of crimes against humanity --- it would become like the "self criticism" sessions done in hard-core communist countries --- I can't take one step down that path of appeasement, because there is no turning back, and there is no real limit to how far that path goes. 

This is a  gross distortion and over exaggeration of what I said. There are people in this thread you refuse to acknowledge or reply to because of some imagined slight. Drop that now. This problem is of your own making.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moderators - stop this train wreck now - please!

Topic locked