Other Processors
----------------
-Currently only Z80 and 6809 are properly supported. Clones should also work as
-should FPGA cores like T80. The current build uses no undocumented instructions
-in any core code.
+Currently only 68000, 6809 and Z80 are properly supported. Clones should also
+work as should FPGA cores like T80. The current build uses no undocumented
+instructions in any core code but the SDCC library does use them for its
+float support.
It ought to be possible to port UZI to any other small processor with
banking. That would include banked 6809/6309 systems and perhaps 65C816
(Apple IIGS anyone ?) with a suitable compiler. The current core code has
been tested to some extent on 6502, and has been build tested on 8086 and
-68000. Various endianisms in the core code have been fixed but there may be
+PDP/11. Various endianisms in the core code have been fixed but there may be
more.
The constraints roughly speaking for any port are
As far as I can tell we have suitable open toolchains for
-6809 (gcc fork) - although 6809 is well served by NitrOS/9.
-
68HC11/2 (for the variants with banked RAM)
TI990 (gcc development) - http://www.cozx.com/~dpitts/tigccinst.html
Various other early minicomputers probably also fit the target.
-Going to early 32bit CPU is hard because
-- not all of the core code is 32bit clean (I've tried to begin marking out
- the argument parameters and the like to fix it)
-- the fs code knows that you can't write a size bigger than the filesystem
- so other sanity checks would need adding
+Interrupts
+----------
+
+The current default behaviour leaves interrupts off for long periods. In
+some cases such as floppy drivers this is hard to avoid on most 8bit
+machines. We try and minimise the harm this causes by loosely tying the
+system clock to the low part of any available RTC (the full RTC isn't used
+both because of the conversion costs, and because of Y2K issues on many
+systems).
+
+It is possible with care to re-enable interrupts during swapping on a task
+switch which is the big nasty but this requires care that mappings are
+always valid. With a fixed common space it isn't too bad.
+
+It's also now possible to define CONFIG_SOFT_IRQ in which case the platform
+provides its own routines for IRQ management and the kernel uses those. The
+requirements for this are:
+
+- You don't call any Fuzix core code while you are in 'di' state
+- You don't try and run extra timer ticks when the 'ei' or 'irqrestore'
+ occurs.
+
+You can thus keep system interrupts on a lot more and copy serial bytes
+into/out of a FIFO buffer or count missed timer ticks. Timer ticks need to
+be processed together in the timer interrupt. so you can call timer_interrupt()
+the correct number of times from the actual timer interrupt handler, but
+because of the context switching must not try and do it anywhere else.
+
+On a 68000 or a 6809 your vectors and stack are usually valid except during
+task switching (tricks.S) so it is fairly easy to handle. On a Z80 a lot of
+care is needed because we must avoid taking an interrupt while the mapped
+low bank does not have valid vectors. Bank16k uses __hard_di for a few
+cases because of this. For a Z80 platform with fixed common and low banks
+you should write the vectors into each bank at early boot time before
+interrupts are enabled.
+
+Fuzix expects physical interrupts to be off on entry, and it will call
+__hard_ei() at the right point in startup. It may call di/ei/irqrestore
+before that but with physical interrupts still off.
+
-A 2BSD/RetroBSD port might make a lot more sense anyway on such a system
Other Things That Would Help
/* We don't want to take an interrupt here while our page mappings are
incomplete. We may restore bogus mappings and then take a second IRQ
into hyperspace */
- irq = di();
+ irq = __hard_di();
if (have > want) {
for (i = want; i < have; i++) {
update = 1;
} else {
- irqrestore(irq);
+ __hard_irqrestore(irq);
return ENOMEM;
}
/* Copy the updated allocation into the ptab */
we switch to this memory map */
if (update)
program_vectors(&udata.u_page);
- irqrestore(irq);
+ __hard_irqrestore(irq);
return 0;
}
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void __fastcall__ irqrestore(irqflags_t f);
-
extern void * __fastcall__ memcpy(void *, void *, size_t);
extern void * __fastcall__ memset(void *, int, size_t);
extern size_t __fastcall__ strlen(const char *);
#define uputi uputl /* Copy user int type */
#define ugeti ugetl /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
-
extern void *memcpy(void *, const void *, size_t);
extern void *memset(void *, int, size_t);
extern int memcmp(const void *, const void *, size_t);
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
-
#define EMAGIC 0x7E /* Header of executable (JMP) */
#define EMAGIC_2 0x20 /* BRA */
/* Allow a minimum of 512 bytes gap between stack and top of allocations */
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
-
#define EMAGIC 0x7E /* Header of executable (JMP) */
#define EMAGIC_2 0x20 /* BRA */
/* Allow a minimum of 512 bytes gap between stack and top of allocations */
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
-
extern void * memcpy(void *, void *, size_t);
extern void * memset(void *, int, size_t);
extern size_t strlen(const char *);
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-extern void ei(void);
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
-
/* FIXME: we actually want to use an a.out loader */
#define EMAGIC 0x7E /* Header of executable (JMP) */
#define uputi uputw /* Copy user int type */
#define ugeti ugetw /* between user and kernel */
-#define ei() do {__asm ei __endasm; } while(0);
-
typedef uint16_t irqflags_t;
-extern irqflags_t di(void);
-extern void irqrestore(irqflags_t f);
extern void out(uint8_t addr, uint8_t val);
extern uint8_t in(uint8_t addr);
extern void trap_reboot(void);
extern uint8_t platform_param(char *p);
+extern irqflags_t __hard_di(void);
+extern void __hard_irqrestore(irqflags_t f);
+extern void __hard_ei(void);
+
+#ifndef CONFIG_SOFT_IRQ
+#define di __hard_di
+#define irqrestore __hard_irqrestore
+#define ei __hard_ei
+#endif
+
/* Will need a uptr_t eventually */
extern uaddr_t ramtop; /* Note: ramtop must be in common in some cases */
extern void platform_interrupt(void);
outcharhex:
ret
-_di:
+___hard_di:
pushf
pop ax
cli
ret
-_irqrestore:
+___hard_irqrestore:
push ax
popf
ret
-
\ No newline at end of file
+
+___hard_ei:
+ sti
+ ret
#include "kernel-pdp11.def"
- .globl _di
- .globl _ei
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
.globl _doexec
.globl ___udivhi3
.globl ___umodhi3
address space - for now 077776 and the other control registers work
in a very similar way */
-_di:
+___hard_di:
mov 0177776,r0
bis 0340,0177776
rts pc
-_ei:
+___hard_ei:
mov 0177776,r0
bic 0340,0177776
rts pc
-_irqrestore:
+___hard_irqrestore:
mov 2(sp),0177776
rts pc
.globl trap_illegal
.globl nmi_handler
.globl interrupt_handler
- .globl _di
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
.globl _in
.globl _out
; IRQ helpers, in common as they may get used by common C
; code (and are tiny)
-_di: ld a, i
+___hard_di: ld a, i
push af
pop hl
di
ret
-_irqrestore: pop hl ; sdcc needs to get register arg passing
+___hard_irqrestore:
+ pop hl ; sdcc needs to get register arg passing
pop de
pop af ; so badly
jp po, was_di
; IRQ helpers, in common as they may get used by common C
; code (and are tiny)
-_di: ld a, i
+___hard_di: ld a, i
push af
pop hl
di
ret
-_irqrestore: pop hl ; sdcc needs to get register arg passing
+___hard_irqrestore:
+ pop hl ; sdcc needs to get register arg passing
pop af ; so badly
jp po, was_di
ei
.area _COMMONMEM
-_di: xor a ; NMOS Z80 bug work around as per CPU manual
+___hard_di: xor a ; NMOS Z80 bug work around as per CPU manual
push af
pop af ; clear byte on stack below our usage
ld a, i
di
ret
-_irqrestore: pop hl
+___hard_irqrestore:
+ pop hl
pop de
pop af
jr c, was_di
.area _COMMONMEM
-_di: xor a ; NMOS Z80 bug work around as per CPU manual
+___hard_di: xor a ; NMOS Z80 bug work around as per CPU manual
push af
pop af ; clear byte on stack below our usage
ld a, i
di
ret
-_irqrestore: pop hl
+___hard_irqrestore:
+ pop hl
pop af
jr c, was_di
ei
.globl trap_illegal
.globl nmi_handler
.globl interrupt_handler
- .globl _di
- .globl _irqrestore
+ .globl ___hard_ei
+ .globl ___hard_di
+ .globl ___hard_irqrestore
.globl _out
.globl _in
in l, (c)
ret
+;
+; Enable interrupts
+;
+___hard_ei:
+ ei
+ ret
+
;
; Pull in the CPU specific workarounds
;
.globl _trap_monitor
.globl _trap_reboot
.globl outchar
- .globl _di
- .globl _ei
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
include "kernel.def"
include "../kernel09.def"
orcc #0x10
bra _trap_monitor
-_di:
+___hard_di:
tfr cc,b ; return the old irq state
orcc #0x10
rts
-_ei:
+___hard_ei:
andcc #0xef
rts
-_irqrestore: ; B holds the data
+___hard_irqrestore: ; B holds the data
tfr b,cc
rts
.globl _trap_monitor
.globl _trap_reboot
.globl outchar
- .globl _di
- .globl _ei
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
; imported symbols
.globl _ramsize
;;; Turn off interrupts
;;; takes: nothing
;;; returns: B = original irq (cc) state
-_di:
+___hard_di:
tfr cc,b ; return the old irq state
orcc #0x10
rts
;;; Turn on interrupts
;;; takes: nothing
;;; returns: nothing
-_ei:
+___hard_ei:
andcc #0xef
rts
;;; Restore interrupts to saved setting
;;; takes: B = saved state (as returned from _di )
;;; returns: nothing
-_irqrestore: ; B holds the data
+___hard_irqrestore: ; B holds the data
tfr b,cc
rts
.globl _trap_monitor
.globl _trap_reboot
.globl outchar
- .globl _di
- .globl _ei
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
include "kernel.def"
include "../kernel09.def"
orcc #0x10
bra _trap_monitor
-_di:
+___hard_di:
tfr cc,b ; return the old irq state
orcc #0x10
rts
-_ei:
+___hard_ei:
andcc #0xef
rts
-_irqrestore: ; B holds the data
+___hard_irqrestore: ; B holds the data
tfr b,cc
rts
.globl _trap_monitor
.globl _trap_reboot
.globl outchar
- .globl _di
- .globl _ei
- .globl _irqrestore
+ .globl ___hard_di
+ .globl ___hard_ei
+ .globl ___hard_irqrestore
; imported symbols
.globl _ramsize
cwai #0
bra _trap_monitor
-_di:
+___hard_di:
tfr cc,b ; return the old irq state
orcc #0x10
rts
-_ei:
+___hard_ei:
andcc #0xef
rts
-_irqrestore: ; B holds the data
+___hard_irqrestore: ; B holds the data
tfr b,cc
rts
;;; Turn off interrupts
;;; takes: nothing
;;; returns: B = original irq (cc) state
-_di:
+___hard_di:
tfr cc,b ; return the old irq state
orcc #0x10
rts
;;; Turn on interrupts
;;; takes: nothing
;;; returns: nothing
-_ei:
+___hard_ei:
andcc #0xef
rts
;;; Restore interrupts to saved setting
;;; takes: B = saved state (as returned from _di )
;;; returns: nothing
-_irqrestore: ; B holds the data
+___hard_irqrestore: ; B holds the data
tfr b,cc
rts
.export _trap_monitor
.export _trap_reboot
.export outchar
- .export _di
- .export _ei
- .export _irqrestore
+ .export ___hard_di
+ .export ___hard_ei
+ .export ___hard_irqrestore
.export vector
.import interrupt_handler
_trap_reboot:
jmp _trap_reboot ; FIXME: original ROM map and jmp
-_di:
+___hard_di:
php
sei ; Save old state in return to C
pla ; Old status
rts
-_ei:
+___hard_ei:
cli ; on 6502 cli enables IRQs!!!
rts
-_irqrestore:
+___hard_irqrestore:
and #4 ; IRQ flag
beq irq_on
cli
ticks_per_dsecond = TICKSPERSEC / 10;
kputs("Enabling interrupts ... ");
- ei();
+ __hard_ei(); /* Physical interrupts on */
kputs("ok.\n");
/* get the root device */