Dr_A: "The bit I don't quite understand is transferring data between hub and cog."
Actually the compiler does not help much linking these things.
Take a look at the ZiCog code. The Z80 registers are in HUB RAM. They are defined and used in Spin in the zicog_cpm.spin module.
Those same registers are accessed by the emulator itself in PASM in zicog.spin.
How does the PASM know where those register variables are in HUB? Well it's done through the "cpu_params" parameter of the "start" function. The "start" method gets the register addresses from the parameter list and sets them into pointers in DAT that are the loaded into the COG when the emulation is started. Then the PASM can use those pointers, like "a_reg" to read and write them in HUB.
You can also pass this kind of parameter list directly into PASM when starting a COG via the "par" register but then you have to read all the par stuff in PASM which eats COG space. So ZiCog uses Spin to set things up before loading the COG.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
You are fast approaching the requirement for SphinxOS which will allow the cogs to be loaded once with the drivers and then the hub is free to load the next program(s). This is what I have been concentrating on as when I have the time. These drivers also shift some of the buffers into the cogs, thereby reducing the hub requirements after loading. That's the main reason the fsrw (SD) drivers use 3 cogs - this is an area for rework.
I think it's time to read the manuals on the prop for explanations of how hub and cog work and interact. You have been making excellent progress, but now it's time to learn what you have taken for granted in extending existing code. Once you grasp the concepts I am sure you will find other ingenious ways to extend the prop.
When you compile a program and load it's binary (from eeprom, dowload or SD) the binary is loaded into hub ram (up to 32KB, with the balance being zeroed) and the a cog is booted to run the interpreter (which is loaded from ROM). When you do a coginit/cognew, 2KB is loaded from the cog DAT start point. Even if the cog code is less that 2KB, the whole 2KB is loaded, so the end pieces are often code for the next cog. It doesn't matter. Now, when you use RES in the DAT, the space is reserved but not initialised. What this means is that space is not taken for the RES locations in hub, so whatever follows in the next cog code gets loaded. This is why it is uncleared. It is also a trap for beginners if they place the RES before some code or LONGs in the cog, because it screws up the placement of code. What this all means is that once a cog is loaded, you can use this space for buffers, etc, provided you do not ned to reload the code again. It requires an undestanding of how to re-use this space also. *EOL* (end of lesson) *grin*
SDRAM is synchronous dynamic ram. It needs refreshing and is a PITA to interface with what we have. IMHO, just forget any form of DRAM and live with sram.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
I am starting to think that way too about the SDRAM. It was a thought, from the late 70's allied with some articals (AVR) bolted onto more modern chips. I think, to get it going, it will need just as many pins that you use for the 1/2 meg static and would need all the house keeping overheads. I will keep trying as I have the PCB's done.
At least I have tried taking the ironing down to 0.8mm, and may end up learning a bit about the modern rams.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
DR_A sent you a PM thank you sir.,,, Toby I remember your thread or I think I do about using CPLD for Ram expansion, I went out and got the Xilink/Avnet Cool runner II to try just that I didn't get very far Xilinx is a mother to learn I also have a copy of Aldec HDL
the Cool Runner has an Atmel chip built in so I found a website where someone was building a memory model for the Atmel chip the farthest I ever got was to send an output from the prop and read it with the Cool Runner board ,, I don't remember which system you were using but if you want to collaborate that would be awesome. I have even seen posts where some people had CPM running on this board in emulation but they didn't want to share code.
Oh I meant to ask a while back does anyone have a copy of Dbase and supercalc or lotus 123 for our CPM?
Hi Mike - I'll get those boards in the post 1st thing Monday.
Supercalc involves moving a floppy image to a hard image. I'll see if I have time when I get home. Not tested with VT100 but it might be good to throw some more programs at the VT100 code.
heater and cluso - thanks ++ for the explanations. I guess I know enough to be dangerous - eg I know that cogint loads bytes to the cog, but I didn't know it loads 2k, including any bits of code that are not actually part of the cog code.
Taking those two posts together, firstly I need to study sphinx. But I'm thinking of a system like the zicog where you have some hub longs defined in spin, the cog code is totally independent and portable and can sit anywhere, and there is a 'start' routine that passes the list of I/O long addresses to the cog code. A system of flag plus byte would probably be simplest - and have two of those per long. Say you have some keyboard code and it is running all the time and if bytes arrive it sets a flag.
I can see some changes to some of the standard obex objects. Some might not be possible to do with this system but I'll have to think about each one individually.
Reading the bytes ought to be fairly straightforward. Make each cog 'object' a 2k file and read it into a buffer area and then do a coginit. The harder bits will be the way to handle the connecting bits of spin. eg, take the vga driver with the .hex method that prints out a hex value. This is an inherent part of that object but the practicalities are that it ends up being split off and is part of the hub spin code but the cog code is in a different file on an sd card. It might make code maintainence confusing if objects are now split in two.
I wonder if it is possible to move supporting spin code into the cog code? eg instead of vgatext.hex('string'), you put 'string' into a buffer, then put a byte with a number into a location in hub ram, then put a flag byte in another location, then the cog code is checking the flag location and when it gets a flag it uses the number byte to then run a pasm subroutine and that grabs the string from the buffer. Hmm - some rewrites might be needed here. Though... I think a very similar scheme is being used by the ram driver code (which cluso wrote) so I think it is a matter of copying that concept.
I guess building an operating system using this scheme involves rewriting objects so they don't need supporting spin code. Pure cog objects where you tell it the location of hub ram pointers at the beginning. The ram driver will be easy. The keyboard ought to be possible but will be a bit of work. The serial driver might be tricky as it is almost full. Zicog is beyond me as I don't understand the overlay concept. VGA will be tedious as there is the huge amount of VT100 code - which may or may not fit into a cog though it could be almost worthwhile looking at overlays for that as these are bits of code that take a lot of space but are hardly ever called.
Disadvantage = need to rewrite lots of code.
Advantage = all objects can now be loaded in sequentially thus potentially freeing up to 14k of hub ram?
Drac & mikediv: The supercal disk in my SD is already in hdisk format
I have not tried it though.
re the OS: The mechanism of sending or receiving characters to the standard out and in routines is already working, as are a number of drivers for this. In particular, the pc serial and the keyboard and video are running. I almost have the 1-pin TV and 1-pin keyboard drivers done. How this passing works is that 1 long hub is defined for each of stdin and stdout. When it is "0" nothing is available, when non-zero (we add the 9th bit) a character is available. The buffers are internal to the cog so no hub is wasted. The SD driver currently takes about 15 longs and 3 cogs at the moment which is an issue for DacBlade.
Advantage = objects are being rewritten (for SphinxOS)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
I looked at some of the dracblade code again with a view to converting it purely to pasm/cog code. Not a task for the faint hearted as there are all sorts of intertwinings between the pasm and spin of each object.
So - another crazy idea. I'm presuming that once the hub has loaded all the cogs up this leaves a number of redundant blocks of data in the hub ram. We know where they are and also how big they are. So - would it be possible to use those blocks to bring in subroutines of spin code from elsewhere. I'm thinking of spin code that is hardly ever used, eg some VT100 commands.
This leads to the concept of relocatable spin code. I wrote such code years ago for Z80 assembler - essentially you only use Call and Jump Relative and DJNZ. But you don't use Jump.
In Basic you would not use GOTO - which is a good thing from a programming purists point of view but when you get into the detail you find that DO and FOR loops are also hidden GOTOs so you can't use those either. The only things you can use in code are Calls where you push the return onto a stack or similar, and Jump Relative where you jump back or forward n bytes. This means the code can be relocated.
So I'm wondering how spin is compiled. Say you have a 'repeat' loop. I gather that spin is interpreted, so what is that interpreted to? Specifically, if you write a 'repeat' loop in one location in hub, then write the same code in a different location, is the byte code the same? (I'm at work on a lunch break so can't test this out right now).
I think data bytes are possible to write in such a way as to be relocatable, as you can pass them via fixed locations. It is the 'jumping around in the code' instructions that are the unknowns.
Hmm - if this idea is remotely possible, maybe take all the DAT code for all the objects and put them all contiguously so at least you now have one big block of data that can be overwritten??
Addit: I've just had a brainwave. I hope this works. What I'm thinking is if I take all the objects and bundle them up into one huge program, then move all the cog code to the end of that code, then they should be contiguous. Then I could take the screen text buffer array which is 80x40 bytes = 3200 bytes, and once the cogs have been loaded up, use that space for the text buffer array. I think it should work. Anyway, I can do this in stages and test it as I go. I think the main change will be that I can't use the array directly - instead of a:=screen[noparse][[/noparse]100] I think I'll have to pass 100 to a special subroutine that calculates the offset and adds it to the start pointer and reads the byte directly.
Drac: A number of people are already re-using the cog data (DAT) for screen buffers. You will need to check the listing to see where the code is placed. Since we have SD files now, we can load the cogs from there using a stub loader, or other methods.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
I just spent an hour on this concept but it isn't working. Combining all the spin programs into one highlights all the myriad of variable names that happen to be the same. eg 'cog' and 'err'
I suppose that also highlights the duplicate longs that potentially could be saved. But I've had to put that to one side as I've also realised that commands like vgatext.color(screencolor) are all not going to work with that little . passing variables (and the way variables are returned). I'm not sure how to write that from within one single spin program.
And changing 20 variable names in an object will make it very difficult if that object gets updated by the original author.
Theoretically this is possible with lots of rewriting. I think I'll now pursue the idea of modifying CP/M after loading it.
Aaargh. So frustrating. 448k of ram I have but I'm running out of longs in the spin code. At least 10k of hub ram that is unused after bootup and I can't use it. I need some sort of circuit breaker - a way of looking at all this in a different light. Spin and pasm are too tightly bound to each other in objects. If only I could get just three objects to have their leftover cog code contiguous so I could make that the screen buffer area.
The CPLDs that I started with were Xilinx, but the older 95xxx ones. Partly as they seemed a bit less daunting, partly because they come in PLCC so I can socket them, but mostly because I levered a few of then off an old board. This allowed me to see if they were above my head before I wasted any time or money on them. Only one of the 9536s would talk to my homemade Parallel to JTAG interface ( as shown by Xilinx ) but it proved that the programming was possible. I assume that the other two were either banjaxed by the removal, or are protected. I use the 9.2 version of their software, mostly in the schematic form, Verilog or VDHL ... will have to be a learning for later on. One CPLD (9572 PLCC84)was going to be some of the "glue" logic for the Nascom rebuild, but then the DracBlade came along and I just started to think of other things. My problem is the constant hopping onto the next thing before the last is finished.
When I ventured the adding of a CPLD to a memory, about a year ago now, a few went into an extremely tight tail spin, I think they thought that I was fishing for the codes for the Hydra expansion (Lattice CPLD).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Dr_A, Sorry, could have saved you an hour but I had to rush into the office just as I was about to post suggesting that you don't try merging all your Spin code modules into one huge Spin file because I could already see that 1) There would probably be a lot of name clashes 2) Updating things would be a pain.
As for the problem with vgatext.color(screencolor) all you would have to do is remove the "vgatext." part. After all that function is now local to the huge module. But never mind it's just not a sound way to go.
What we really need is a way for BST or whatever compiler to emit the PASM sections into separate files that could then be written to SD card. Then when it comes to starting a PASM COG we would read the PASM from SD card file into a big (2K) general purpose buffer and start the COG with it.
Problem is, like in zicog.spin, the SPIN code tweaks some pointers in the PASM prior to starting the COG. As I described above. So that mechanism would have to be changed to tweak the correct LONGs in the 2K buffer instead.
Recycling the COG space use for PASM code once it is load is so fundamental I wonder why it is not possible in the standard Spin compilers from the beginning.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
Drac: I am so close to getting some of this done (the StdIn & StdOut). My 1-pin keyboard is running without the RC circuitry.
You will just have to hang on a bit longer and some of the code can disappear from your hub code. So just try to continue without this for another week or so, rather than wasting duplicated effort. I cannot do the CPM/Z80 stuff and that is definately your specialty.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
So much sage advice there in those last two posts.
Ok, yes I shall hang on and wait. I think the concept of recycling lost hub ram is ripe for some new code - after all it has the potential to free up almost half the hub ram of a big program, and hence double the size of available working memory.
Yes my forte probably is CP/M. I can now take a propeller chip and run a program and wake up a remote propeller chip and compile programs in C and Basic and other languages, all on that remote propeller, all via wireless.
I've been trying to do everything with pure peer to peer networks, but am running out of hub ram to run the data transfer protocols, so I think I'll resurrect the old idea of servers and clients, but with a modern twist where servers can talk to other servers and hence to their local cluster of clients. This is possible with CP/M and I already have a lot of the code working. A few hours ago I was stuck with a big brick wall in front of me, but I've had a series of brainwaves thanks to some recent posts on comp.os.cpm. I've scribbled these down before I forget them!
Notes re CP/M server program for wireless networks
The fundamental problem – only one board can transmit at any time. So strict protocols are needed to prevent data clashes between boards.
The server program:
* Acts as a router between two clients.
* Can direct bytes between client 1 and client 2
* Can serve up files
* Can search for and find other servers within range
* Can’t do a local DIR nor run other local programs nor go back to CP/M
Client boards/computers can:
* Run any local CP/M program
* Run a little program called NET4 that connects to any local board within wireless range
* Connect to a server board that can then handle routing to any client board within range of any server
Boards have names ALPHA BETA GAMMA etc
A byte string #ALP coming into serial port 2 will “wake up” a board. Any further bytes coming into that serial port are directed to the console as if typed on the local screen. Any output to the local screen also goes to port 2. You can disconnect by running the program PORT2OFF or LOGOFF (which does an OUT to port 71 (any byte)).
Boards also timeout and disconnect if no data transfer for 3 minutes. Boards can directly transfer files if they are in range with the NET4 program. This program can also handle direct logins to other boards.
But the problem here is chaining messages from, say ALPHA to BETA to GAMMA, particularly when ALPHA is not able to contact GAMMA directly.
So, consider a cluster ALPHA, BETA and SIGMA. And consider another cluster, GAMMA, EPSILON, and their server TAU.
ALPHA wants to log into GAMMA, but GAMMA is out of range.
So – ALPHA logs into SIGMA and SIGMA is running a network program. SIGMA sends back a message to say it is online and gives a menu. The menu includes local clients that SIGMA has tested it has good links with. It also includes a list of other servers that SIGMA has found (via longer range wireless for example). ALPHA might request a list of local clients for TAU. SIGMA then sends out a message to ALPHA not to print characters on its local display while it is talking to TAU. SIGMA then wakes up TAU and requests a list of local nodes. These might be transferred via xmodem in a small text file. SIGMA then sends this list on to ALPHA. The list includes GAMMA.
ALPHA might then choose to build a link to GAMMA. A message is sent to SIGMA to build the link. SIGMA replies to ALPHA saying the link is now active. ALPHA now types some characters, eg a DIR These are passed to SIGMA, SIGMA then sends a message back to ALPHA to ignore any RF characters for the moment. SIGMA forwards the characters on to TAU wrapped up in a packet. TAU wakes up GAMMA, sends the characters, waits till characters stop coming back (a 5 second timeout maybe), buffers them, wraps them up as a series of packets (or possibly as a file if there are lots and sends via xmodem), sends this on to SIGMA, who then wakes ALPHA back up and then sends them to ALPHA such that they appear on the screen as if it was a response to a DIR.
The concept can be daisy chained with servers.
An emergency sequence of 4 bytes can be sent to a server to reboot it if it is not responding. Servers have an autoexec file such that they run the server program automatically.
Since file transfers are possible, it is possible to upgrade server software via wireless.
The server software is a simple as possible. Functions include:
* Find local nodes (either manually or automatically from time to time)
* Find other servers.
* Pass messages to local clients
* Pass messages to other servers wrapped up in data packets
* Receive messages from other servers.
* Transfer files to and from clients.
* Send new versions of server software to other servers and reboot them.
The main role of the server is to wrap up data packets and route them on. Consider, we have a link set up between ALPHA and EPSILON and there are a whole lot of boards in between handling getting the data there. The user types DIR, but they have a long pause between the I and the R. Sooner or later the server decides that it may as well take DI and wrap it up into a packet and send it on. This needs to be done such that there are no data clashes, so the first thing is to tell the sending board to just buffer input for the moment and not forward it on. Then the server wraps this up in a packet with a source and destination and sends it on via the server network such that it gets to the nearest local server that is in range of the destination board. That server then “types” it into that destination board as if someone typed it on the keyboard. It then waits for a reply. In this case the command is incomplete, so the remote board will just wait, and the server network handles handshaking so that there are no data clashes.
What this means is that any client board can be either a new or an old computer/board. All it really needs is a serial port and the UART port codes to talk to that port. Usually that will be a few port numbers between 0 and 255. The ‘terminal’ program is incredibly simple – it just accepts keyboard input and routes it on to the serial port. It also scans the serial port and routes characters to the display. And it looks for a specific logoff character (I’m using ~, but maybe Esc would be better?)
The big disadvantage of wireless is that only one board can talk at any one time. So very strict protocols are needed for server software.
But the huge advantage is you don’t need fancy RS232 routers (which are very rare these days anyway). Even a server has just one serial port with a wireless transceiver module (standard RS232 signals, cost about $20). So this ought to be a way of linking old computers with new boards, or 20 old computers with each other etc.
At present, the Propeller network is using the command #BET to log into specific boards. This requires a layer underneath CP/M that runs some code when these bytes arrive. But I think with servers no layer is needed under CP/M, as any nominal logon sequence can be defined and the server can listen for that and respond accordingly. So, if you give up the (already working) direct links between two clients, and do everything via a server, the sacrifice is a small time delay, but the advantage is that no special code is needed so old computers (with a serial port) can become part of the network.
Obviously this is going to need testing with real code, but the basic principles are already working. It is possible right now to send and receive files wirelessly via xmodem and to log into remote computers wirelessly, so all that is needed now is server software with simple menus to make this an easy process for the user. And the good news is that about half that server software has already been written and tested. Stay tuned…
So actually all I need is a RamBlade, a keyboard and TV (both 1-pin versions) and 2 serial pins (stolen from the sram so only 128KB) and I can use them wirelessly. Nice & tiny.
BTW I have the 1-pin keyboard working. Just about to post alpha code (no buffering yet as I want this in cog not hub).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
I am sure that you have already been told that the protocol for the Node-2-Node stuff you want sounds just like the AX25 used on Packet radio. Usually it was on Bell modem 1200 and 2200Hz FSK. I haven' t touched if for 20 years+ but they all seemed to be Z80 + SIO based, TAPR seems to be there, in the dimming memories.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Clusso thank you sir got it, Toby I know the feeling I have about 9 projects all going on at the same time I think I have ADD but I just love jumping around and every time I come here someone else has posted some awesome thing I just have to try lol
Heater I don't know if you remember a while back you were trying to help me get CPM going on my Hydra I am sorry I didn't followed through , But here is where I am ,, I tried to somehow interface the Hydra 512K card and the SD card at the same time but the Hydra just does not have enough lines 0-7 that's it and they have to share VGA, Finally thinking it through I took my blank experimenters board and made up a much bigger circuit board that the Hydra can connect to I sort of ripped off DR_A's Ram circuit but ran into to many problems so I am now using a PIC 16F684 as a sort of memory manager and 2-64K Srams my intent is to make a Sram board for the Hydra that will allow me to use the SD card at the same time to hold all the CPM files. I would have liked to just make an all in one board that just fit the Hydra socket but you just need to many support chips (DIP) I can't do SMT at this point. Every time I try and think up a better way it always comes back to not enough prop pins left over I do have a couple of 1 meg eeproms serial if anyone has any thoughts please feel free to jump in but at this point I can not see any way to get CPM to work without extra hardware and a good amount at that.
Oh Toby I have decided to try and built my own board as well, I am struggling trying to do the schematic in Eagle Pro so I can have real boards made when I am done but right now I am just wire wrapping it will have 4 Hydra sockets for expansion buss
A Motorola 6800 or 6809 I always loved Moto stuff and a Pic 877 Oh and of course a prop chip I have always wanted to build a multi MCU board since Clusso got me hooked. I dont know if you guys know anything about FLEX OS for the Moto chips but a multi OS like CPM and FLEX would be cool I don't know why I just feel compelled LOL Oh I don't have one in PIC but it will have SD , if any of you guys want to play along I also have a bunch of 3 1/4 floppies drives I know it would be hugely stupid 1.4 meg floppies but it would be retro ,, This is probably the biggest reason I suck at programing I just can't stay focused. lol
and of course if anyone wants a floppy they are free I still have 3 1/4 floppies but I dumped all my 5 and 8 inch stuff I actually found a 5 floppy looking through my junk and an original giant case IBM PC AT with a 386sx 128K and a 5/14 floppy and a 5 MEG 5 1/4 hard disk drive
remember MFM and RLL guys? it actually still works it had a very old VGA card serial ports and a parallel I cant believe how big these cases where
The tops of Wire wraps always look cute, the bottoms don't.
I was in the "mass storage" bit with my 8052/ Z80 thoughts when the Prop came onto my radar. Then I thought Video/Serial could be the Prop's bit. Then SD cards came ont the Props, then Z80 emulation .... I must stick to one thing otherwise the tricky bits make me have a go at the other bits again.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
mikediv: Brave man. I still don't know anything much about the Hydra RAM expansion. I suspect it takes more PASM code to drive it than will fit in the COG with the Z80 emulation.
Not sure, so if I were attempting it my approach would be to forget about VGA and keyboard and such. Just get a PASM program reading and writing bytes from the external RAM, random access, first. Then you know exactly how many longs you need to do that and can see if it will fit into zicog.
If it fits then move on to getting emulation and CP/M running using the Prop Plug or whatever link back to the PC as a serial terminal interface. Use the terminal emulator in BST.
If that ever gets working then worry about how we are going to do peripherals, keyboard and VGA.
It's a long road....
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
With the ever-increasing number of XMM solutions, have you considered decoupling ZiCog from the memory access?
I have not looked at the sources, so I don't know how easy the following would be - or if you have thought of something similar.
Loosely, there are three types of memory accesses:
- code fetch
- data read
- data write
I am thinking of a solution where the memory access is handed off to another cog, and ZiCog requests memory actions through hub locations.
Consider:
codefetch long 0
coder long 0
dataread long 0
datar long 0
datawrite long 0
dataw long 0
' When ZiCog wants to read an instruction from 'zpc', it does the following:
wrlong zpc,codefetch
cfl rdlong code, coder wz
if_z jmp #cfl ' when NOP (0) read, reader returns $1000_0000
' When ZiCog wants to read the byte at (HL)
wrlong hl,dataread
drl rdlong acc, datar wz
if_z jmp #drl ' when zero data byte read, returns $1000_0000
' when ZiCog wants to write (HL)
wrlong dataw, acc
wrlong datawrite, HL
The beauty of this approach is that it TOTALLY decouples ZiCog from specific XMM implementation, and the memory cog can try to do all sorts of caching etc.
Adding new XMM targets is trivial.
Frees up some LONGs in ZiCog
Doing split I/D for 128K memory (which I think MP/M supported) is easy.
Doing banked memory on any XMM becomes MUCH easier.
Even better, in any instruction that is not a JUMP/CALL, the next instruction read can be done in parallel with executing the current instruction!
Simply ask for the next instruction before processing the current one.
The hub delay slots can also be used [noparse]:)[/noparse]
I think it would potentiall run faster.
This would also make it trivial to provide breakpoints for execution or data access, and monitoring locations, performance etc.
On the hardware side...
This would also allow a super-cheap ZiCog config I was thinking about, by using two MCP23K256 SPI ram's or FRAMs (with a speed penalty)
What do you guys think?
heater said...
mikediv: Brave man. I still don't know anything much about the Hydra RAM expansion. I suspect it takes more PASM code to drive it than will fit in the COG with the Z80 emulation.
Not sure, so if I were attempting it my approach would be to forget about VGA and keyboard and such. Just get a PASM program reading and writing bytes from the external RAM, random access, first. Then you know exactly how many longs you need to do that and can see if it will fit into zicog.
If it fits then move on to getting emulation and CP/M running using the Prop Plug or whatever link back to the PC as a serial terminal interface. Use the terminal emulator in BST.
If that ever gets working then worry about how we are going to do peripherals, keyboard and VGA.
Heater when you say get the it to read and write ram do you mean the prop ram or the external memory, And you are correct the Hydra 512K ram card is kind of unique in my opinion anyway, becuase like I said the biggest problem for me anyway is I can not use the SD card at the same time one of the other so I have the CPM files on SD and you need more memory that the props 32K so if I could load the CPM files and have the 512K of ram I could do somehting I also tried loading the CPM files to the Hydras big 1 Meg eeprom but its not enough room
to hold the CPM files and then I hit that darn 32K anyway so if I use the upper eeprom as asset I cant address it. Heater you and Clusso are kind of memory gurus for the prop in order to get around the props 32K limitations and say connect a 64 Sram and have it addressed continuously we would need a whole prop OS wouldn't we? DR_A Toby feel free to jump in I understand how to interface Sram to a MCU or CPU to be honest its actually easy what I don't understand fully is why it has to be so hard with a prop I don't fully understand why the 32K limit is it becuase of the prop itself or the IDE?
Actually the more I think about this ,, Bill, Clusso, Heater, DR_A all you guys have successfully added Ram to the prop can anyone just give me a quick Vtech on my above question.
The prop does not have an external address / data bus.
All XMM solutions construct an external address and data bus using propeller I/O pins (and various combinations of propeller pins and latches).
This chews up propeller pins, and XMM is generally noticably slower than hub access.
There is a fairly direct relationship between the number of pins used, and the speed of random external memory access. Different XMM implementations are optimized for different usage patterns and Propeller pin usage.
mikediv said...
Heater when you say get the it to read and write ram do you mean the prop ram or the external memory, And you are correct the Hydra 512K ram card is kind of unique in my opinion anyway, becuase like I said the biggest problem for me anyway is I can not use the SD card at the same time one of the other so I have the CPM files on SD and you need more memory that the props 32K so if I could load the CPM files and have the 512K of ram I could do somehting I also tried loading the CPM files to the Hydras big 1 Meg eeprom but its not enough room
to hold the CPM files and then I hit that darn 32K anyway so if I use the upper eeprom as asset I cant address it. Heater you and Clusso are kind of memory gurus for the prop in order to get around the props 32K limitations and say connect a 64 Sram and have it addressed continuously we would need a whole prop OS wouldn't we? DR_A Toby feel free to jump in I understand how to interface Sram to a MCU or CPU to be honest its actually easy what I don't understand fully is why it has to be so hard with a prop I don't fully understand why the 32K limit is it becuase of the prop itself or the IDE?
Actually the more I think about this ,, Bill, Clusso, Heater, DR_A all you guys have successfully added Ram to the prop can anyone just give me a quick Vtech on my above question.
@Mike, Everything is a compromise with this circuit. There are not enough prop pins. There is not enough prop memory. You need the ram fast enough to run the emulation but if you go for super fast you don't have enough pins as speed is inversely proportional to the number of prop pins you use. (serial ram is at one end of that extreme and probably is too slow).
Is there a link to the hydra schematic?
Mike, do you have a schematic of what you are working on now?
@Cluso - it would be cool to have your ramblade able to log into a network. I think we have everything we need there. Just need the server software.
Re packet radio - yes absolutely and that is the inspiration for a lot of this.
Re decoupling zicog and ram. The problem with the dracblade is no spare cogs. 1 for the interpreter, 1 keyboard, 2 vga, 1 serial, 1 zicog, 1 ram latch, 1 sd card. But it is an intriguing possibility, especially since once you have sent up ram latches is it much quicker to get the second, third byte etc. Mathematically, what is the optimum number of bytes to prefetch? And I guess you need some management code to do that prefetching. On the dracblade, everything is a compromise and I think that code would max out the hub ram (until cluso does the clever code he is working on...). But for the zicog on another emulation, it would be a very useful concept.
@mike- heater has had CP/M running in 32k on a propeller with no external ram. The problem is there isn't room for most programs to then run.
On the DracBlade, your "ram latch" cog would be the "xmm server", servicing the memory requests, so no need for an extra cog.
On a SPIBlade, the "xmm server" would presumably pre-fetch internally, as it can run in parallel with Zicog. I think for some applications even a 50% speed hit would be worth the reduced pin count! Frankly, I'd be tempted to try a paging approach, with say a 16-64 page working set, with LRU replacement. It should hide most of the slow access of SPI ram.
I suspect that for non-SPI memory solutions the decoupling with prefetch could be an overall speed win.
As far as hub ram... if you use a 64KB EEPROM, you could load the drivers one at a time, and use only a 2K buffer area to hold drivers - which could later be re-used for SD card buffers.
Dr_Acula said...
Re decoupling zicog and ram. The problem with the dracblade is no spare cogs. 1 for the interpreter, 1 keyboard, 2 vga, 1 serial, 1 zicog, 1 ram latch, 1 sd card. But it is an intriguing possibility, especially since once you have sent up ram latches is it much quicker to get the second, third byte etc. Mathematically, what is the optimum number of bytes to prefetch? And I guess you need some management code to do that prefetching. On the dracblade, everything is a compromise and I think that code would max out the hub ram (until cluso does the clever code he is working on...). But for the zicog on another emulation, it would be a very useful concept.
What we really need is a way for BST or whatever compiler to emit the PASM sections into separate files that could then be written to SD card. Then when it comes to starting a PASM COG we would read the PASM from SD card file into a big (2K) general purpose buffer and start the COG with it.
Why not put a very small method in each object that simply returns the address of the relevant DAT portion, then write a top object that includes all the subobjects. Have that top object write the 2k chunks to SD card. That way you can run that object whenever you change the code in any of the sub objects, and it will automatically update the driver binaries on the SD card for you.
...alternatively...
bstc will drop the dat section from the top object as a raw .dat file, but it won't do that for sub-objects. You could do something like
for i in *.spin ; do bstc -c $i ; done
That would drop a .dat file for each spin object in the directory. You could then just take the ones you wanted and pop them onto the SD card. I like the dedicated top object better though.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Life may be "too short", but it's the longest thing we ever do.
Ah, a post from Brad! Brad has a Compiler. This could be very useful. All the models I've been considering all involve cog programs that are relocatable anywhere in memory. Hence you can't referance any locations in hub by name - unless those locations happen to be fixed eg in high ram. This entails a complete rewrite of most objects because most objects have references to hub locations scattered randomly all through the code. Which is no surprise really.
But I wonder if a compiler could be modified to handle this? Consider:
The compiler goes through all this one at a time and puts the cog code in where it is meant to and when it is run the coginit moves the cog code into a cog and there is now a pile of wasted bytes in hub ram.
What if the compiler were able to compile all the DAT code, complete with references to hub ram locations, but when it got to the end of the DAT section, it reset the pointers for hub ram locations as if that DAT code had never existed. Eg back to the end of the PUB2 code.
It then saves the cog DAT code as a seperate file.
The main source code now has PUB1 PUB2 PUB3 with no cog code in it.
The cog code is loaded seperately by a dedicated spin routine and place in a cog. But any references to any hub locations are correct because the compiler knew where they should be.
I suppose the questions are - would this work, and if it would, how hard would it be to code for a compiler?
Hi guys I am sorry I keep asking these questions, I stripped my DR_A board down to just the prop, eeprom , max232 chip of course I left all the componets on it but I pulled all the other IS's including the SD card, I have been running tests ll night with just the prop portion I have tested all the prop I/O even connected LEDs and have them blinking on and off, I have run square wave stuff PWM even conneted a servo everything is working just fine with the prop tool software 1.2.7 just for kicks I went to run BST ,,, and BST can not find the prop I thoguht it finally died but the prop tool is working just fine F7 com port 13 and all my test programs are still working but no matter what I do BST will not find the board????? Am I onto something or does BST need the other support chips to work with this board. if thats not the case can anyone figure out why BST would not work but the prop tool would wor just fine??? Guys I know I have been beating this to death DR_A when I get my other boards I think I might send you this to takea look at but more to stop me from constantly working on it I just hate being beat and if you don't want it maybe I will send it to Toby lol .. I just feel that I am close it will run CPM for only about 30 seconds - a minute or two but it has been working with just the prop chips and the prop tool all night without a hicup ???? Thanks guys for putting up with me
I swear I will contribute CPM stuff as soon as I get a system running
Mike. ·
Dr_Acula said...
Ah, a post from Brad! Brad has a Compiler. This could be very useful. All the models I've been considering all involve cog programs that are relocatable anywhere in memory. Hence you can't referance any locations in hub by name - unless those locations happen to be fixed eg in high ram. This entails a complete rewrite of most objects because most objects have references to hub locations scattered randomly all through the code. Which is no surprise really.
Well, it kinda is.. DAT code can't reference any other areas (PUB/PRI/VAR) by symbol name. So you need a SPIN routine to load a DAT symbol with the address of a VAR location for example.
In this context, the DAT block is completely stand-alone, but the SPIN code knows how to load some locations prior to starting it up. You can achieve a similar thing quite easily by preloading a series of longs in VAR for example, and having your cog code just block copy them from an address passed through par when you launch the cog. That way there is no need for the SPIN code to know the offsets in the DAT block or do any pre-launch tweaking.
Dr_Acula said...
But I wonder if a compiler could be modified to handle this? Consider:
Is that how you'd like the layout to be? The compiler _always_ places the *entire* dat block at the start of the object. So it's all DAT up until the first PUB method.
DAT
PUB1
PUB2
PRI1
PRI2
..end
Dr_Acula said...
The compiler goes through all this one at a time and puts the cog code in where it is meant to and when it is run the coginit moves the cog code into a cog and there is now a pile of wasted bytes in hub ram.
I can see this working in one particular context.
Each DAT block would have to be cog code only, load all its parameters from the PAR variable and be launched with a single cognet(@start,@parms)
Now, if you are going to do that, then there is really zero reason to have the DAT block in the same file as the SPIN code, as the SPIN code is not allowed to reference any of the symbols in the DAT block (as you plan to relocate it). If you were going to do that, then my previous idea of just compiling the DAT blocks separately is a lot easier to achieve _now_.
Personally I quite often use the DAT block as buffers for an object after the COG is loaded if I have no need to re-load the cog.
One thing I did give a cursory glance at was consolidating all the DAT blocks at the end of the code block, and after VAR (so squeezed in between the end of VAR and the stack) but I just never saw it buying enough advantage to be worth the significant re-write required to shuffle everything around and break the object model.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Life may be "too short", but it's the longest thing we ever do.
Re BST not working, Brad is online here so he can probably best answer that, but given you have prop tool working but not BST, I'd be wondering about a setup somewhere. If I change from port 1 to port 2 or 3 (I like having lots of serial ports!) then BST gives an error and then you can run "find prop" in a little menu and then the second time you try a compile it works. Are you getting that error block?
Also - help is on the way. Three boards are winging their way to you - should be at the airport by tonight.
Re Brad, yes I need to digest that in the context of a real object, eg the keyboard object. Most objects seem to have some tiny setup PUBs associated with them but I agree, it ought to be possible to pass all possible locations and parameters via the setup.
I have answered Bill's ideas on the ZiCog thread as I thought that was the most relevant place to do it. Hope no-one minds this.
Nice to see you lurking with ideas Brad. Yes, I think just compling seperate Dat's is the way to go to save hub space. We would just require a cog loader to locate the file on SD, find the length and load it. This approach could become part of SphinxOS.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ Links to other interesting threads:
Comments
Actually the compiler does not help much linking these things.
Take a look at the ZiCog code. The Z80 registers are in HUB RAM. They are defined and used in Spin in the zicog_cpm.spin module.
Those same registers are accessed by the emulator itself in PASM in zicog.spin.
How does the PASM know where those register variables are in HUB? Well it's done through the "cpu_params" parameter of the "start" function. The "start" method gets the register addresses from the parameter list and sets them into pointers in DAT that are the loaded into the COG when the emulation is started. Then the PASM can use those pointers, like "a_reg" to read and write them in HUB.
You can also pass this kind of parameter list directly into PASM when starting a COG via the "par" register but then you have to read all the par stuff in PASM which eats COG space. So ZiCog uses Spin to set things up before loading the COG.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
You are fast approaching the requirement for SphinxOS which will allow the cogs to be loaded once with the drivers and then the hub is free to load the next program(s). This is what I have been concentrating on as when I have the time. These drivers also shift some of the buffers into the cogs, thereby reducing the hub requirements after loading. That's the main reason the fsrw (SD) drivers use 3 cogs - this is an area for rework.
I think it's time to read the manuals on the prop for explanations of how hub and cog work and interact. You have been making excellent progress, but now it's time to learn what you have taken for granted in extending existing code. Once you grasp the concepts I am sure you will find other ingenious ways to extend the prop.
When you compile a program and load it's binary (from eeprom, dowload or SD) the binary is loaded into hub ram (up to 32KB, with the balance being zeroed) and the a cog is booted to run the interpreter (which is loaded from ROM). When you do a coginit/cognew, 2KB is loaded from the cog DAT start point. Even if the cog code is less that 2KB, the whole 2KB is loaded, so the end pieces are often code for the next cog. It doesn't matter. Now, when you use RES in the DAT, the space is reserved but not initialised. What this means is that space is not taken for the RES locations in hub, so whatever follows in the next cog code gets loaded. This is why it is uncleared. It is also a trap for beginners if they place the RES before some code or LONGs in the cog, because it screws up the placement of code. What this all means is that once a cog is loaded, you can use this space for buffers, etc, provided you do not ned to reload the code again. It requires an undestanding of how to re-use this space also. *EOL* (end of lesson) *grin*
SDRAM is synchronous dynamic ram. It needs refreshing and is a PITA to interface with what we have. IMHO, just forget any form of DRAM and live with sram.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
I am starting to think that way too about the SDRAM. It was a thought, from the late 70's allied with some articals (AVR) bolted onto more modern chips. I think, to get it going, it will need just as many pins that you use for the 1/2 meg static and would need all the house keeping overheads. I will keep trying as I have the PCB's done.
At least I have tried taking the ironing down to 0.8mm, and may end up learning a bit about the modern rams.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
the Cool Runner has an Atmel chip built in so I found a website where someone was building a memory model for the Atmel chip the farthest I ever got was to send an output from the prop and read it with the Cool Runner board ,, I don't remember which system you were using but if you want to collaborate that would be awesome. I have even seen posts where some people had CPM running on this board in emulation but they didn't want to share code.
Oh I meant to ask a while back does anyone have a copy of Dbase and supercalc or lotus 123 for our CPM?
Post Edited (mikediv) : 1/31/2010 1:39:33 AM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
Supercalc involves moving a floppy image to a hard image. I'll see if I have time when I get home. Not tested with VT100 but it might be good to throw some more programs at the VT100 code.
heater and cluso - thanks ++ for the explanations. I guess I know enough to be dangerous - eg I know that cogint loads bytes to the cog, but I didn't know it loads 2k, including any bits of code that are not actually part of the cog code.
Taking those two posts together, firstly I need to study sphinx. But I'm thinking of a system like the zicog where you have some hub longs defined in spin, the cog code is totally independent and portable and can sit anywhere, and there is a 'start' routine that passes the list of I/O long addresses to the cog code. A system of flag plus byte would probably be simplest - and have two of those per long. Say you have some keyboard code and it is running all the time and if bytes arrive it sets a flag.
I can see some changes to some of the standard obex objects. Some might not be possible to do with this system but I'll have to think about each one individually.
Reading the bytes ought to be fairly straightforward. Make each cog 'object' a 2k file and read it into a buffer area and then do a coginit. The harder bits will be the way to handle the connecting bits of spin. eg, take the vga driver with the .hex method that prints out a hex value. This is an inherent part of that object but the practicalities are that it ends up being split off and is part of the hub spin code but the cog code is in a different file on an sd card. It might make code maintainence confusing if objects are now split in two.
I wonder if it is possible to move supporting spin code into the cog code? eg instead of vgatext.hex('string'), you put 'string' into a buffer, then put a byte with a number into a location in hub ram, then put a flag byte in another location, then the cog code is checking the flag location and when it gets a flag it uses the number byte to then run a pasm subroutine and that grabs the string from the buffer. Hmm - some rewrites might be needed here. Though... I think a very similar scheme is being used by the ram driver code (which cluso wrote) so I think it is a matter of copying that concept.
I guess building an operating system using this scheme involves rewriting objects so they don't need supporting spin code. Pure cog objects where you tell it the location of hub ram pointers at the beginning. The ram driver will be easy. The keyboard ought to be possible but will be a bit of work. The serial driver might be tricky as it is almost full. Zicog is beyond me as I don't understand the overlay concept. VGA will be tedious as there is the huge amount of VT100 code - which may or may not fit into a cog though it could be almost worthwhile looking at overlays for that as these are bits of code that take a lot of space but are hardly ever called.
Disadvantage = need to rewrite lots of code.
Advantage = all objects can now be loaded in sequentially thus potentially freeing up to 14k of hub ram?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
Post Edited (Dr_Acula) : 1/31/2010 2:37:43 AM GMT
I have not tried it though.
re the OS: The mechanism of sending or receiving characters to the standard out and in routines is already working, as are a number of drivers for this. In particular, the pc serial and the keyboard and video are running. I almost have the 1-pin TV and 1-pin keyboard drivers done. How this passing works is that 1 long hub is defined for each of stdin and stdout. When it is "0" nothing is available, when non-zero (we add the 9th bit) a character is available. The buffers are internal to the cog so no hub is wasted. The SD driver currently takes about 15 longs and 3 cogs at the moment which is an issue for DacBlade.
Advantage = objects are being rewritten (for SphinxOS)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
I looked at some of the dracblade code again with a view to converting it purely to pasm/cog code. Not a task for the faint hearted as there are all sorts of intertwinings between the pasm and spin of each object.
So - another crazy idea. I'm presuming that once the hub has loaded all the cogs up this leaves a number of redundant blocks of data in the hub ram. We know where they are and also how big they are. So - would it be possible to use those blocks to bring in subroutines of spin code from elsewhere. I'm thinking of spin code that is hardly ever used, eg some VT100 commands.
This leads to the concept of relocatable spin code. I wrote such code years ago for Z80 assembler - essentially you only use Call and Jump Relative and DJNZ. But you don't use Jump.
In Basic you would not use GOTO - which is a good thing from a programming purists point of view but when you get into the detail you find that DO and FOR loops are also hidden GOTOs so you can't use those either. The only things you can use in code are Calls where you push the return onto a stack or similar, and Jump Relative where you jump back or forward n bytes. This means the code can be relocated.
So I'm wondering how spin is compiled. Say you have a 'repeat' loop. I gather that spin is interpreted, so what is that interpreted to? Specifically, if you write a 'repeat' loop in one location in hub, then write the same code in a different location, is the byte code the same? (I'm at work on a lunch break so can't test this out right now).
I think data bytes are possible to write in such a way as to be relocatable, as you can pass them via fixed locations. It is the 'jumping around in the code' instructions that are the unknowns.
Hmm - if this idea is remotely possible, maybe take all the DAT code for all the objects and put them all contiguously so at least you now have one big block of data that can be overwritten??
Addit: I've just had a brainwave. I hope this works. What I'm thinking is if I take all the objects and bundle them up into one huge program, then move all the cog code to the end of that code, then they should be contiguous. Then I could take the screen text buffer array which is 80x40 bytes = 3200 bytes, and once the cogs have been loaded up, use that space for the text buffer array. I think it should work. Anyway, I can do this in stages and test it as I go. I think the main change will be that I can't use the array directly - instead of a:=screen[noparse][[/noparse]100] I think I'll have to pass 100 to a special subroutine that calculates the offset and adds it to the start pointer and reads the byte directly.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
Post Edited (Dr_Acula) : 1/31/2010 6:07:33 AM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
I suppose that also highlights the duplicate longs that potentially could be saved. But I've had to put that to one side as I've also realised that commands like vgatext.color(screencolor) are all not going to work with that little . passing variables (and the way variables are returned). I'm not sure how to write that from within one single spin program.
And changing 20 variable names in an object will make it very difficult if that object gets updated by the original author.
Theoretically this is possible with lots of rewriting. I think I'll now pursue the idea of modifying CP/M after loading it.
Aaargh. So frustrating. 448k of ram I have but I'm running out of longs in the spin code. At least 10k of hub ram that is unused after bootup and I can't use it. I need some sort of circuit breaker - a way of looking at all this in a different light. Spin and pasm are too tightly bound to each other in objects. If only I could get just three objects to have their leftover cog code contiguous so I could make that the screen buffer area.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
Post Edited (Dr_Acula) : 1/31/2010 10:41:06 AM GMT
The CPLDs that I started with were Xilinx, but the older 95xxx ones. Partly as they seemed a bit less daunting, partly because they come in PLCC so I can socket them, but mostly because I levered a few of then off an old board. This allowed me to see if they were above my head before I wasted any time or money on them. Only one of the 9536s would talk to my homemade Parallel to JTAG interface ( as shown by Xilinx ) but it proved that the programming was possible. I assume that the other two were either banjaxed by the removal, or are protected. I use the 9.2 version of their software, mostly in the schematic form, Verilog or VDHL ... will have to be a learning for later on. One CPLD (9572 PLCC84)was going to be some of the "glue" logic for the Nascom rebuild, but then the DracBlade came along and I just started to think of other things. My problem is the constant hopping onto the next thing before the last is finished.
When I ventured the adding of a CPLD to a memory, about a year ago now, a few went into an extremely tight tail spin, I think they thought that I was fishing for the codes for the Hydra expansion (Lattice CPLD).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
As for the problem with vgatext.color(screencolor) all you would have to do is remove the "vgatext." part. After all that function is now local to the huge module. But never mind it's just not a sound way to go.
What we really need is a way for BST or whatever compiler to emit the PASM sections into separate files that could then be written to SD card. Then when it comes to starting a PASM COG we would read the PASM from SD card file into a big (2K) general purpose buffer and start the COG with it.
Problem is, like in zicog.spin, the SPIN code tweaks some pointers in the PASM prior to starting the COG. As I described above. So that mechanism would have to be changed to tweak the correct LONGs in the 2K buffer instead.
Recycling the COG space use for PASM code once it is load is so fundamental I wonder why it is not possible in the standard Spin compilers from the beginning.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
You will just have to hang on a bit longer and some of the code can disappear from your hub code. So just try to continue without this for another week or so, rather than wasting duplicated effort. I cannot do the CPM/Z80 stuff and that is definately your specialty.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
Ok, yes I shall hang on and wait. I think the concept of recycling lost hub ram is ripe for some new code - after all it has the potential to free up almost half the hub ram of a big program, and hence double the size of available working memory.
Yes my forte probably is CP/M. I can now take a propeller chip and run a program and wake up a remote propeller chip and compile programs in C and Basic and other languages, all on that remote propeller, all via wireless.
I've been trying to do everything with pure peer to peer networks, but am running out of hub ram to run the data transfer protocols, so I think I'll resurrect the old idea of servers and clients, but with a modern twist where servers can talk to other servers and hence to their local cluster of clients. This is possible with CP/M and I already have a lot of the code working. A few hours ago I was stuck with a big brick wall in front of me, but I've had a series of brainwaves thanks to some recent posts on comp.os.cpm. I've scribbled these down before I forget them!
Notes re CP/M server program for wireless networks
The fundamental problem – only one board can transmit at any time. So strict protocols are needed to prevent data clashes between boards.
The server program:
* Acts as a router between two clients.
* Can direct bytes between client 1 and client 2
* Can serve up files
* Can search for and find other servers within range
* Can’t do a local DIR nor run other local programs nor go back to CP/M
Client boards/computers can:
* Run any local CP/M program
* Run a little program called NET4 that connects to any local board within wireless range
* Connect to a server board that can then handle routing to any client board within range of any server
Boards have names ALPHA BETA GAMMA etc
A byte string #ALP coming into serial port 2 will “wake up” a board. Any further bytes coming into that serial port are directed to the console as if typed on the local screen. Any output to the local screen also goes to port 2. You can disconnect by running the program PORT2OFF or LOGOFF (which does an OUT to port 71 (any byte)).
Boards also timeout and disconnect if no data transfer for 3 minutes. Boards can directly transfer files if they are in range with the NET4 program. This program can also handle direct logins to other boards.
But the problem here is chaining messages from, say ALPHA to BETA to GAMMA, particularly when ALPHA is not able to contact GAMMA directly.
So, consider a cluster ALPHA, BETA and SIGMA. And consider another cluster, GAMMA, EPSILON, and their server TAU.
ALPHA wants to log into GAMMA, but GAMMA is out of range.
So – ALPHA logs into SIGMA and SIGMA is running a network program. SIGMA sends back a message to say it is online and gives a menu. The menu includes local clients that SIGMA has tested it has good links with. It also includes a list of other servers that SIGMA has found (via longer range wireless for example). ALPHA might request a list of local clients for TAU. SIGMA then sends out a message to ALPHA not to print characters on its local display while it is talking to TAU. SIGMA then wakes up TAU and requests a list of local nodes. These might be transferred via xmodem in a small text file. SIGMA then sends this list on to ALPHA. The list includes GAMMA.
ALPHA might then choose to build a link to GAMMA. A message is sent to SIGMA to build the link. SIGMA replies to ALPHA saying the link is now active. ALPHA now types some characters, eg a DIR These are passed to SIGMA, SIGMA then sends a message back to ALPHA to ignore any RF characters for the moment. SIGMA forwards the characters on to TAU wrapped up in a packet. TAU wakes up GAMMA, sends the characters, waits till characters stop coming back (a 5 second timeout maybe), buffers them, wraps them up as a series of packets (or possibly as a file if there are lots and sends via xmodem), sends this on to SIGMA, who then wakes ALPHA back up and then sends them to ALPHA such that they appear on the screen as if it was a response to a DIR.
The concept can be daisy chained with servers.
An emergency sequence of 4 bytes can be sent to a server to reboot it if it is not responding. Servers have an autoexec file such that they run the server program automatically.
Since file transfers are possible, it is possible to upgrade server software via wireless.
The server software is a simple as possible. Functions include:
* Find local nodes (either manually or automatically from time to time)
* Find other servers.
* Pass messages to local clients
* Pass messages to other servers wrapped up in data packets
* Receive messages from other servers.
* Transfer files to and from clients.
* Send new versions of server software to other servers and reboot them.
The main role of the server is to wrap up data packets and route them on. Consider, we have a link set up between ALPHA and EPSILON and there are a whole lot of boards in between handling getting the data there. The user types DIR, but they have a long pause between the I and the R. Sooner or later the server decides that it may as well take DI and wrap it up into a packet and send it on. This needs to be done such that there are no data clashes, so the first thing is to tell the sending board to just buffer input for the moment and not forward it on. Then the server wraps this up in a packet with a source and destination and sends it on via the server network such that it gets to the nearest local server that is in range of the destination board. That server then “types” it into that destination board as if someone typed it on the keyboard. It then waits for a reply. In this case the command is incomplete, so the remote board will just wait, and the server network handles handshaking so that there are no data clashes.
What this means is that any client board can be either a new or an old computer/board. All it really needs is a serial port and the UART port codes to talk to that port. Usually that will be a few port numbers between 0 and 255. The ‘terminal’ program is incredibly simple – it just accepts keyboard input and routes it on to the serial port. It also scans the serial port and routes characters to the display. And it looks for a specific logoff character (I’m using ~, but maybe Esc would be better?)
The big disadvantage of wireless is that only one board can talk at any one time. So very strict protocols are needed for server software.
But the huge advantage is you don’t need fancy RS232 routers (which are very rare these days anyway). Even a server has just one serial port with a wireless transceiver module (standard RS232 signals, cost about $20). So this ought to be a way of linking old computers with new boards, or 20 old computers with each other etc.
At present, the Propeller network is using the command #BET to log into specific boards. This requires a layer underneath CP/M that runs some code when these bytes arrive. But I think with servers no layer is needed under CP/M, as any nominal logon sequence can be defined and the server can listen for that and respond accordingly. So, if you give up the (already working) direct links between two clients, and do everything via a server, the sacrifice is a small time delay, but the advantage is that no special code is needed so old computers (with a serial port) can become part of the network.
Obviously this is going to need testing with real code, but the basic principles are already working. It is possible right now to send and receive files wirelessly via xmodem and to log into remote computers wirelessly, so all that is needed now is server software with simple menus to make this an easy process for the user. And the good news is that about half that server software has already been written and tested. Stay tuned…
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
So actually all I need is a RamBlade, a keyboard and TV (both 1-pin versions) and 2 serial pins (stolen from the sram so only 128KB) and I can use them wirelessly. Nice & tiny.
BTW I have the 1-pin keyboard working. Just about to post alpha code (no buffering yet as I want this in cog not hub).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
I am sure that you have already been told that the protocol for the Node-2-Node stuff you want sounds just like the AX25 used on Packet radio. Usually it was on Bell modem 1200 and 2200Hz FSK. I haven' t touched if for 20 years+ but they all seemed to be Z80 + SIO based, TAPR seems to be there, in the dimming memories.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Heater I don't know if you remember a while back you were trying to help me get CPM going on my Hydra I am sorry I didn't followed through , But here is where I am ,, I tried to somehow interface the Hydra 512K card and the SD card at the same time but the Hydra just does not have enough lines 0-7 that's it and they have to share VGA, Finally thinking it through I took my blank experimenters board and made up a much bigger circuit board that the Hydra can connect to I sort of ripped off DR_A's Ram circuit but ran into to many problems so I am now using a PIC 16F684 as a sort of memory manager and 2-64K Srams my intent is to make a Sram board for the Hydra that will allow me to use the SD card at the same time to hold all the CPM files. I would have liked to just make an all in one board that just fit the Hydra socket but you just need to many support chips (DIP) I can't do SMT at this point. Every time I try and think up a better way it always comes back to not enough prop pins left over I do have a couple of 1 meg eeproms serial if anyone has any thoughts please feel free to jump in but at this point I can not see any way to get CPM to work without extra hardware and a good amount at that.
Oh Toby I have decided to try and built my own board as well, I am struggling trying to do the schematic in Eagle Pro so I can have real boards made when I am done but right now I am just wire wrapping it will have 4 Hydra sockets for expansion buss
A Motorola 6800 or 6809 I always loved Moto stuff and a Pic 877 Oh and of course a prop chip I have always wanted to build a multi MCU board since Clusso got me hooked. I dont know if you guys know anything about FLEX OS for the Moto chips but a multi OS like CPM and FLEX would be cool I don't know why I just feel compelled LOL Oh I don't have one in PIC but it will have SD , if any of you guys want to play along I also have a bunch of 3 1/4 floppies drives I know it would be hugely stupid 1.4 meg floppies but it would be retro ,, This is probably the biggest reason I suck at programing I just can't stay focused. lol
and of course if anyone wants a floppy they are free I still have 3 1/4 floppies but I dumped all my 5 and 8 inch stuff I actually found a 5 floppy looking through my junk and an original giant case IBM PC AT with a 386sx 128K and a 5/14 floppy and a 5 MEG 5 1/4 hard disk drive
remember MFM and RLL guys? it actually still works it had a very old VGA card serial ports and a parallel I cant believe how big these cases where
I was in the "mass storage" bit with my 8052/ Z80 thoughts when the Prop came onto my radar. Then I thought Video/Serial could be the Prop's bit. Then SD cards came ont the Props, then Z80 emulation .... I must stick to one thing otherwise the tricky bits make me have a go at the other bits again.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Not sure, so if I were attempting it my approach would be to forget about VGA and keyboard and such. Just get a PASM program reading and writing bytes from the external RAM, random access, first. Then you know exactly how many longs you need to do that and can see if it will fit into zicog.
If it fits then move on to getting emulation and CP/M running using the Prop Plug or whatever link back to the PC as a serial terminal interface. Use the terminal emulator in BST.
If that ever gets working then worry about how we are going to do peripherals, keyboard and VGA.
It's a long road....
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
With the ever-increasing number of XMM solutions, have you considered decoupling ZiCog from the memory access?
I have not looked at the sources, so I don't know how easy the following would be - or if you have thought of something similar.
Loosely, there are three types of memory accesses:
- code fetch
- data read
- data write
I am thinking of a solution where the memory access is handed off to another cog, and ZiCog requests memory actions through hub locations.
Consider:
The beauty of this approach is that it TOTALLY decouples ZiCog from specific XMM implementation, and the memory cog can try to do all sorts of caching etc.
Adding new XMM targets is trivial.
Frees up some LONGs in ZiCog
Doing split I/D for 128K memory (which I think MP/M supported) is easy.
Doing banked memory on any XMM becomes MUCH easier.
Even better, in any instruction that is not a JUMP/CALL, the next instruction read can be done in parallel with executing the current instruction!
Simply ask for the next instruction before processing the current one.
The hub delay slots can also be used [noparse]:)[/noparse]
I think it would potentiall run faster.
This would also make it trivial to provide breakpoints for execution or data access, and monitoring locations, performance etc.
On the hardware side...
This would also allow a super-cheap ZiCog config I was thinking about, by using two MCP23K256 SPI ram's or FRAMs (with a speed penalty)
What do you guys think?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.mikronauts.com E-mail: mikronauts _at_ gmail _dot_ com 5.0" VGA LCD in stock!
Morpheus dual Prop SBC w/ 512KB kit $119.95, Mem+2MB memory/IO kit $89.95, both kits $189.95 SerPlug $9.95
Propteus and Proteus for Propeller prototyping 6.250MHz custom Crystals run Propellers at 100MHz
Las - Large model assembler Largos - upcoming nano operating system
Post Edited (Bill Henning) : 1/31/2010 7:51:52 PM GMT
to hold the CPM files and then I hit that darn 32K anyway so if I use the upper eeprom as asset I cant address it. Heater you and Clusso are kind of memory gurus for the prop in order to get around the props 32K limitations and say connect a 64 Sram and have it addressed continuously we would need a whole prop OS wouldn't we? DR_A Toby feel free to jump in I understand how to interface Sram to a MCU or CPU to be honest its actually easy what I don't understand fully is why it has to be so hard with a prop I don't fully understand why the 32K limit is it becuase of the prop itself or the IDE?
Actually the more I think about this ,, Bill, Clusso, Heater, DR_A all you guys have successfully added Ram to the prop can anyone just give me a quick Vtech on my above question.
Post Edited (mikediv) : 1/31/2010 11:09:53 PM GMT
All XMM solutions construct an external address and data bus using propeller I/O pins (and various combinations of propeller pins and latches).
This chews up propeller pins, and XMM is generally noticably slower than hub access.
There is a fairly direct relationship between the number of pins used, and the speed of random external memory access. Different XMM implementations are optimized for different usage patterns and Propeller pin usage.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.mikronauts.com E-mail: mikronauts _at_ gmail _dot_ com 5.0" VGA LCD in stock!
Morpheus dual Prop SBC w/ 512KB kit $119.95, Mem+2MB memory/IO kit $89.95, both kits $189.95 SerPlug $9.95
Propteus and Proteus for Propeller prototyping 6.250MHz custom Crystals run Propellers at 100MHz
Las - Large model assembler Largos - upcoming nano operating system
Is there a link to the hydra schematic?
Mike, do you have a schematic of what you are working on now?
@Cluso - it would be cool to have your ramblade able to log into a network. I think we have everything we need there. Just need the server software.
Re packet radio - yes absolutely and that is the inspiration for a lot of this.
Re decoupling zicog and ram. The problem with the dracblade is no spare cogs. 1 for the interpreter, 1 keyboard, 2 vga, 1 serial, 1 zicog, 1 ram latch, 1 sd card. But it is an intriguing possibility, especially since once you have sent up ram latches is it much quicker to get the second, third byte etc. Mathematically, what is the optimum number of bytes to prefetch? And I guess you need some management code to do that prefetching. On the dracblade, everything is a compromise and I think that code would max out the hub ram (until cluso does the clever code he is working on...). But for the zicog on another emulation, it would be a very useful concept.
@mike- heater has had CP/M running in 32k on a propeller with no external ram. The problem is there isn't room for most programs to then run.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
On the DracBlade, your "ram latch" cog would be the "xmm server", servicing the memory requests, so no need for an extra cog.
On a SPIBlade, the "xmm server" would presumably pre-fetch internally, as it can run in parallel with Zicog. I think for some applications even a 50% speed hit would be worth the reduced pin count! Frankly, I'd be tempted to try a paging approach, with say a 16-64 page working set, with LRU replacement. It should hide most of the slow access of SPI ram.
I suspect that for non-SPI memory solutions the decoupling with prefetch could be an overall speed win.
As far as hub ram... if you use a 64KB EEPROM, you could load the drivers one at a time, and use only a 2K buffer area to hold drivers - which could later be re-used for SD card buffers.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.mikronauts.com E-mail: mikronauts _at_ gmail _dot_ com 5.0" VGA LCD in stock!
Morpheus dual Prop SBC w/ 512KB kit $119.95, Mem+2MB memory/IO kit $89.95, both kits $189.95 SerPlug $9.95
Propteus and Proteus for Propeller prototyping 6.250MHz custom Crystals run Propellers at 100MHz
Las - Large model assembler Largos - upcoming nano operating system
Why not put a very small method in each object that simply returns the address of the relevant DAT portion, then write a top object that includes all the subobjects. Have that top object write the 2k chunks to SD card. That way you can run that object whenever you change the code in any of the sub objects, and it will automatically update the driver binaries on the SD card for you.
...alternatively...
bstc will drop the dat section from the top object as a raw .dat file, but it won't do that for sub-objects. You could do something like
for i in *.spin ; do bstc -c $i ; done
That would drop a .dat file for each spin object in the directory. You could then just take the ones you wanted and pop them onto the SD card. I like the dedicated top object better though.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Life may be "too short", but it's the longest thing we ever do.
But I wonder if a compiler could be modified to handle this? Consider:
PUB1
... code
PUB2
... code
DAT
... cog code
.. ?FIT command
PUB3
... code
The compiler goes through all this one at a time and puts the cog code in where it is meant to and when it is run the coginit moves the cog code into a cog and there is now a pile of wasted bytes in hub ram.
What if the compiler were able to compile all the DAT code, complete with references to hub ram locations, but when it got to the end of the DAT section, it reset the pointers for hub ram locations as if that DAT code had never existed. Eg back to the end of the PUB2 code.
It then saves the cog DAT code as a seperate file.
The main source code now has PUB1 PUB2 PUB3 with no cog code in it.
The cog code is loaded seperately by a dedicated spin routine and place in a cog. But any references to any hub locations are correct because the compiler knew where they should be.
I suppose the questions are - would this work, and if it would, how hard would it be to code for a compiler?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
I swear I will contribute CPM stuff as soon as I get a system running
Mike.
·
Well, it kinda is.. DAT code can't reference any other areas (PUB/PRI/VAR) by symbol name. So you need a SPIN routine to load a DAT symbol with the address of a VAR location for example.
In this context, the DAT block is completely stand-alone, but the SPIN code knows how to load some locations prior to starting it up. You can achieve a similar thing quite easily by preloading a series of longs in VAR for example, and having your cog code just block copy them from an address passed through par when you launch the cog. That way there is no need for the SPIN code to know the offsets in the DAT block or do any pre-launch tweaking.
Is that how you'd like the layout to be? The compiler _always_ places the *entire* dat block at the start of the object. So it's all DAT up until the first PUB method.
DAT
PUB1
PUB2
PRI1
PRI2
..end
I can see this working in one particular context.
Each DAT block would have to be cog code only, load all its parameters from the PAR variable and be launched with a single cognet(@start,@parms)
Now, if you are going to do that, then there is really zero reason to have the DAT block in the same file as the SPIN code, as the SPIN code is not allowed to reference any of the symbols in the DAT block (as you plan to relocate it). If you were going to do that, then my previous idea of just compiling the DAT blocks separately is a lot easier to achieve _now_.
Personally I quite often use the DAT block as buffers for an object after the COG is loaded if I have no need to re-load the cog.
One thing I did give a cursory glance at was consolidating all the DAT blocks at the end of the code block, and after VAR (so squeezed in between the end of VAR and the stack) but I just never saw it buying enough advantage to be worth the significant re-write required to shuffle everything around and break the object model.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Life may be "too short", but it's the longest thing we ever do.
Also - help is on the way. Three boards are winging their way to you - should be at the airport by tonight.
Re Brad, yes I need to digest that in the context of a real object, eg the keyboard object. Most objects seem to have some tiny setup PUBs associated with them but I agree, it ought to be possible to pass all possible locations and parameters via the setup.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
Nice to see you lurking with ideas Brad. Yes, I think just compling seperate Dat's is the way to go to save hub space. We would just require a cog loader to locate the file on SD, find the length and load it. This approach could become part of SphinxOS.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:
· Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
· Prop Tools under Development or Completed (Index)
· Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
· Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz