EtchedPixels / FUZIX

FuzixOS: Because Small Is Beautiful
Other
2.18k stars 272 forks source link

eZ80 port #710

Closed jcw closed 5 years ago

jcw commented 5 years ago

I've finally got my EZ-Retro build working, which is basically an eZ80F91 with 512 KB or 2 MB SRAM, combined with an STM32F103 board for controlling it and for providing a µSD card as permanent storage (the F103 can control the eZ80 through "ZDI" and the eZ80 can talk over UART and perform disk requests to the F103 through SPI).

After a very long time being shelved, I've found out why it wasn't working (bad solder joint, doh!). This board now reliably passes full 2 MB memory tests at 36 MHz with no wait states. And given eZ80's pipelining, I believe that equates to a classic Z80 running at over 100 MHz.

The eZ80 can be set up to run in std Z80 mode with a 8 KB common page and the rest mapped as a bank to any 64K page in its 16 MB address space (or in this case just the 2 MB attached SRAM). So in principle, it should able to run FUZIX quite nicely. It doesn't have the Z180's MMU design, but it does support a large number of extra instructions (Z180/Z280 compatible, AFAIK).

If there's any interest in the eZ80, I could look into getting FUZIX on there.

EtchedPixels commented 5 years ago

It's not quite compatible in theory (they borrowed some pointless instructions as prefixes) but in practice yes it ought to be.

I'd be very interested in a Fuzix port for ez80, and conveniently Philipp is currently adding ez80 optimizations to SDCC as well right now!

nick-lifx commented 5 years ago

Yes, very interested. Back in the day, I built a prototype of an eZ80 based cash register, it was quite interesting because it had an area of memory reserved for a bitmapped screen and used something like an LDIR instruction to clock out a frame to a parallel LCD periodically, the datasheet suggested you could do this because LDIR gave DMA-like speeds. I still have the devkit somewhere, and could contribute to the eZ80 development. It'd be interesting to arrange compiler support for a 24 bit CPU.

jcw commented 5 years ago

Ok, I've got CP/M 2.2 running again on my eZ80 + 2 MB SRAM. My first FUZIX attempt will be with banked 8x 56K and 8K common, a 1440K disk image in the rest of RAM space, no IRQs, no swap.

jcw commented 5 years ago

Lots of progress, just some homework left to do w.r.t. my bank switching code:

FUZIX version 0.3pre1
Copyright (c) 1988-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza
Copyright (c) 1997-2001 by Arcady Schekochikhin, Adriano C. R. da Cunha
Copyright (c) 2013-2015 Will Sowerbutts <will@sowerbutts.com>
Copyright (c) 2014-2019 Alan Cox <alan@etchedpixels.co.uk>
Devboot
512kB total RAM, 448kB available to processes (7 processes max)
Enabling interrupts ... ok.
Mounting root fs (root_dev=0, ro): OK
Starting /init
init version 0.9.0ac#1
Checking root file system.
0049_switchin: FAIL

Interestingly, bank switching is not needed for disk transfers - there's a way to run special 24-bit instructions, in particular "ldir". I suspect that on eZ80, FUZIX could be made to run with 64 KB user process banks. Combined with the hardware watchdog, this might make the system fairly robust.

jcw commented 5 years ago

Hm, not much luck yet. With process debugging, I get:

Starting /init
init version 0.9.0ac#1
Dofork A709 (n A709)returns 0
udata.u_page 6 p_page 6
parent A6C0
Dofork A752 (n A752)returns 0
udata.u_page 5 p_page 5
parent A709
Dofork A79B (n A79B)returns 0
udata.u_page 4 p_page 4
parent A752
Checking root file system.
0049_switchin: FAIL

Also, system call tracing says the last system call is _exit. So presumably, this is about resuming the parent process. Is there a hint in the 0049 value? Is that the size of a proc table entry, i.e. off-by-one?

Would things have gotten this far if no bank switching took place at all? IOW, if the parent gets overwritten instead of forked to a new address space, would the above output be expected?

Here's the code, at least the wrappers around the actual switching:

map_kernel:
map_kernel_di:
        push af
        xor a
        call selmem
        pop af
            ret

map_process:
map_process_di:
        ld a, h
        or l
        jr z, map_kernel
        ld a, (hl)
map_process_a:
; the actual bank-switching code is in low memory, since SRAM is being moved
selmem:     ; jp.lil {0,seladl}     (enter ADL mode)
            .db 0x5B,0xC3
            .dw seladl
            .db 0x00
selret:     ret ; control returns here once SRAM and MBASE have been adjusted

map_process_always:
map_process_always_di:
        push af
        ld a, (_udata + U_DATA__U_PAGE)
        call selmem
        pop af
        ret

map_save_kernel:
        push af
            .db 0xED,0x38,0xB5  ; in0 a,(RAM_BANK)
        ld (mapsave), a
        xor a
        call selmem
        pop af
        ret     

map_restore:
        push af
        ld a, (mapsave)
        call selmem
        pop af
        ret     

mapsave:    .db 0

This code does the actual work, and lives outside the common bank, in kernel space:

; this code runs in 24-bit ADL mode and must be placed outside SRAM
; FIXME this doesn't handle interrupts in ADL mode, avoid interrupts for now
seladl:     ; out0 (RAM_BANK),a     (move SRAM to selected bank)
            .db 0xED,0x39,0xB5
            ; ld  mb,a          (set MBASE to selected bank)
            .db 0xED,0x6D   
            ; jp.sis selret             (exit ADL mode)
            .db 0x40,0xC3 
            .dw selret

Bit messy, due to the need to encode the special instructions in a non-eZ80-aware assembler.

EtchedPixels commented 5 years ago

Checking root file system. 0049_switchin: FAIL

0049 is the size of a process structure so it tried to switch tasks but the new udata it mapped when switching back to pid 1 contained the udata for pid 2.

So I would guess you either copied the wrong udata back on the switch or you didn't copy it back at all ?

jcw commented 5 years ago

Thanks, that led to the fix. I still had the 0xC000 .. 0xDFFF ram bank enabled as well, so the setup was configured for 8K common, but the hardware was behaving as 16K common. Onwards, last thing I need to do for this initial setup, is to implement tty input.

jcw commented 5 years ago

Ok, here's my simple port to eZ80. As mentioned, it relies on a secondary µC, and needs 2 MB RAM, of which 1.5 MB are used as RAM disk. There's no real disk driver, no rtc, and no interrupt handling.

I'm attaching this as a ZIP file, as I'm moving away from GitHub and a bit too lazy to go through their tedious pull-request dance (a simple branching model would work much better for me, but that requires a basic level of commit access on GitHub, which you may not want to consider).

I've tried to document my work on this port in the included platform-ezretro/README.md.

platform-ezretro.zip

UPDATE - for completeness, here's a transcript of the output:

IZCD<0>A<1474560>B
FUZIX version 0.3pre1
Copyright (c) 1988-2002 by H.F.Bower, D.Braun, S.Nitschke, H.Peraza
Copyright (c) 1997-2001 by Arcady Schekochikhin, Adriano C. R. da Cunha
Copyright (c) 2013-2015 Will Sowerbutts <will@sowerbutts.com>
Copyright (c) 2014-2019 Alan Cox <alan@etchedpixels.co.uk>
Devboot
512kB total RAM, 448kB available to processes (8 processes max)
Enabling interrupts ... ok.
Mounting root fs (root_dev=0, ro): OK
Starting /init
init version 0.9.0ac#1
Checking root file system.
Current date is Thu 1970-01-01
Enter new date:
Current time is  0:00:00
Enter new time:

 ^ ^
 n n   Fuzix 0.3rc1
 >@<
       Welcome to Fuzix
 m m

login: root

Welcome to FUZIX.
# df -k
Filesystem       KBytes   Used   Free  %Used Mounted on
/dev/hda           1440    406   1002    29% /
# ps
  PID    TTY     TIME CMD
    9    tty1 00:00:00 -sh
   11    tty1 00:00:00 ps
#
jcw commented 5 years ago

PS. The Kernel/ directory is starting to become a bit unwieldy. I'd vote for creating a new platforms/ directory, and then inside there sbcv2, z80pack, ezretro, etc. The current symlink of platform (no "s") could then remain as is. It would help while moving around and working on kernel stuff for a single platform (the same could be argued for cpu-*/ and cpus/, but that's less overwhelming).

EtchedPixels commented 5 years ago

At some point I need to sort out platform-* but later after I have a 0.3 release.

I've merged the stuff (and patches for updates are fine - others work that way). I tidied a few tiny bits up to use some of the current sdcc features (build it with -mez80_z80, start using the ez80 asm support in the current sdcc etc) so you might want to treat it with care as it is possible that sdcc will throw up some ez80 bugs yet.

jcw commented 5 years ago

Thx, also for the tidying. It all works. Good to see in0/out0 support in sdcc, that was a nuisance.

cfarrar commented 3 years ago

I vote for a pure port. using zds II compiler package and abandoning the sdcc compiler and z80 compatibility. The end result will be fuzix running in full adl mode. A cpm emulator can thunk down to z80 mode run z80 programs. As for the small c compiler within the package, it would have to be extended generate adl mode compatible output.