tag:blogger.com,1999:blog-86578284358046276782024-02-08T09:04:46.285-08:00Something like EiffelSimonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-8657828435804627678.post-71505227036007640712013-04-11T03:42:00.004-07:002013-04-11T03:42:27.852-07:00Blog movedWork is still going on, but this blog has moved to <a href="https://sourceforge.net/p/isembard-os/blog/">https://sourceforge.net/p/isembard-os/blog/</a>.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-6717747268602858102012-02-16T08:32:00.000-08:002012-02-16T08:32:52.203-08:00I think I'll go with Isembard for a name.It turns out that I.K. Brunel's father was French, as well.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-53560618712529097412012-01-21T02:17:00.000-08:002012-01-21T02:17:32.836-08:00Kernel progressThe kernel is now at a point where code in two separate maps can communicate non-object parameters, provided the maps do not overlap, and only a single thread is supported.<br />
<br />
The calling code should:<br />
<ul><li>Put the feature identifier into r0 (this number is ignored by the kernel and passed unchanged to the callee)</li>
<li>Encode any parameters into the thread transfer block</li>
<li>Access the target "object" address using the specific instruction required by the kernel (currently LDR r14, [r14], so load r14 with the object's address and execute the instruction)</li>
</ul>Only one register (r13) is preserved over the call, and on return r11 points to the map's thread transfer block which will contain the return values. (I'm not sure yet whether to have the V bit set on exception, or call an exception handler routine.)<br />
<br />
The callee is entered with: <br />
<ul><li>r0 containing the value from the caller (nominally the feature number/identifier),</li>
<li>r11 pointing to the thread transfer block,</li>
<li>r12 containing the object identifier, as provided by code in the destination map when exporting the object handler, and</li>
<li>r14 containing the address to which the code should jump in order to return from the call.</li>
</ul>The encoding of parameters allows the transfers of objects and simple expanded type values.<br />
Objects local to the caller memory map will be defined by a handler (code) address and object identifier pair, which will be replaced by the kernel with a single pointer to an imported object. Objects that have been imported into the caller can also be passed as parameters or results of calls, and the kernel will give the recipient access to these values as well.<br />
<br />
The next task will be to add interrupt handling and multi-threading.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-18992467809829442882012-01-13T04:03:00.000-08:002012-01-13T04:03:51.062-08:00Name already takenI just realised that the Brunel name was already taken (also for an Eiffel derivative language), <a href="http://staffwww.dcs.shef.ac.uk/people/A.Simons/brunel/index.html">back in 1991.</a><br />
<br />
I'll have to come up with another name, I guess.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-43632934732272823932011-12-07T01:47:00.000-08:002011-12-07T07:15:50.263-08:00Starting on threads and memory mapsI finally got the SDRAM responding last night; I'd been writing 100 to a register rather than &100 (0x100), and it didn't like that. That's what you get from not taking open source code directly!<br />
<br />
The next task is to introduce (memory) maps and threads.<br />
<br />
Initially, I won't dynamically allocate these things, just create a few example ones with simple interfaces to prove the thread and map management code works.<br />
<br />
One map will implement the serial port driver.<br />
<br />
There are two ways I can think of where the caches/TLB can get confused:<br />
Change of thread<br />
Change of map<br />
<br />
In the first case, there is a context switch where one thread moves from the running state to either the runnable or blocked state, and another thread moves from runnable to running.<br />
<br />
In the second case, a thread makes a call to an object implemented in another map. (This will be done by storing the parameters to the call at a known location in thread-local storage and accessing a location in non-user accessible memory associated with the destination object. The map will be switched to the destination object's map and the thread will continue at a location within that map.)<br />
<br />
<span style="font-size: xx-small;">(Security note: the ARM registers will have to be preserved in the calling map and cleared before entering the called map, to ensure there's no leak of information from one map to another.)</span><br />
<br />
As a simple test of the switching code, I intend to have some threads running that do nothing but increment a single ARM register each while jumping around in their code and, checking their other general purpose registers remain at zero. If any of these test threads detect changes to registers, other than the one they're manipulating, there's a problem with the cache/TLB flushing.<br />
<br />
To test the test, I'll start with a kernel that won't perform any manipulations on the TLB or cache.<br />
<br />
Update: First problem was that the boot code (presumably) has set the Nonsecure Vector Base Address Register to 0x00014000, so putting my handlers in zero page meant they weren't called.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-23674827697285850832011-12-01T02:22:00.000-08:002011-12-01T02:22:30.370-08:00Introducing BrunelOSI've been working on hacking a BeagleBoard recently, and I've decided to design and implement my own OS to run on it.<br />
<br />
I've decided to call my variation on the Eiffel language Brunel (for <a href="http://en.wikipedia.org/wiki/Isambard_Kingdom_Brunel" target="_blank">I.K. Brunel</a>), and this operating system BrunelOS.<br />
<br />
I expect to be able to create a GNU/BrunelOS, where GNU software such as GCC can run on the OS, but ideally, I'd like to implement new applications using Brunel instead.<br />
<br />
Brunel is an Object Oriented language with design by contract, inline callbacks and with virtually invisible multi-threading/multi-processing facilities built in.<br />
<br />
The implementation of multi-threading is quite simple; only one thread at a time may access any of an object's features and subsequent attempts by other threads to enter an object will be blocked until the first thread exits the object. Deadlock will be automatically detected and cause an exception in the thread that causes it. The only exception to this system will be Event objects that allow threads to block until the event occurs (or is cancelled).<br />
<br />
BrunelOS is an operating system designed to work with the Brunel programming language.<br />
<br />
BrunelOS does not have traditional processes, but a combination of memory maps and threads.<br />
<br />
Objects and code exist in memory maps, and threads can pass from memory map to memory map within the system, but only ever to interface objects known to the calling memory map.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-58800551956443821332008-06-24T02:29:00.000-07:002008-06-24T02:41:26.920-07:00Bootstrap versionIn the last week I've managed to get the Eiffel version of the compiler to a state where it will compile itself.<br /><br />Until now, I've been using a very basic compiler written in C++ to compile the Eiffel code I've been writing, but from now on I should be able to dispense with that and simply work on the Eiffel code. As I add support for more features to the compiler, I will be able to use the features in the code.<br /><br />Basically, at the moment, I have a single test case; compiling the compiler. The test works in three stages:<br /><br />1. Use a tested version of the compiler to process the source code<br /><br />2. Use the new version of the software to process the same code<br /><br />3. Use the third version of the compiler to process the source code again<br /><br />4. Check that the generated code from steps 2 and 3 are identical; that version of the code then becomes the tested version for next time.<br /><br />The output from stages 1 and 2 may be different, because of different code generation strategies or support for more language features.<br /><br />Some time after the holidays, I intend to put the code in the form of the Eiffel source and generated C onto Source Forge.Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0tag:blogger.com,1999:blog-8657828435804627678.post-52107596396673083812008-04-23T00:30:00.000-07:002008-06-09T11:34:46.413-07:00A compilerAbout ten years ago I started working on a compiler for the Eiffel programming language and even quit my job to work on it full time for a few months. Before I finished it, I was offered a contracting job where I would split my time between working in England and Germany. One thing led to another and now I live in Germany and look after two small daughters.<br /><br />Anyway a few weeks ago I was asked to look into the C# language and that re-awakened my interest in languages and compilers, so I thought I'd have another look at it.<br /><br />Since then, I've modified the old C++ implementation of the compiler to generate C code with more features of Eiffel that I'd previously left out and I am now working on an Eiffel implementation of the compiler with the lessons learned.<br /><br />I was always unhappy with some of the gotchas in Eiffel, and that the compilers didn't manage to implement all the features of the language as described in the books (sometimes due to language deficiencies). I'm attempting to find ways around these deficiencies for a new version of the language.<br /><br /><span style="font-weight: bold;">Selecting interfaces rather than features</span><br /><br />My view of an Eiffel class is that it provides many interfaces, one for each type it inherits from. An object provides a set of features that may be accessed using different names from different interfaces.<br /><br /><pre><span style="font-weight: bold;">class</span> D<br /><span style="font-weight: bold;">inherit</span><br /> B<span style="font-weight: bold;"><br /> rename</span><br /> fn <span style="font-weight: bold;">as</span> b_fn<br /> <span style="font-weight: bold;">end</span><br /> C<br /> <span style="font-weight: bold;">rename</span><br /> fn <span style="font-weight: bold;">as</span> c_fn<br /> <span style="font-weight: bold;">select as</span> A -- c_fn will be called through a C reference<br /> <span style="font-weight: bold;">end</span><br /><span style="font-weight: bold;">feature</span><br /><span style="font-weight: bold;">end</span></pre><br /><br />This needs a lot more explaining, but it will have to wait for another post, or an update. It does, however, solve the Iterating Several Actions problem (I know, I know, it's not really a problem any more, but it's been bugging me since 1995).<br /><br /><span style="font-weight: bold;">Callbacks</span><br /><br />From what I've seen (although I admit, I haven't looked for some years) Agents and Tuples are not very aesthetically pleasing. In order to be able to provide effectively functions to a feature, I came up with callbacks.<br /><br />The syntax of a callback definition is simple:<br /><br /><pre> a_callback ":" <span style="font-weight: bold;">callback</span> [ "(" { formal_parameters "," } ")" ] [ ":" type ]</pre><br /><br />The names of the formal parameters may be used in the callback itself, which is a compound instruction contained in braces{}.<br /><br />e.g.<br /> some_container.for_each( { other_container.extend( item ) } )<br /><br />The callback can use attributes (including Current) of the class containing the callback code, the feature's parameters and locals, as well as the formal parameters of the callback. The identifier Result, used in a callback will refer only to the result of the callback, not the result of the feature.<br /><br />A callback that uses feature parameters or locals may not be assigned to anything, but merely passed from feature to feature or called. (This is to ensure the locals and parameters will be available<br />when the callback is made.)<br /><br />A callback (parameter) may be compared against Void, checked for storability (the_callback.is_storable, usually used in preconditions) or called with the same syntax as a feature call.<br /><br /><span style="font-weight: bold;">Preconditions in the right place<br /><span style="font-weight: bold;"></span></span><br />In some (all?) implementations of Eiffel the precondition checked for a routine is the precondition of the routine in the object's class rather than the interface's class. This seems to me to undermine the whole concept of these assertions by allowing code to be written that clearly breaks the preconditions of routines (since the preconditions may be weakened in subclasses).<br /><br />My compiler will check the interfaces' preconditions before making the call to the object; if you know some subclasses have weakened preconditions, access them through references to those classes!<br /><br /><span style="font-weight: bold;">Inspect class</span><br /><br />Back in December 2003, MacReiter made a suggestion to the Eiffel NICE Language list that the ?= operator should be replaced by a switch-like construct. I like this idea, so I'm intending to implement this variation on the theme:<br /><br /><pre> <span style="font-weight: bold;">inspect</span> <span style="font-weight: bold;">class</span> some_reference<br /> <span style="font-weight: bold;">when</span> SUBCLASS_A <span style="font-weight: bold;">then</span><br /> -- some_reference is usable in this compound<br /> -- instruction as a SUBCLASS_A reference<br /> some_reference.subclass_a_routine<br /> <span style="font-weight: bold;">when</span> NONE <span style="font-weight: bold;">then</span><br /> -- some_reference can only be Void<br /> <span style="font-weight: bold;">when</span> GENERAL <span style="font-weight: bold;">then</span><br /> -- some_reference is a non-Void reference<br /> <span style="font-weight: bold;">end</span></pre><br /><br />The types will be checked in order from most specific to least, i.e. if a type is a subclass of another class the subclass will match rather than the superclass. If two types are listed where neither is an ancestor of the other, they will be matched in the order they appear in the inspect instruction.<br /><br /><span style="font-weight: bold;">Multiple formal generic constraints</span><br /><br />Formal generics in Eiffel are constrained by a single type, e.g.:<br /><br /><span style="font-weight: bold;">class</span> BINARY_TREE[T -> COMPARABLE] ...<br /><span style="font-weight: bold;"></span><br />I suspect that sometimes it may be useful to have two or more constraints on a formal generic, and that could be written:<br /><br /><span style="font-weight: bold;">class</span> BINARY_NUMBER_TREE[T -> NUMERIC & COMPARABLE] ...<br /><br />Then, all actual generics used to obtain a type of BINARY_NUMBER_TREE would have to be a subclass of NUMERIC and COMPARABLE, but the two classes need not be related for all time.<br /><br />This would allow for more flexible class hierarchies since you can defer some decisions (like "Are all NUMERIC types also COMPARABLE?", how about complex numbers, where do they come in?)Simonhttp://www.blogger.com/profile/11289534660572407264noreply@blogger.com0