I have been playing with my much modified "DracBlade".
First I planted an additional 22uF Tant right on the SD sub-board so that it was within 15mm od the card connection. This had no effect, Er1 still happened.
Then I put an additional 100uF Tant under the Prop and added a brand new 0.1uF with it. This had no effect.
Next I strenthened the ground routing (only a single sided board ). Again this showed no effect, Er1 was got unless the cold stuff was used.
Finally I cut the tracks, that went from the same pins as the SD, onto the IDC wiring and onto the top board (this was for possible future use on DRAM experiments). This did have an effect and the system boots up without the ice. Either the extra capacitance or the unterminated stub was fouling things up.
Just remembered, this is all at 5MHz x 16
Addit
Now that the code runs I have found one slight complication. I saved two pins by disconnecting the EEPROM and selecting the KBD on P28-P29, this is switched over by the start of H sync which stops when the screen saver kicks in so the KBD is deselected and cannot be used to bring the board out of hibernation (so the saver will have to go, for now). Hey-Ho.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Post Edited (Toby Seckshund) : 4/13/2010 7:36:34 PM GMT
Toby: Glad to hear you got it working. Definitely the capacitive loading, ribbon cables are really bad for that.
I've got an update to the code. This is based on the latest version I had I'm afraid so changes others have made are not included. However, I've only changed one line in Main_Dr_Acula.spin; I've renamed the modified fsrw object to drac_fat.spin hopefully this change can be incorporated into the latest code.
From now on I consider the interface to drac_fat to be stable, i.e. the callable PUBs will not change name/parameters. I've also included two 'new' backends called drac_spi.spin and drac_spi_warp.spin. drac_spi_warp is the latest multi-block code that's been causing people problems but with the high-address latch bug fixed (I hope, not tested properly I'm afraid).
drac_spi is based on the old sdspiFemto code, but with a re-written SPIN interface to match drac_spi_warp.
These two can be switched in the drac_fat.spin with a comment, see the OBJ section.
Limitations:
The slower drac_spi has a couple of limitations at the moment; it only works with standard capacity SD cards (although as it only does the block layer, FAT32 should be possible). It currently doesn't do SD pin tri-stating properly either.
Hopefully this should let people get on with other stuff without worrying about what the backend code is too much. I plan to tinker with it more, but the changes will now be contained within drac_fat and drac_spi objects.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
Hairymnstr: I'm running a stock standard Dracblade V4 with Switching regulators and Electrolytic caps. No Tants. SD card is a 2GB Sandisk and I'm using a 9V DC switchmode plugpack.
Dr_A: Your bank switching scheme sounds interesting however, I think there are some issues you will need to handle. Specifically, since you have separate instances of cp/m each instance will think it owns the disk and will manage the file system independently of any other instance. This means that you can't have two instances using the same disk (unless it is read-only) also, you can't share devices between the instances. You would also need some way to communicate between instances
I think what you need is to implement mp/m as it provides file locking and one file system. To do that, the main thing you need is banked memory with a common section (say 16KB) at the end of the address space and multiple banks of (sav 48KB) extending from 0 up to the beginning of the common memory. If you change banks you keep the same common area and the lower portion is swapped out.
MP/M also needs at least a periodic interrupt for it to check queues and swap processes. Ideally, interrupts from the terminal devices and disk DMA would also be good.
Your packet processing network code could either be implemented as a driver as part of the XIOS (eg the way cp/net is integrated) or you could run it as a server process in user land. The advantage of running it as a process it that you consume banked memory rather than common memory.
Alternatively, maybe you could handle the network comms outside of cp/m and do it in spin? Depending on what you want to do, maybe you could virtualise the IO devices in cp/m (say using IOBYTE) and allow the network code to manipulate the IOBYTE redirecting the IO from cp/m's logical devices based on network requests?
Yes suddenly there are all sorts of possibilities. MPM is the best one but I've been going through the source code and it is not entirely clear how it all works. Specifically, I'm trying to find the one line of code that switches the bank, and the line of code that handles the interrupt.
Re disk drives, one answer could be a simple 'lock' flag in spin and if one instance of CP/M is using the disk drive, it bypasses the interrupt that changes to the next instance of CP/M until disk access is finished. There are other solutions too, eg delaying disk access until the drive is free.
I've also been pondering moving some of the spin code into Z80 - even into a third virtual machine running Z80 assembly. I wonder how spin compares in speed with Z80 assembly? Eg there are a number of inputs and a number of outputs. Keyboard, vga display, two serial ports, LCD display. Then one can envisage virtual ports that can enable communications between CP/M users. It would be great to have flexibility on how things are connected. eg you can 'attach' serial port 0 to CP/M user 2. There is also the complexity of merging inputs into one - eg the current code merges keyboard and port0 into one. With pasm and spin, memory is always at a premium. But with multiple virtual machines, memory is no longer a problem. Consider a program that 'attaches' ports and where every port has a huge buffer - kilobytes of storage for each port. This accepts input from, say, the 4 serial port object that has 64 byte buffers, and parks the data in much larger buffers ready for use. Then one can start looking at much bigger packet sizes for xmodem and other file transfer protocols.
In moments of complete madness I've even pondered a spin to Z80 compiler. Then you could have up to eight spin programs running in parallel with 64k of memory each.
Back to the real world, MP/M probably is the next step. I need to find someone who is expert on this - maybe I'll ask over at comp.os.cpm or perhaps Peter Schorn who wrote the SIMH version.
Bank switching is performed in the xios (mp/m equivalent of bios) by the SELMEMORY entry in the jump table. This is written by the implementer and switches in the appropriate bank depending on how banked memory is supported by the hardware.
From memory, interrupts simply set a flag in mp/m depending on what they are for. eg, an incoming character is written to a queue and a flag is set to indicate that a character is available. The terminal message processor (tmp) equivalent of the CCP is then scheduled to run and it obtains the character. Have a look at the MP/M II system manual it has a brief explanation of the IO system.
Regarding the disk drives, you have to take into account that cp/m keeps some information relating to the file system in memory. If one instance of cp/m changes something on the disk and then another instance goes to do something else it will notice (hopefully) that something has changed on disk compared to memory and you will get the old bdos disk r/o error. This is similar to changing a floppy in the drive and not typing ^c to get cp/m to re login the drive.
Regarding your network code, what are the primary functions that it performs? I guess it would be:
1. Remote access to the console so you can run programs on the individual nodes;
2. File transfer between nodes, driven by accessing the console of each node?
3. Maybe some sort of re-directed i/o eg. print via another node?
FWIW the SIMH ports emulated in my io.spin had the bits for banked memory, and just now I implemented it for qz80 - seems to be working after a quick test. I wrote a little program at 0c000h with ddtz that selects bank 1, writes a 055h to (4000h), switches back to bank 0 and reads memory at (4000h). The result is different from 55h, so banking was done. I released a new version now to play with. It supports bank numbers 0 to 9. There is currently no range checking, so don't specify numbers higher than 9 or your system will crash.
I now tested it with this Z80 program fillbank.mac:
ld hl, prog
ld de, 0c000h
ld bc, endprog - prog
ldir
jp 0c000h
prog: di
ld a, 1
loop: ld bc, 0cfeh
out (c),b
out (c),a
ld hl, 0
ld de, 1
ld bc, 0bfffh
ld (hl),055h
ldir
inc a
cp 10
jr c, loop
xor a
ld bc,0cfeh
out (c),b
out (c),a
ei
ret
endprog:
end
It takes 2 or 3 seconds to fill the entire external RAM except bank 0 with $55.
This all sounds very exciting. Thanks++ for the background info.
I gather there are all sorts of bank switching options but I think a common one was to have the top 16k stay constant and to switch in the lower 48k. That would involve changes to the memory driver code in two places - the LMM emulator and also the direct ram access cog. MPM runs under CP/M so it boots CP/M then you run MPM (which can be an autoexec). At present the code I'm experimenting with sets the bank by doing an OUT to a certain port. But I'm not sure how MPM actually sets a bank.
Re networks, yes all what you suggest Max. I think if the only bytes that are on the network (wired/radio) are in a packet, then it is always possible to route those bytes to the right place.
pullmoll, I need to think about getting all your code into the dracblade. What are your thoughts on which sd card driver to use - yours, hairymnstrs, the old code or something else?
Dr_Acula said...
pullmoll, I need to think about getting all your code into the dracblade. What are your thoughts on which sd card driver to use - yours, hairymnstrs, the old code or something else?
I now incorporated hairymnstr's new fast SPI code verbatim as DracBlade_mb_small_spi.spin
I also wrote a RamBlade_mb_small_spi.spin that _should_ work for the RamBlade, while I can't test it because my code doesn't at all work on a RamBlade.
Instead of getting my code into your dracblade setup, why not have me getting your missing code bits into my code? I just started to make my io.spin LMM function call capable, so there's room for extensions now (LED, LCD, whatever). Also: did you read my suggestion regarding terminal colors? Instead of ports it would be wise to use a VT100 escape sequence, because using a port would mixing different levels of access.
From an MP/M perspective, it must have some common memory in the top of the address space and banked in the lower section. The actual sizes are implementation specific and end up being a trade-off between application size and OS size. Most of MP/M has to be kept in common memory and is available all the time so the more drivers, queues, terminals etc the more common memory is needed. One of the nice things about the Z180 is it has registers to set the sizes of the common and banked memory.
In true CP/M fashion, MP/M doesn't care how a specific bank is selected except that a call is made to a location in the BIOS jump table and the bank number is placed in a register. The system implementer writes the actual bank select routine based on the value passed from the kernel. Just like making a BIOS call.
MP/M doesn't actually run under CP/M. The loader can, but it overwrites CP/M. You can boot MP/M directly from the disk providing you put the loader on the boot sectors and have an appropriate boot rom.
How does the interrupt support in the emulator work? Can you specify where it vectors to (like a Z80) or does it only support 038H like an 8080? What sources can generate an interrupt? Is there an RTC?
MaxS said...
How does the interrupt support in the emulator work? Can you specify where it vectors to (like a Z80) or does it only support 038H like an 8080? What sources can generate an interrupt? Is there an RTC?
That's a question for me: Interrupts are generated by writing to a public long "irq". You can write -1 to generate a Z80 NMI ($0066) or write the RST command ($CF,$D7,$DF...$FF) to execute it in interrupt mode 0. In interrupt mode 1 a RST 38h is executed (8080 compatibility mode) and in interrupt mode 2 you can place the low byte of a vector in irq. Vector table is a list of words at (I-register << 8) and vector selects one of the entries. In other words: interrupts are just like a real Z80, with a long serving as data bus for the actual IRQ.
There is no RTC, no. I could implement a timer tick in one of the cogs and generate cyclic IRQs, though.
That is a very generous and kind offer, thankyou pullmoll.
For the moment there is a lot of code that is experimental and which there is no need to add, eg the bank switching experiment and all the complicated io routines. So to keep things simple:
keyboard
20x4 LCD
sd card access (ideally one that is stable (slower) and also can do fat 16 and fat32)
serial driver
8080 emulation (and full Z80 if it will fit)
For the input, currently it merges keyboard and ports. That code is a bit messy and the only reason for it was so xmodem could do file transfers. I now have a modified version of xmodem that works on port2, so I can make a copy of that so it works on port 1. So rather than any code that merges inputs, I am thinking keep things very simple and just access those with port OUT and IN calls. Which should make the code easier.
(the historical reason for the merging of inputs was that it was using port 0 and a terminal on the PC originally. Then the local keyboard was added. But now the board really is working as a standalone board with either VGA or LCD (or even TV) and its own local keyboard. So there is less need for a version running with a PC terminal program).
And yes, VT100 colour commands would be much neater than via ports. In fact, it should be possible to do this with a lot less ports. VT100 is a good standard.
Ok, so to implement MP/M we would need a periodic interrupt at say once every 20ms and a separate interrupt at once every second (for time keeping). It would be nice to be able to turn if off under program control also, especially during booting. MP/M needs to be able to mask interrupts during context switching etc.
In mode 2, how is the value of the low order vector byte defined?
Can a terminal character also generate an interrupt?
It sounds like MP/M might be do-able if the memory management is compatible.
Dr_Acula said...
That is a very generous and kind offer, thankyou pullmoll.
For the moment there is a lot of code that is experimental and which there is no need to add, eg the bank switching experiment and all the complicated io routines.
The bank switching code is there now, working, and simple and short enough to fit.
Dr_Acula said...
So to keep things simple:
keyboard
20x4 LCD
sd card access (ideally one that is stable (slower) and also can do fat 16 and fat32)
serial driver
8080 emulation (and full Z80 if it will fit)
Keyboad is there. LCD has to be done (I have some PASM code, just need to incorporate it). SD card access is there, working on my board and so far on everyone else's IIRC!? Serial driver is there, two ports. The second port can be accessed through the SIMH punch ports. Nothing of your port2 code is there, though (baudrate switching, turning port2 off). The 8080 is a different story. You would have to switch the core, because I have a separate q85.spin. This one also does not (yet) support bank switching, but is otherwise compatible with qz80.
Dr_Acula said...
For the input, currently it merges keyboard and ports. That code is a bit messy and the only reason for it was so xmodem could do file transfers. I now have a modified version of xmodem that works on port2, so I can make a copy of that so it works on port 1. So rather than any code that merges inputs, I am thinking keep things very simple and just access those with port OUT and IN calls. Which should make the code easier.
And yes, VT100 colour commands would be much neater than via ports. In fact, it should be possible to do this with a lot less ports. VT100 is a good standard.
I also have SIO port 0 and keyboard return constat and condata. Why would you add xmodem to the console ports? Isn't that protocol a layer above keyboard? Port in/out should work with the punch, unless I have bugs sitting in there. Simple enough to fix, should it be the case, though.
The VT100 code is also LMM capable and can be extended as long as hub RAM is available.
MaxS said...
Ok, so to implement MP/M we would need a periodic interrupt at say once every 20ms and a separate interrupt at once every second (for time keeping). It would be nice to be able to turn if off under program control also, especially during booting. MP/M needs to be able to mask interrupts during context switching etc.
Well, the DI/EI commands should suffice, no? They work as you would expect it.
I can add code to the I/O cog polling loop that generates cyclic interrupts. I've done this for the M100 emulation (where I have some bug that causes the whole thing to stall after 10 minutes ... *grmbl*)
For the tick timer I would suggest 15.625ms then, i.e. clock frequency / 64.
MaxS said...
In mode 2, how is the value of the low order vector byte defined?
.
You would write e.g. $100 + vector LSB to irq, so that you could also use vector LSB == 0. The interrupt code uses just the lower byte of the value from irq.
MaxS said...
Can a terminal character also generate an interrupt?
Not currently, no, because that would mean to modify the generic Keyboard and/or SIO drivers. I could perhaps poll the status in a cyclic interrupt, which could suffice. I think you could do the same on the Z80 side as well.
MaxS said...
It sounds like MP/M might be do-able if the memory management is compatible.
It should be, since it is how SIMH does it, and I think MP/M runs on SIMH!?
MPM runs on the SIMH. I have a code package but it is easy to download. You just need a terminal program to attach it to - attach on port 23. I'll dig up a copy when I get home as I have Teraterm all pre-configured. Also the source code is on the MPM disk.
DI and EI and interrupts all should work as expected as Juergen says. The propeller has an internal clock that is just perfect for this purpose.
pullmoll, that is great news as it sounds like you already have most of the parts working. Just a matter of pulling them all together.
Re Punch and Reader on the second port, there is a complicated bit of code on the SIMH that combines these together. It took me ages to work out how to seperate out the data and I can't recall how I did it (I'm not at my home computer) but I think there are comments in the code that describe it more. I think they shared a common port or something, and it was possible to seperate them. In the end I used OUT and IN to ports rather than via CP/M but maybe it is worth coding both. I did have both working at one stage.
If we are going to get MPM working then we don't need any of the code that changes port2 baud rate or turns that port on and off. That will all be done as a seperate C or Basic or Assembly program running in MPM. Which will be a lot neater as the spin/pasm code won't need to be changing all the time.
Dr_Acula said...
pullmoll, that is great news as it sounds like you already have most of the parts working. Just a matter of pulling them all together.
I'm working on it. First thing is trying to get a ticker interrupt working. There is a SIMH port 22 defined for disabling timer interrupts, but no port for enabling them (again)!? For now I use port 20 to do this, while it's probably better to find out what SIMH really uses for this purpose.
When I have the tick timer working, I will add the LCD code to io.spin.
Edit: Ok, got the timer interrupt working after fixing a bug in the qz80.spin do_timer code (forogot to add # and *4 for the lmm_pc...). Here's my little timer interrupt handler:
ld hl, prog
ld de, 0ff80h
ld (39h), de
ld bc, endprog - prog
ldir
im 1
ld a, 0c3h
ld (38h), a
ld a, 20
out (0feh),a
ei
ret
prog: push af
push hl
ld hl, 0fffah
ld a, (hl)
add a, 4
ld (hl), a
jr nc, done
inc hl
loop: inc (hl)
jr nz, done
inc hl
ld a, h
or a
jr nz, loop
done: pop hl
pop af
ei
reti
endprog:
end
It copies the prog..endprog to $ff80, i.e. beyond the boot sector code. It then patches $38 to jump to $ff80. The prog increments the 6 bytes at $fffa..$ffff, so you have a 48 bit tick count. We could easily store the Unix time - seconds since 1.1.1970 - in the whole seconds part $fffb..$ffff and use these values for a real time clock. Only setting the time initially would have to be done somehow, ideally from a RTC, if there is one on the board...
This little BASIC program prints the current seconds (omitting the high bytes) and fraction:
Edit: LCD code is in there now too. Since not all platforms have LCD, I use a global #define HAVE_LCD to enable the code. The io.spin just initializes the LCD at startup, but doesn't output everything that goes to conout to the LCD also, as I think that would be slowing down the SIO #0 and VT100. I wired the LCD to ports $14 (20) = status on read, instruction on write, and $15 (21) = data on write (you can't read the LCD, it returns 0), just like console and punch. Is there a standard CP/M device like LPT that could be redirected to these ports? Then you could write to the LCD by pip or BASIC's LPRINT. Right now LPRINT seems to go to the punch, because I can hear it - with the audio output connected to pin 24
Did anyone notice the latest versions of the SD/SRAM code I posted last night? The drac_spi_warp.spin file is basically what was in mb_small_spi.spin but I think I've fixed the bank switching so that the LED doesn't reset the bank when switched on or off. There's also a compatible slower SPI object so you can include either and get the same interface at the higher level now, so there shouldn't be any worries about other platforms with SD incompatibilities as the slower code should work and doesn't require any re-writing of higher level objects.
I'm working on the slower code to get it to support HCSD and to speed it up a little whilst retaining the stability.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
hairymnstr said...
Did anyone notice the latest versions of the SD/SRAM code I posted last night?
Me, yes. I grabbed the fast version and put it in the qz80 ./lib directory as DracBlade_mb_small_spi.spin. I guess we should use the same names, though... I wrote a RamBlade variant of the mb_small_spi.spin code, so that one could be renamed as well. We should just settle on a naming scheme and keep that consistent from now on, if you agree
Just a question: If I never use the high port functions, your code will leave the latch alone? The banking I do is in PASM, because I can't call a Spin method from there - and because it should be as fast as possible. I write all three address latches when banking is enabled, limiting the high latch value to 3 bits.
Yes, unifying the names is a good plan, I'm a fan of less letters hence why I shortened the name, I'm happy to switch to your naming scheme if you like, that would mean the slower version for more capacitive buses would be DracBlade_sdspi.spin I guess.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
hairymnstr said...
Yes, unifying the names is a good plan, I'm a fan of less letters hence why I shortened the name, I'm happy to switch to your naming scheme if you like, that would mean the slower version for more capacitive buses would be DracBlade_sdspi.spin I guess.
I would also like shorter names. Prepending the platform name is okay IMO, just like we (I saw you did that, too) #define it in the top level file. sdspi for the slow version is okay for me. How about just spi_warp for the fast version then? Or what would you like to use?
Right, using the name as is done in the #define is a good idea, of course we could integrate all the code into one file and use the #define to select the platform...
For now I'll propose DracBlade_spi.spin and DracBlade_spi_warp.spin as the two object names.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
hairymnstr said...
Right, using the name as is done in the #define is a good idea, of course we could integrate all the code into one file and use the #define to select the platform...
For now I'll propose DracBlade_spi.spin and DracBlade_spi_warp.spin as the two object names.
Okay, agreed! We can perhaps later merge in the code for the RamBlade, if it ever gets tested. It is in ./lib/RamBlade_mb_small_spi.spin if you want to peek at it. qz80 doesn't start on my RamBlade, thus it's untested.
For boards that use TV or VGA output, you can easily get a regular "tick" by modifying the TV or VGA driver to increment a "tick" count in the hub during every VSYNC
There isn't much I can contribute while pullmoll and hairymnstr work on getting the qZ80 and hairysd code converted into the new Dracblade operating system (thanks guys!), so in the meantime I thought I would take a look at banked memory and MPM.
Re MaxS "Bank switching is performed in the xios (mp/m equivalent of bios) by the SELMEMORY entry in the jump table. This is written by the implementer and switches in the appropriate bank depending on how banked memory is supported by the hardware."
Attached is a 'package' for MPM. Unzip to a new directory. Run MPM.BAT. Then run Teraterm and hopefully it will read the local TERATERM.INI and start with a message with the connection to TCP/IP to LOCALHOST with TELNET and port#23. Click OK and it should connect to the MPM simulation. This is actually running CP/M so at the A> prompt type MPM and it should then be running MPM.
Then you would attach various other terminal programs. On the Dracblade, one might have user 1 running the local keyboard and vga disply, user 2 on serial port0 and user3 on serial port1 etc.
In the zip I have extracted out the source code off the disk (you can do this easily with the W command). So a quick search for SELMEMORY in MPMXIOS.MAC finds this code:
; Select / Protect Memory
selmemory: ; <BC> = adr of memory descriptor
; <BC> -> base 1 byte,
; size 1 byte,
; attributes 1 byte,
; bank 1 byte.
if banked
ld hl,3 ; offset of 'bank' in memory descriptor
add hl,bc ; <HL> now points to desired bank
call checkb ; make sure we got banked memory
ld a,setbankselect ; prepare command
out (simhport),a ; execute it
ld a,(hl) ; get new bank
out (simhport),a ; inform mmu
endif
ret
just above that is the code for polling each user input, and just below is clock setting and resetting.
A lot of things seem to be done through a port eg:
out (simhport),a ; execute it
and simhport is $FE
ticks equ 50 ; 50 ticks per second
deltati equ 1000/ticks ; time in milliseconds between ticks
simhport equ 0feh ; SIMH port
So I'm starting to get a bit of an idea how this can be run on the propeller. I do note some settings for the disk drive that seem to be for floppy drives, and for all the good reasons Cluso and Heater have found, there really is little point in using any other drive on an sd card than an 8mb hard drive. So maybe those values need changing?
Of course, if MPM can be emulated, I can think of at least three different ways that users can communicate with each other (for the purposes of running code doing a network protocol etc):
1) via custom ports
2) by peeking and poking data to unused ram locations on the 512k ram chip
3) by writing to and reading from files on the sd card
One of the huge strengths of the propeller chip is that it has 8 independent processors. In creating the dracblade, we have used 8 processors to emulate one CP/M machine. It is sort of going backwards in terms of parallel processing. But with MPM, it would be possible to emulate at least 4 processors and possibly 8 or even up to 10. Each with 24 times the memory of a cog, and each with the ability to run multiple languages like Basic and C and Pascal etc all at the same time. So in a way this is like creating a giant propeller chip!
Okay, so what's the top priority now? I can tinker with the block layer and trim longs till the cows come home, but now that the object naming and spin interface have been more or less frozen I can be doing that in parallel with what others are working on. Are there new features needed, for banking out the bottom 48K of RAM some address jiggery-pokery is needed (to use the technical term). I guess, as long as the top latch is left alone there's not much to do for the DMA transfer stuff, will need to check the top two bits of the 16bit RAM address and see if we're accessing from 0 or from the current bank. Are you integrating this common area code into the memory routines in qZ80 Juergen?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
You guys are running ahead at break neck speed, I can't keep up...
To get MP/M running you will need to create a new LDRBIOS for it so as to get it working from the HD only systems.
(I assume you are still running the ZiCog CP/M that has no floppy support)
The LDRBIOS supplied with SIMH Altairz80 only understands floppy drives. Take a look at the CBIOSX.MAC that is on the ZiCog CP/M 2 disks to see how I modified it, removing all Altair floppy driver code and using the HD drivers only.
You will also need to modify MPMXIOS so as to get it to use the hard drives for disks A:, B: ...instead of floppies. Again look at CBIOSX to se how I did that.
For the banked memory, that was already inthe ZiCog emulator albeit with a wee bug. Looks like Pullmoll has that sorted anyway.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
hairymnstr said...
Are you integrating this common area code into the memory routines in qZ80 Juergen?
What I do when banking is enabled is just this: if address < $c000 add bankbase. This variable is set by an output to the SIMH port with the command setbank, followed by the bank number. The value for bank 1 is 64K, bank 2 is 64K+48K, bank 3 is 64K+2*48K etc.
I guess I would have to do the same in the I/O routines if the DMA address for a transfer is below $c000, so that the transfer goes to the correct bank.
Comments
First I planted an additional 22uF Tant right on the SD sub-board so that it was within 15mm od the card connection. This had no effect, Er1 still happened.
Then I put an additional 100uF Tant under the Prop and added a brand new 0.1uF with it. This had no effect.
Next I strenthened the ground routing (only a single sided board ). Again this showed no effect, Er1 was got unless the cold stuff was used.
Finally I cut the tracks, that went from the same pins as the SD, onto the IDC wiring and onto the top board (this was for possible future use on DRAM experiments). This did have an effect and the system boots up without the ice. Either the extra capacitance or the unterminated stub was fouling things up.
Just remembered, this is all at 5MHz x 16
Addit
Now that the code runs I have found one slight complication. I saved two pins by disconnecting the EEPROM and selecting the KBD on P28-P29, this is switched over by the start of H sync which stops when the screen saver kicks in so the KBD is deselected and cannot be used to bring the board out of hibernation (so the saver will have to go, for now). Hey-Ho.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Style and grace : Nil point
Post Edited (Toby Seckshund) : 4/13/2010 7:36:34 PM GMT
I've got an update to the code. This is based on the latest version I had I'm afraid so changes others have made are not included. However, I've only changed one line in Main_Dr_Acula.spin; I've renamed the modified fsrw object to drac_fat.spin hopefully this change can be incorporated into the latest code.
From now on I consider the interface to drac_fat to be stable, i.e. the callable PUBs will not change name/parameters. I've also included two 'new' backends called drac_spi.spin and drac_spi_warp.spin. drac_spi_warp is the latest multi-block code that's been causing people problems but with the high-address latch bug fixed (I hope, not tested properly I'm afraid).
drac_spi is based on the old sdspiFemto code, but with a re-written SPIN interface to match drac_spi_warp.
These two can be switched in the drac_fat.spin with a comment, see the OBJ section.
Limitations:
The slower drac_spi has a couple of limitations at the moment; it only works with standard capacity SD cards (although as it only does the block layer, FAT32 should be possible). It currently doesn't do SD pin tri-stating properly either.
Hopefully this should let people get on with other stuff without worrying about what the backend code is too much. I plan to tinker with it more, but the changes will now be contained within drac_fat and drac_spi objects.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
Cheers!
I think what you need is to implement mp/m as it provides file locking and one file system. To do that, the main thing you need is banked memory with a common section (say 16KB) at the end of the address space and multiple banks of (sav 48KB) extending from 0 up to the beginning of the common memory. If you change banks you keep the same common area and the lower portion is swapped out.
MP/M also needs at least a periodic interrupt for it to check queues and swap processes. Ideally, interrupts from the terminal devices and disk DMA would also be good.
Your packet processing network code could either be implemented as a driver as part of the XIOS (eg the way cp/net is integrated) or you could run it as a server process in user land. The advantage of running it as a process it that you consume banked memory rather than common memory.
Alternatively, maybe you could handle the network comms outside of cp/m and do it in spin? Depending on what you want to do, maybe you could virtualise the IO devices in cp/m (say using IOBYTE) and allow the network code to manipulate the IOBYTE redirecting the IO from cp/m's logical devices based on network requests?
Re disk drives, one answer could be a simple 'lock' flag in spin and if one instance of CP/M is using the disk drive, it bypasses the interrupt that changes to the next instance of CP/M until disk access is finished. There are other solutions too, eg delaying disk access until the drive is free.
I've also been pondering moving some of the spin code into Z80 - even into a third virtual machine running Z80 assembly. I wonder how spin compares in speed with Z80 assembly? Eg there are a number of inputs and a number of outputs. Keyboard, vga display, two serial ports, LCD display. Then one can envisage virtual ports that can enable communications between CP/M users. It would be great to have flexibility on how things are connected. eg you can 'attach' serial port 0 to CP/M user 2. There is also the complexity of merging inputs into one - eg the current code merges keyboard and port0 into one. With pasm and spin, memory is always at a premium. But with multiple virtual machines, memory is no longer a problem. Consider a program that 'attaches' ports and where every port has a huge buffer - kilobytes of storage for each port. This accepts input from, say, the 4 serial port object that has 64 byte buffers, and parks the data in much larger buffers ready for use. Then one can start looking at much bigger packet sizes for xmodem and other file transfer protocols.
In moments of complete madness I've even pondered a spin to Z80 compiler. Then you could have up to eight spin programs running in parallel with 64k of memory each.
Back to the real world, MP/M probably is the next step. I need to find someone who is expert on this - maybe I'll ask over at comp.os.cpm or perhaps Peter Schorn who wrote the SIMH version.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
From memory, interrupts simply set a flag in mp/m depending on what they are for. eg, an incoming character is written to a queue and a flag is set to indicate that a character is available. The terminal message processor (tmp) equivalent of the CCP is then scheduled to run and it obtains the character. Have a look at the MP/M II system manual it has a brief explanation of the IO system.
Regarding the disk drives, you have to take into account that cp/m keeps some information relating to the file system in memory. If one instance of cp/m changes something on the disk and then another instance goes to do something else it will notice (hopefully) that something has changed on disk compared to memory and you will get the old bdos disk r/o error. This is similar to changing a floppy in the drive and not typing ^c to get cp/m to re login the drive.
Regarding your network code, what are the primary functions that it performs? I guess it would be:
1. Remote access to the console so you can run programs on the individual nodes;
2. File transfer between nodes, driven by accessing the console of each node?
3. Maybe some sort of re-directed i/o eg. print via another node?
Anything else?
I now tested it with this Z80 program fillbank.mac:
It takes 2 or 3 seconds to fill the entire external RAM except bank 0 with $55.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 3:36:06 AM GMT
I gather there are all sorts of bank switching options but I think a common one was to have the top 16k stay constant and to switch in the lower 48k. That would involve changes to the memory driver code in two places - the LMM emulator and also the direct ram access cog. MPM runs under CP/M so it boots CP/M then you run MPM (which can be an autoexec). At present the code I'm experimenting with sets the bank by doing an OUT to a certain port. But I'm not sure how MPM actually sets a bank.
Re networks, yes all what you suggest Max. I think if the only bytes that are on the network (wired/radio) are in a packet, then it is always possible to route those bytes to the right place.
pullmoll, I need to think about getting all your code into the dracblade. What are your thoughts on which sd card driver to use - yours, hairymnstrs, the old code or something else?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
I also wrote a RamBlade_mb_small_spi.spin that _should_ work for the RamBlade, while I can't test it because my code doesn't at all work on a RamBlade.
Instead of getting my code into your dracblade setup, why not have me getting your missing code bits into my code? I just started to make my io.spin LMM function call capable, so there's room for extensions now (LED, LCD, whatever). Also: did you read my suggestion regarding terminal colors? Instead of ports it would be wise to use a VT100 escape sequence, because using a port would mixing different levels of access.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 4:52:18 AM GMT
In true CP/M fashion, MP/M doesn't care how a specific bank is selected except that a call is made to a location in the BIOS jump table and the bank number is placed in a register. The system implementer writes the actual bank select routine based on the value passed from the kernel. Just like making a BIOS call.
MP/M doesn't actually run under CP/M. The loader can, but it overwrites CP/M. You can boot MP/M directly from the disk providing you put the loader on the boot sectors and have an appropriate boot rom.
How does the interrupt support in the emulator work? Can you specify where it vectors to (like a Z80) or does it only support 038H like an 8080? What sources can generate an interrupt? Is there an RTC?
That's a question for me: Interrupts are generated by writing to a public long "irq". You can write -1 to generate a Z80 NMI ($0066) or write the RST command ($CF,$D7,$DF...$FF) to execute it in interrupt mode 0. In interrupt mode 1 a RST 38h is executed (8080 compatibility mode) and in interrupt mode 2 you can place the low byte of a vector in irq. Vector table is a list of words at (I-register << 8) and vector selects one of the entries. In other words: interrupts are just like a real Z80, with a long serving as data bus for the actual IRQ.
There is no RTC, no. I could implement a timer tick in one of the cogs and generate cyclic IRQs, though.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 5:03:26 AM GMT
For the moment there is a lot of code that is experimental and which there is no need to add, eg the bank switching experiment and all the complicated io routines. So to keep things simple:
keyboard
20x4 LCD
sd card access (ideally one that is stable (slower) and also can do fat 16 and fat32)
serial driver
8080 emulation (and full Z80 if it will fit)
For the input, currently it merges keyboard and ports. That code is a bit messy and the only reason for it was so xmodem could do file transfers. I now have a modified version of xmodem that works on port2, so I can make a copy of that so it works on port 1. So rather than any code that merges inputs, I am thinking keep things very simple and just access those with port OUT and IN calls. Which should make the code easier.
(the historical reason for the merging of inputs was that it was using port 0 and a terminal on the PC originally. Then the local keyboard was added. But now the board really is working as a standalone board with either VGA or LCD (or even TV) and its own local keyboard. So there is less need for a version running with a PC terminal program).
And yes, VT100 colour commands would be much neater than via ports. In fact, it should be possible to do this with a lot less ports. VT100 is a good standard.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
Post Edited (Dr_Acula) : 4/14/2010 5:17:33 AM GMT
In mode 2, how is the value of the low order vector byte defined?
Can a terminal character also generate an interrupt?
It sounds like MP/M might be do-able if the memory management is compatible.
Keyboad is there. LCD has to be done (I have some PASM code, just need to incorporate it). SD card access is there, working on my board and so far on everyone else's IIRC!? Serial driver is there, two ports. The second port can be accessed through the SIMH punch ports. Nothing of your port2 code is there, though (baudrate switching, turning port2 off). The 8080 is a different story. You would have to switch the core, because I have a separate q85.spin. This one also does not (yet) support bank switching, but is otherwise compatible with qz80.
I also have SIO port 0 and keyboard return constat and condata. Why would you add xmodem to the console ports? Isn't that protocol a layer above keyboard? Port in/out should work with the punch, unless I have bugs sitting in there. Simple enough to fix, should it be the case, though.
The VT100 code is also LMM capable and can be extended as long as hub RAM is available.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Well, the DI/EI commands should suffice, no? They work as you would expect it.
I can add code to the I/O cog polling loop that generates cyclic interrupts. I've done this for the M100 emulation (where I have some bug that causes the whole thing to stall after 10 minutes ... *grmbl*)
For the tick timer I would suggest 15.625ms then, i.e. clock frequency / 64.
.
You would write e.g. $100 + vector LSB to irq, so that you could also use vector LSB == 0. The interrupt code uses just the lower byte of the value from irq.
Not currently, no, because that would mean to modify the generic Keyboard and/or SIO drivers. I could perhaps poll the status in a cyclic interrupt, which could suffice. I think you could do the same on the Z80 side as well.
It should be, since it is how SIMH does it, and I think MP/M runs on SIMH!?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 5:30:53 AM GMT
DI and EI and interrupts all should work as expected as Juergen says. The propeller has an internal clock that is just perfect for this purpose.
pullmoll, that is great news as it sounds like you already have most of the parts working. Just a matter of pulling them all together.
Re Punch and Reader on the second port, there is a complicated bit of code on the SIMH that combines these together. It took me ages to work out how to seperate out the data and I can't recall how I did it (I'm not at my home computer) but I think there are comments in the code that describe it more. I think they shared a common port or something, and it was possible to seperate them. In the end I used OUT and IN to ports rather than via CP/M but maybe it is worth coding both. I did have both working at one stage.
If we are going to get MPM working then we don't need any of the code that changes port2 baud rate or turns that port on and off. That will all be done as a seperate C or Basic or Assembly program running in MPM. Which will be a lot neater as the spin/pasm code won't need to be changing all the time.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
I'm working on it. First thing is trying to get a ticker interrupt working. There is a SIMH port 22 defined for disabling timer interrupts, but no port for enabling them (again)!? For now I use port 20 to do this, while it's probably better to find out what SIMH really uses for this purpose.
When I have the tick timer working, I will add the LCD code to io.spin.
Edit: Ok, got the timer interrupt working after fixing a bug in the qz80.spin do_timer code (forogot to add # and *4 for the lmm_pc...). Here's my little timer interrupt handler:
It copies the prog..endprog to $ff80, i.e. beyond the boot sector code. It then patches $38 to jump to $ff80. The prog increments the 6 bytes at $fffa..$ffff, so you have a 48 bit tick count. We could easily store the Unix time - seconds since 1.1.1970 - in the whole seconds part $fffb..$ffff and use these values for a real time clock. Only setting the time initially would have to be done somehow, ideally from a RTC, if there is one on the board...
This little BASIC program prints the current seconds (omitting the high bytes) and fraction:
Edit: LCD code is in there now too. Since not all platforms have LCD, I use a global #define HAVE_LCD to enable the code. The io.spin just initializes the LCD at startup, but doesn't output everything that goes to conout to the LCD also, as I think that would be slowing down the SIO #0 and VT100. I wired the LCD to ports $14 (20) = status on read, instruction on write, and $15 (21) = data on write (you can't read the LCD, it returns 0), just like console and punch. Is there a standard CP/M device like LPT that could be redirected to these ports? Then you could write to the LCD by pip or BASIC's LPRINT. Right now LPRINT seems to go to the punch, because I can hear it - with the audio output connected to pin 24
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 8:55:39 AM GMT
I'm working on the slower code to get it to support HCSD and to speed it up a little whilst retaining the stability.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
Me, yes. I grabbed the fast version and put it in the qz80 ./lib directory as DracBlade_mb_small_spi.spin. I guess we should use the same names, though... I wrote a RamBlade variant of the mb_small_spi.spin code, so that one could be renamed as well. We should just settle on a naming scheme and keep that consistent from now on, if you agree
Just a question: If I never use the high port functions, your code will leave the latch alone? The banking I do is in PASM, because I can't call a Spin method from there - and because it should be as fast as possible. I write all three address latches when banking is enabled, limiting the high latch value to 3 bits.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
Post Edited (pullmoll) : 4/14/2010 8:58:03 AM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
I would also like shorter names. Prepending the platform name is okay IMO, just like we (I saw you did that, too) #define it in the top level file. sdspi for the slow version is okay for me. How about just spi_warp for the fast version then? Or what would you like to use?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
For now I'll propose DracBlade_spi.spin and DracBlade_spi_warp.spin as the two object names.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
Okay, agreed! We can perhaps later merge in the code for the RamBlade, if it ever gets tested. It is in ./lib/RamBlade_mb_small_spi.spin if you want to peek at it. qz80 doesn't start on my RamBlade, thus it's untested.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.mikronauts.com E-mail: mikronauts _at_ gmail _dot_ com
My products: Morpheus / Mem+ / PropCade / FlexMem / VMCOG / Propteus / Proteus SerPlug
and 6.250MHz Crystals to run Propellers at 100MHz & 5.0" OEM TFT VGA LCD modules
Las - Large model assembler Largos - upcoming nano operating system
Re MaxS "Bank switching is performed in the xios (mp/m equivalent of bios) by the SELMEMORY entry in the jump table. This is written by the implementer and switches in the appropriate bank depending on how banked memory is supported by the hardware."
Attached is a 'package' for MPM. Unzip to a new directory. Run MPM.BAT. Then run Teraterm and hopefully it will read the local TERATERM.INI and start with a message with the connection to TCP/IP to LOCALHOST with TELNET and port#23. Click OK and it should connect to the MPM simulation. This is actually running CP/M so at the A> prompt type MPM and it should then be running MPM.
Then you would attach various other terminal programs. On the Dracblade, one might have user 1 running the local keyboard and vga disply, user 2 on serial port0 and user3 on serial port1 etc.
In the zip I have extracted out the source code off the disk (you can do this easily with the W command). So a quick search for SELMEMORY in MPMXIOS.MAC finds this code:
just above that is the code for polling each user input, and just below is clock setting and resetting.
A lot of things seem to be done through a port eg:
and simhport is $FE
So I'm starting to get a bit of an idea how this can be run on the propeller. I do note some settings for the disk drive that seem to be for floppy drives, and for all the good reasons Cluso and Heater have found, there really is little point in using any other drive on an sd card than an 8mb hard drive. So maybe those values need changing?
Of course, if MPM can be emulated, I can think of at least three different ways that users can communicate with each other (for the purposes of running code doing a network protocol etc):
1) via custom ports
2) by peeking and poking data to unused ram locations on the 512k ram chip
3) by writing to and reading from files on the sd card
One of the huge strengths of the propeller chip is that it has 8 independent processors. In creating the dracblade, we have used 8 processors to emulate one CP/M machine. It is sort of going backwards in terms of parallel processing. But with MPM, it would be possible to emulate at least 4 processors and possibly 8 or even up to 10. Each with 24 times the memory of a cog, and each with the ability to run multiple languages like Basic and C and Pascal etc all at the same time. So in a way this is like creating a giant propeller chip!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
www.smarthome.viviti.com/propeller
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nathan
"Free as in freedom, beer gratefully accepted though."
To get MP/M running you will need to create a new LDRBIOS for it so as to get it working from the HD only systems.
(I assume you are still running the ZiCog CP/M that has no floppy support)
The LDRBIOS supplied with SIMH Altairz80 only understands floppy drives. Take a look at the CBIOSX.MAC that is on the ZiCog CP/M 2 disks to see how I modified it, removing all Altair floppy driver code and using the HD drivers only.
You will also need to modify MPMXIOS so as to get it to use the hard drives for disks A:, B: ...instead of floppies. Again look at CBIOSX to se how I did that.
For the banked memory, that was already inthe ZiCog emulator albeit with a wee bug. Looks like Pullmoll has that sorted anyway.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
For me, the past is not over yet.
I guess I would have to do the same in the I/O routines if the DMA address for a transfer is below $c000, so that the transfer goes to the correct bank.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Pullmoll's Propeller Projects