From 5e0fcd45040ca6c811c22f838979bb58df21ce95 Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Thu, 13 Sep 2018 23:13:42 +0200 Subject: [PATCH] New MOOH platform with 8K flexible banks This is in good enough shape to try out levee :) Adjusting the program allocation sizes with chmem seems to work fine. A few TODOs: The virtual consoles currently overlap with the graphics framebuffer so using them doesn't look pretty. Trials at moving them fails badly, maybe related to next issue: We need to disable interrupts in the code accessing video memory, because common is not there then. Or deal with this in the interrupt handlers. Trials at disabling interrupts have not been successful yet. Signed-off-by: Tormod Volden --- Kernel/platform-dragon-mooh/Makefile | 78 ++++ Kernel/platform-dragon-mooh/README | 57 +++ Kernel/platform-dragon-mooh/char42.s | 412 ++++++++++++++++++ Kernel/platform-dragon-mooh/config.h | 88 ++++ Kernel/platform-dragon-mooh/crt0.s | 76 ++++ Kernel/platform-dragon-mooh/discard.c | 161 ++++++++ Kernel/platform-dragon-mooh/dragon.s | 305 ++++++++++++++ Kernel/platform-dragon-mooh/fuzix.link | 23 ++ Kernel/platform-dragon-mooh/kernel.def | 25 ++ Kernel/platform-dragon-mooh/mem-mooh.s | 136 ++++++ Kernel/platform-dragon-mooh/multihead.s | 124 ++++++ Kernel/platform-dragon-mooh/rules.mk | 5 + Kernel/platform-dragon-mooh/target.mk | 3 + Kernel/platform-dragon-mooh/tricks.s | 233 +++++++++++ Kernel/platform-dragon-mooh/usermem_sam.s | 128 ++++++ Kernel/platform-dragon-mooh/video.s | 481 ++++++++++++++++++++++ 16 files changed, 2335 insertions(+) create mode 100644 Kernel/platform-dragon-mooh/Makefile create mode 100644 Kernel/platform-dragon-mooh/README create mode 100644 Kernel/platform-dragon-mooh/char42.s create mode 100644 Kernel/platform-dragon-mooh/config.h create mode 100644 Kernel/platform-dragon-mooh/crt0.s create mode 100644 Kernel/platform-dragon-mooh/discard.c create mode 100644 Kernel/platform-dragon-mooh/dragon.s create mode 100644 Kernel/platform-dragon-mooh/fuzix.link create mode 100644 Kernel/platform-dragon-mooh/kernel.def create mode 100644 Kernel/platform-dragon-mooh/mem-mooh.s create mode 100644 Kernel/platform-dragon-mooh/multihead.s create mode 100644 Kernel/platform-dragon-mooh/rules.mk create mode 100644 Kernel/platform-dragon-mooh/target.mk create mode 100644 Kernel/platform-dragon-mooh/tricks.s create mode 100644 Kernel/platform-dragon-mooh/usermem_sam.s create mode 100644 Kernel/platform-dragon-mooh/video.s diff --git a/Kernel/platform-dragon-mooh/Makefile b/Kernel/platform-dragon-mooh/Makefile new file mode 100644 index 00000000..86274807 --- /dev/null +++ b/Kernel/platform-dragon-mooh/Makefile @@ -0,0 +1,78 @@ +# steal what we can from nx32 port +VPATH = .:../platform-dragon-nx32 + +CSRCS = devlpr.c devtty.c devfd.c ttydw.c +CSRCS += devices.c main.c libc.c + +VSRCS = vc.c + +CDSRCS = discard.c + +DSRCS = ../dev/devdw.c ../dev/blkdev.c ../dev/devide.c \ + ../dev/crt9128.c \ + ../dev/devsd.c + +DDSRCS = ../dev/devide_discard.c ../dev/mbr.c \ + ../dev/gpt.c ../dev/devsd_discard.c + +ASRCS = crt0.s dragon.s mem-mooh.s video.s ide.s spi.s +ASRCS += tricks.s commonmem.s usermem_sam.s floppy.s drivewire.s +ASRCS += multihead.s +ASRCS += char42.s + +COBJS = $(CSRCS:.c=$(BINEXT)) +VOBJS = $(VSRCS:.c=$(BINEXT)) +CDOBJS = $(CDSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.s=$(BINEXT)) +DOBJS = $(patsubst ../dev/%.c,%.o, $(DSRCS)) +DDOBJS = $(patsubst ../dev/%.c,%.o, $(DDSRCS)) +OBJS = $(COBJS) $(VOBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(DDOBJS) + +CROSS_CCOPTS += -I../dev/ -I../platform-dragon-nx32/ + +drivewire.o: ASOPTS += --defsym BECKER=$(BECKER) + +JUNK = $(CSRCS:.c=.o) $(ASRCS:.s=.o) + +all: $(OBJS) + +$(COBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) -c $< + +$(VOBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_VIDEO) -c $< + +$(CDOBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DOBJS): %$(BINEXT): ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) -c $< + +$(DDOBJS): %$(BINEXT): ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(AOBJS): %$(BINEXT): %.s + $(CROSS_AS) $(ASOPTS) $< -o $*.o + +clean: + rm -f $(OBJS) $(JUNK) + +image: + $(CROSS_LD) -o ../fuzix.bin -Map=../fuzix.map --script=fuzix.link --oformat=decb \ + crt0.o commonmem.o usermem_sam.o \ + dragon.o mem-mooh.o ../bank8k.o \ + ../start.o ../version.o ../lowlevel-6809.o \ + tricks.o main.o ../timer.o ../kdata.o devfd.o floppy.o devices.o \ + multihead.o crt9128.o vc.o \ + char42.o \ + drivewire.o devdw.o ttydw.o \ + ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \ + ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o \ + ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec16.o \ + ../syscall_fs3.o \ + devlpr.o devtty.o libc.o ../vt.o video.o ../font8x8.o \ + devide.o blkdev.o ide.o devide_discard.o mbr.o gpt.o \ + devsd.o devsd_discard.o spi.o \ + discard.o + ../tools/pad256 ../fuzix.bin + ../tools/lw-checkmap ../fuzix.map diff --git a/Kernel/platform-dragon-mooh/README b/Kernel/platform-dragon-mooh/README new file mode 100644 index 00000000..97450a63 --- /dev/null +++ b/Kernel/platform-dragon-mooh/README @@ -0,0 +1,57 @@ +This port is for the Dragon/CoCo with 32K internal memory and a MOOH +external memory cartridge. It uses the 8K banks memory model with +flexible mapping. + +It is not compatible with the dragon-nx32 (or its MOOH build variant) +and needs all applications linked differently (load address). + +It works fine on the 64K computers (Dragon 64/Tano, CoCo2) as well but +another port could be made to fully exploit the extra memory. + +About the memory map: +The 6847 video generator can only access the internal memory - it has +its own data bus and SAM generates memory access addresses for it. + +Since the internal memory here (unlike the upper 32K on the 64K +machines) will be scribbled upon external memory writes in the same CPU +space (thanks to the sloppy internal SLENB deactivation logic), we keep +the video in the first 8KB of memory, and only map read-only sections on +top of the 6K video area. This leaves us with 2KB of read/write memory +for common data and udata. The remaining 7 banks can be mapped freely. + +The upper 256 bytes at FF00 always map I/O and are therefore excluded +from memory access. The MOOH (like the GIME) has an optional vector page +at 0xFE00 (Common Reserved Memory) that we also can use for common code +(in general well suited for small primary interrupt handlers). + +Bootstrapping: +Using the same bootloaders as for dragon-nx32 (SDBOOT etc) the kernel is +loaded at internal memory 0x1C00 upwards and written to banks 0-3 above +0x8000. + +The tricky part is loading the common into the lowest bank, since the +bootloader uses this memory area. We here use a tool that modifies the +DECB image to shift the segment load addresses from 0x0000-0x1FFF up to +0x2000-0x3FFF and also insert mini segments poking the appropriate bank +values into the MMU registers. See Kernel/tools/decb-mooh.c. + +We also replace the loaded bank 3 with bank $3F to sit at 0xE000 - it is +the only place we can map it so we'll use it for the kernel here. + +After relocation we have: +0000 bank 4 2K commondata + 6K common || 6K video (internal memory) +2000 bank 5 +4000 bank 6 +6000 bank 7 + +8000 bank 0 +A000 bank 1 +C000 bank 2 +E000 bank 0x3F (was loaded into bank 3) + +and banks 8-0x3E and 3 for user apps flexibly mapped at 0x2000-0xFDFF + +We make use of the two MMU tasks so we can efficiently switch between +kernel (task 0) and user mapping (task 1). The user mapping should in +principle only need to be rewritten to the MMU on switchout() and after +page map (re)allocation. diff --git a/Kernel/platform-dragon-mooh/char42.s b/Kernel/platform-dragon-mooh/char42.s new file mode 100644 index 00000000..0b83ffdf --- /dev/null +++ b/Kernel/platform-dragon-mooh/char42.s @@ -0,0 +1,412 @@ +******************************************************************** +* +* Taken from NitrOS-9 level1/modules/co42.asm 2018-08-18 +* +* Co42 - Hi-Res 42x24 Graphics Console Output Subroutine for VTIO +* Based from CoHR +* +* $Id$ +* +* Edt/Rev YYYY/MM/DD Modified by +* Comment +* ------------------------------------------------------------------ +* 1 ????/??/?? +* Original Dragon distribution version +* +* 2003/09/22 Rodney Hamilton +* Recoded fcb arrays, added labels & some comments +* +* 2004/11/15 P.Harvey-Smith +* Added code to turn off the drives on the Dragon Alpha. +* +* 2004/12/01 P.Harvey-Smith +* Began converting drvr51 to CoHR, removed all keyboard +* related code, added symbolic defines for a lot of things. +* +* 2004/12/02 P.Harvey-Smith +* Finished converting to c051 driver, moved all variable +* storage into ccio module (defined in cciodefs). +* +* 2005/04/09 P.Harvey-Smith +* Replaced all ; comment chars with * for benefit of native +* asm. Re-implemented (hopefully) non-destructive cursor which +* is XORed onto the screen. Commented character drawing routines +* and replaced the V51xx names with more meaningful ones. +* +* 2005/04/24 P.Harvey-Smith +* Addded routines to flash the cursor, this is as it was in the +* Dragon Data 51 column driver. +* +* 2017/04/23 Felipe Antoniosi +* Create this driver as 42x24 column +* +* 2018/01/20 David Ladd +* Moved Driver Entry Table closer to Term to allow fall through. +* This is to save bytes and cycles. Changed lbra Write to bra +* Write to save cyrcles each time characters are written to screen. +* Also changed lda and ldb to a ldd to save cycle(s) and space. +* Also a few other optimizations to code. +* +* 2018/08/18 Tormod Volden +* Extract DrawCharacter routine for use in FUZIX +* + + .module char42 + + .globl _m6847_plot_char_42 + .globl _m6847_cursor_on_42 + .globl _m6847_cursor_off_42 + + include "kernel.def" + +ScreenSize equ $1800 ; Screen Size in Bytes + + .area .videodata + +ScreenMask .dw 0 +BytePixOffset .db 0 +XORFlag .db 0 +CursorChanged .db 0 +ReverseFlag .db 1 ; are we in reverse mode ? +CursorSave .dw 0 + + .area .video + +* FIXME clear_across is missing + +* void m6847_cursor_on(int8_t newy, int8_t newx); + +_m6847_cursor_on_42: + pshs y,b ; newy + lda 5,s ; newx + std CursorSave + ldb #$7f + inc XORFlag + lbsr DrawCharacter ; stack: newx C-pc y newy pc + dec XORFlag + puls b,y,pc + + +* void m6847_cursor_off(void); + +_m6847_cursor_off_42: + ldd CursorSave + pshs a + pshs u,y,b + ldb #$7f + inc XORFlag + lbsr DrawCharacter ; stack: C-pc oldx u y oldy pc + dec XORFlag + puls b,y,u + puls a,pc + + +* called as plot_char(int8_t y, int8_t x, uint16_t c) + +_m6847_plot_char_42: + pshs y,b ; Ypos + tfr x,d ; character now in b + bsr DrawCharacter + puls b,y,pc + +* +* Draw the normal characters $20..$7f, in the b register +* Stack: Xpos C-pc y Ypos pc + +DrawCharacter + lda #$3F + sta $FFA0 ; unmap kernel in video memory area + subb #$20 ; Make b an offset into table + lda #5 + ldx #CharacterShapes ; point to character shape table + mul ; Multiply by 5 (5 bytes / character) + leax d,x ; Point X at required character's bitmap + ldb #$06 ; Work out pixel X co-ordinate of current cursor + lda 7,s ; Xpos + mul + pshs b ; Save pixel x + lsra ; Divide pixel-x by 8, to get byte offset into line + rorb + lsra + rorb + lsra + rorb + lda ,s + anda #$07 ; Calculate offset within byte where character begins + stb ,s +* puls a ; restore pixel X +* anda #$07 ; Calculate offset within byte where character begins +* pshs b + sta BytePixOffset + tst XORFlag + bne L01FF + tfr a,b ; Calculate a mask for character data + lda #$FC ; shifts $fc right b times + tstb + beq L01FA ; Done all bits ? +L01E5 lsra ; shift mask right + decb ; decrement count + bhi L01E5 ; done all ? + bne L01EE ; have we shifted any mask bits off right hand end ? + rorb + bra L01FA + +L01EE pshs b ; Save count on stack + ldb #$80 ; start to build mask for second byte as well +L01F2 lsra ; shift bits from bottom of a to top of b + rorb + dec ,s ; decrement count + bne L01F2 ; if any shifts left loop again + leas 1,s ; drop count + +* When we reach here we should have a pair of bytes in d which indicate where exactly the +* character should be drawn, this may be partly in each + +L01FA coma + comb + std ScreenMask ; Save screen mask + +* The code below works out the offset of the character cell to be updated, this works because +* the y coordinate is loaded into the high byte of d, effectively multiplying it by 256, since +* each screen line is 32 bytes wide, and each character is 8 pixels tall this works out as 8x32=256 + +L01FF ldy #VIDEO_BASE ; Point y at screen memory address + lda 3,s ; YPos + ldb ,s+ ; Retrieve byte offset from stack + leay d,y ; calculate screen address. +* lda #$08 ; get character data byte count, 8 bytes +* pshs a + inc CursorChanged ; flag character at cursor being changed + +* The caracters are packed in 5-bytes following the order +* 00000111 +* 11222223 +* 33334444 +* 45555566 +* 66677777 + +L0211 lda ,x ; row 0 + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x+ ; row 1 + ldb ,x + lsra + rorb + lsra + rorb + lsra + rorb + tfr b,a + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x ; row 2 + lsla + lsla + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x+ ; row 3 + ldb ,x + lsra + rorb + tfr b,a + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x+ ; row 4 + ldb ,x + lslb + rola + lslb + rola + lslb + rola + lslb + rola + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x ; row 5 + lsla + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x+ ; row 6 + ldb ,x + lsra + rorb + lsra + rorb + tfr b,a + anda #$F8 ; mask out character + bsr L0236 ; update screen + + lda ,x ; row 7 + lsla + lsla + lsla + anda #$F8 ; mask out character + bsr L0236 ; update screen + +* dec ,s ; Decrement character data byte counter +* bne L0211 ; all done ? + dec CursorChanged ; Flag character update finished + lda #4 + sta $ffA0 ; remap kernel + rts + + +*L0227 ldb BytePixOffset +* subb #$04 +* bhi L023B +* beq L0250 +*L0230 lsla +* incb +* bne L0230 +* bra L0250 + +L0236 ldb BytePixOffset ; Retrieve byte pixel offset + beq L0250 + +L023B lsra ; manipulate character data into correct position + decb ; in a similar way to the mask above + bhi L023B + bne L0244 + rorb + bra L0250 +L0244 pshs b + ldb #$80 +L0248 lsra + rorb + dec ,s + bne L0248 + leas 1,s + +L0250 tst XORFlag ; are we XORing data direct to screen ? + bne L0273 ; Yes : just do it + tst ReverseFlag ; are we in reverse mode ? + beq L0262 ; no : just output data + coma ; set mask up for reverse mode + comb + eora ScreenMask + eorb ScreenMask+1 + +L0262 pshs b,a ; combine mask and screen data + ldd ScreenMask + anda ,y + andb $01,y + addd ,s++ + +L026D std ,y ; screen update + leay <$20,y + rts + +L0273 eora ,y ; XOR onto screen + eorb $01,y + bra L026D + + puls pc,b + + .area .videodata + +CharacterShapes + + fcb $00,$00,$00,$00,$00 ; ' ' + fcb $21,$08,$40,$00,$80 ; '!' + fcb $52,$94,$00,$00,$00 ; '"' + fcb $52,$be,$af,$a9,$40 ; '#' + fcb $23,$e8,$e2,$f8,$80 ; '$' + fcb $c6,$44,$44,$4c,$60 ; '%' + fcb $45,$11,$59,$4d,$80 ; '&' + fcb $11,$10,$00,$00,$00 ; ''' + fcb $11,$10,$84,$10,$40 ; '(' + fcb $41,$04,$21,$11,$00 ; ')' + fcb $25,$5c,$47,$54,$80 ; '*' + fcb $01,$09,$f2,$10,$00 ; '+' + fcb $00,$00,$00,$10,$88 ; ',' + fcb $00,$00,$f0,$00,$00 ; '-' + fcb $00,$00,$00,$31,$80 ; '.' + fcb $00,$02,$22,$22,$00 ; '/' + fcb $74,$67,$5c,$c5,$c0 ; '0' + fcb $23,$28,$42,$13,$e0 ; '1' + fcb $74,$42,$26,$43,$e0 ; '2' + fcb $74,$42,$60,$c5,$c0 ; '3' + fcb $11,$95,$2f,$88,$40 ; '4' + fcb $fc,$38,$20,$8b,$80 ; '5' + fcb $32,$21,$e8,$c5,$c0 ; '6' + fcb $fc,$44,$42,$10,$80 ; '7' + fcb $74,$62,$e8,$c5,$c0 ; '8' + fcb $74,$62,$f0,$89,$80 ; '9' + fcb $00,$08,$00,$10,$00 ; ':' + fcb $00,$08,$00,$10,$88 ; ';' + fcb $19,$99,$86,$18,$60 ; '<' + fcb $00,$3e,$0f,$80,$00 ; '=' + fcb $c3,$0c,$33,$33,$00 ; '>' + fcb $74,$42,$22,$00,$80 ; '?' + fcb $74,$42,$da,$d5,$c0 ; '@' + fcb $22,$a3,$1f,$c6,$20 ; 'A' + fcb $f2,$52,$e4,$a7,$c0 ; 'B' + fcb $32,$61,$08,$24,$c0 ; 'C' + fcb $e2,$92,$94,$ab,$80 ; 'D' + fcb $fc,$21,$e8,$43,$e0 ; 'E' + fcb $fc,$21,$e8,$42,$00 ; 'F' + fcb $74,$61,$78,$c5,$c0 ; 'G' + fcb $8c,$63,$f8,$c6,$20 ; 'H' + fcb $71,$08,$42,$11,$c0 ; 'I' + fcb $38,$84,$29,$49,$80 ; 'J' + fcb $8c,$a9,$8a,$4a,$20 ; 'K' + fcb $84,$21,$08,$43,$e0 ; 'L' + fcb $8e,$eb,$58,$c6,$20 ; 'M' + fcb $8e,$73,$59,$ce,$20 ; 'N' + fcb $74,$63,$18,$c5,$c0 ; 'O' + fcb $f4,$63,$e8,$42,$00 ; 'P' + fcb $74,$63,$1a,$c9,$a0 ; 'Q' + fcb $f4,$63,$ea,$4a,$20 ; 'R' + fcb $74,$60,$e0,$c5,$c0 ; 'S' + fcb $f9,$08,$42,$10,$80 ; 'T' + fcb $8c,$63,$18,$c5,$c0 ; 'U' + fcb $8c,$63,$15,$28,$80 ; 'V' + fcb $8c,$63,$5a,$ee,$20 ; 'W' + fcb $8c,$54,$45,$46,$20 ; 'X' + fcb $8c,$62,$e2,$10,$80 ; 'Y' + fcb $f8,$44,$44,$43,$e0 ; 'Z' + fcb $72,$10,$84,$21,$c0 ; '[' + fcb $00,$20,$82,$08,$20 ; '\' + fcb $70,$84,$21,$09,$c0 ; ']' + fcb $22,$a2,$00,$00,$00 ; '^' + fcb $00,$00,$00,$03,$e0 ; '_' + fcb $41,$04,$00,$00,$00 ; '`' + fcb $00,$1c,$17,$c5,$e0 ; 'a' + fcb $84,$2d,$98,$e6,$c0 ; 'b' + fcb $00,$1d,$18,$45,$c0 ; 'c' + fcb $08,$5b,$38,$cd,$a0 ; 'd' + fcb $00,$1d,$1f,$c1,$c0 ; 'e' + fcb $11,$49,$f2,$10,$80 ; 'f' + fcb $00,$1b,$39,$b4,$2e ; 'g' + fcb $84,$3d,$18,$c6,$20 ; 'h' + fcb $20,$18,$42,$11,$c0 ; 'i' + fcb $10,$0c,$21,$0a,$4c ; 'j' + fcb $42,$12,$a6,$29,$20 ; 'k' + fcb $61,$08,$42,$11,$c0 ; 'l' + fcb $00,$35,$5a,$d6,$a0 ; 'm' + fcb $00,$2d,$98,$c6,$20 ; 'n' + fcb $00,$1d,$18,$c5,$c0 ; 'o' + fcb $00,$2d,$9c,$da,$10 ; 'p' + fcb $00,$1b,$39,$b4,$21 ; 'q' + fcb $00,$2d,$98,$42,$00 ; 'r' + fcb $00,$1f,$0f,$07,$c0 ; 's' + fcb $42,$3c,$84,$24,$c0 ; 't' + fcb $00,$25,$29,$49,$a0 ; 'u' + fcb $00,$23,$18,$a8,$80 ; 'v' + fcb $00,$23,$5a,$d5,$40 ; 'w' + fcb $00,$22,$a2,$2a,$20 ; 'x' + fcb $00,$23,$19,$b4,$2e ; 'y' + fcb $00,$3e,$22,$23,$e0 ; 'z' + fcb $19,$08,$82,$10,$60 ; '{' + fcb $21,$08,$02,$10,$80 ; '|' + fcb $c1,$08,$22,$13,$00 ; '}' + fcb $45,$44,$00,$00,$00 ; '~' + fcb $ff,$ff,$ff,$ff,$ff ; 'cursor' + diff --git a/Kernel/platform-dragon-mooh/config.h b/Kernel/platform-dragon-mooh/config.h new file mode 100644 index 00000000..4eacb9a2 --- /dev/null +++ b/Kernel/platform-dragon-mooh/config.h @@ -0,0 +1,88 @@ +/* Enable to make ^Z dump the inode table for debug */ +#undef CONFIG_IDUMP +/* Enable to make ^A drop back into the monitor */ +#undef CONFIG_MONITOR +/* Profil syscall support (not yet complete) */ +#undef CONFIG_PROFIL +/* Multiple processes in memory at once */ +#define CONFIG_MULTI +/* Single tasking - for now while we get it booting */ +#undef CONFIG_SINGLETASK +/* Pure swap */ +#undef CONFIG_SWAP_ONLY + +#define CONFIG_BANK8 +#define PAGE_INVALID 0xFF /* soft value, the MOOH has no invalid value */ +#define PAGE_VIDEO 0xFF /* not used */ +#define MAX_MAPS 56 /* 64 - 8 for kernel */ +#define CONFIG_BANKS 8 +/* And swapping */ +#define SWAPDEV 2049 /* DriveWire drive 1 */ +#define SWAP_SIZE 0x6F /* 56K in 512 byte blocks - 1 */ +#define SWAPBASE 0x2000 /* We swap the lot, including stashed uarea */ +#define SWAPTOP 0xFE00 /* so it's a round number of 256 byte sectors */ +#define MAX_SWAPS 32 + +/* Permit large I/O requests to bypass cache and go direct to userspace */ +#define CONFIG_LARGE_IO_DIRECT + +/* Reclaim the discard space for buffers */ +#define CONFIG_DYNAMIC_BUFPOOL + +#define MAX_BLKDEV 3 /* 2 IDE drives + 1 SPI */ +#define SD_DRIVE_COUNT 1 /* Could be higher with multiple CS used */ +#define CONFIG_SD /* enable if SD interface present */ +#undef CONFIG_IDE /* enable if IDE interface present */ +#undef CONFIG_SCSI /* enable if SCSI interface present */ + +#define CONFIG_GPT + +/* Video terminal, not a serial tty */ +#define CONFIG_VT +#define CONFIG_VT_MULTI +#define CONFIG_FONT8X8 +/* Vt definitions */ +#define VT_RIGHT (vt_tright[curtty]) +#define VT_BOTTOM (vt_tbottom[curtty]) +#define VT_INITIAL_LINE 0 + +/* These overlap for now until we figure out properly moving VCs down */ +#define VT_ALLBASE 0x0800 /* Two 32x16 virtual consoles here */ +#define VIDEO_BASE 0x0800 /* 0x800 - 0x1FFF (6K) */ +#define map_video(x) +#define unmap_video(x) + +#define CRT9128_BASE 0xFF7C + +#define TICKSPERSEC 50 /* Ticks per second */ +/* FIXME: This will move once we put the display in the kernel bank and + sort the banker out */ +#define PROGBASE 0x2000 /* also data base */ +#define PROGLOAD 0x2000 /* also data base */ +#define PROGTOP 0xFC00 /* Top of program */ + +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + /* Temp FIXME set to serial port for debug ease */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 7 +#define NDEVS 2 /* Devices 0..NDEVS-1 are capable of being mounted */ + /* (add new mountable devices to beginning area.) */ +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 5 /* Number of block buffers at boot time */ +#define NMOUNTS 2 /* Number of mounts at a time */ +#define swap_map(x) ((uint8_t *)(x)) + +/* Drivewire Defines */ + +#define DW_VSER_NUM 1 /* No of Virtual Serial Ports */ +#define DW_VWIN_NUM 1 /* No of Virtual Window Ports */ +#define DW_MIN_OFF 6 /* Minor number offset = first DW ttyX */ + +/* Remember to update platform-dragon-nx32/kernel.defs to match */ + +extern void platform_discard(void); diff --git a/Kernel/platform-dragon-mooh/crt0.s b/Kernel/platform-dragon-mooh/crt0.s new file mode 100644 index 00000000..ef25832e --- /dev/null +++ b/Kernel/platform-dragon-mooh/crt0.s @@ -0,0 +1,76 @@ + ; exported + .globl start + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl kstack_top + .globl _system_id + + ; startup code + .area .start + +start: + ; we enter from bootloader with MMU disabled + orcc #0x10 ; interrupts definitely off + lds #kstack_top ; note we'll wipe the stack later + ldb $80FD ; save from ROM space + lda #4 ; MMU bank 4 = KBANKV + sta 0xFFA0 ; set up kernel lower bank + sta 0xFFA8 ; also for user task + ; other banks set by bootloader and DECB poking + lda #64+8 ; enable MMU with CRM on MOOH + sta 0xFF90 + ; use bank 0x3F instead of 3 at 0xE000 + ; lotsa point-less copying if only .vectors there... + lda #3 + sta 0xFFA6 ; bank 3 at 0xC000 + lda #0x3F + sta 0xFFA7 ; bank 0x3F in place + ldx #0xC000 ; copy from bank 3 + ldy #0xE000 +copyhb ldu ,x++ + stu ,y++ + cmpx #0xDF00 ; or __section* ? + blo copyhb + lda #2 + sta 0xFFA6 ; bank 2 at 0xC000 again + ; text and discard may be in memory bank 0 + jsr map_kernel + jmp premain + + .area .discard + +premain: clra + ldx #__sectionbase_.udata__ +udata_wipe: sta ,x+ + cmpx #__sectionbase_.udata__+__sectionlen_.udata__ + blo udata_wipe + ldx #__sectionbase_.bss__ + ldy #__sectionlen_.bss__ +bss_wipe: sta ,x+ + leay -1,y + bne bss_wipe + ; This might be in BSS so don't save until we've wiped! + lda #0 + cmpb #0x49 ; Dragon32 + beq identified + inca + cmpb #0x31 ; COCO1/2 + beq identified + inca + cmpb #0x32 ; COCO3 + beq identified + inca ; Beats me +identified: + sta _system_id ; what sort of a box are we ? + jsr init_early + jsr init_hardware + jmp main + + .area .text + +main jsr _fuzix_main + orcc #0x10 ; we should never get here +stop: bra stop diff --git a/Kernel/platform-dragon-mooh/discard.c b/Kernel/platform-dragon-mooh/discard.c new file mode 100644 index 00000000..22172866 --- /dev/null +++ b/Kernel/platform-dragon-mooh/discard.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + * Map handling: We have flexible paging. Each map table consists of a set of pages + * with the last page repeated to fill any holes. + */ + +extern uint8_t internal32k; + +void pagemap_init(void) +{ + int i; + + /* kernel uses 4 5 6 7 0 1 2 3F */ + for (i = 0x3e; i > 7; i--) + pagemap_add(i); + pagemap_add(3); /* was used while loading, replaced by 3F */ + +#ifdef SWAPDEV + for (i = 0; i < MAX_SWAPS; i++) + swapmap_init(i); +#endif +} + +uint8_t platform_param(char *p) +{ + return 0; +} + +static const char *sysname[] = {"Dragon", "COCO", "COCO3", "Unknown"}; + +struct cart_rom_id { + uint16_t hash; + uint8_t id; + const char *name; +}; + +static const char empty[] = "(empty)"; + +struct cart_rom_id carts[] = { + { 0x72B0, CART_DRAGONDOS, "DragonDOS" }, + { 0x9063, CART_DELTADOS, "DeltaDOS" }, + { 0xB400, 0, empty }, + { 0xC248, CART_RSDOS, "RS-DOS" }, + /* This one is an oddity - we need to do more to know what it drives + The great thing is we can extract the MMIO addresses from it */ + { 0xB61B, CART_HDBDOS, "HDBDOS" }, + { 0xCF55, CART_HDBDOS, "HDBDOS" }, + { 0xE1BA, CART_ORCH90, "Orchestra-90 CC" }, + { 0x0000, 0, "No ROM" } +}; + +struct hdb_rom_id { + char key[2]; + uint8_t id; + const char *name; +}; + +static struct hdb_rom_id hdb[] = { + { "ID", CART_IDE, "IDE-CHS" }, + { "LB", CART_IDE, "IDE-LBA" }, + { "TC", CART_TC3, "TC^3" }, + { "KE", CART_KENTON, "KENTON" }, + { "LR", CART_LRTECH, "LRTECH" }, + { "HD", CART_HDII, "HD-II" }, + { "4-", CART_4N1, "4-N-1" }, + { "DW", CART_DRIVEWIRE, "Drivewire" }, + { "BE", CART_BECKER, "Becker" }, + { "J&", CART_JMCP, "J&M CP" }, + {} +}; + +/* Find a cartridge or it's slot */ +int cart_find(int id) +{ + int i; + for (i = 0; i < id; i++) { + if (carttype[i] == id) + return i; + } + return -1; +} + +static struct cart_rom_id *cart_lookup(uint16_t hash) +{ + struct cart_rom_id *cart = carts; + do { + if (cart->hash == hash) + return cart; + } while(cart++->hash); + return NULL; +} + +static inline int keycmp(uint16_t *k1, uint16_t *k2) +{ + return (*k1 == *k2); +} + +static struct hdb_rom_id *hdb_lookup(uint16_t key) +{ + struct hdb_rom_id *id = hdb; + do { + if (keycmp(&key, (uint16_t *)id->key)) + return id; + } while(id++->id); + return NULL; +} + +void map_init(void) +{ + uint8_t i; + uint8_t bslot = 0; + uint16_t hash; + struct cart_rom_id *rom; + + kprintf("%s system.\n", sysname[system_id]); + if (mpi_present()) { + kputs("MPI cartridge detected.\n"); + cartslots = 4; + bootslot = mpi_set_slot(0); + bslot = bootslot & 3; + } + for (i = 0; i < cartslots; i++) { + mpi_set_slot((i << 4) | i); + hash = cart_hash(); + rom = cart_lookup(hash); + if (rom) { + kprintf("%d:%c%s", + i, i == bslot ? '*':' ', + rom->name); + carttype[i] = rom->id; + } + else + kprintf("%d:%cUnknown(%x)", + i, i == bslot ? '*':' ', hash); + + /* The analysis needs to be in asm as we need to page in + the ROM to peer at it */ + if (rom->id == CART_HDBDOS) { + uint16_t t = cart_analyze_hdb(); + struct hdb_rom_id *hdb = hdb_lookup(t); + if (hdb) { + kprintf(" %s ID %d", + hdb->name, hdb_id); + if (hdb->id == CART_IDE) + kprintf(" MMIO %x", hdb_port); + carttype[i] = hdb->id; + cartaddr[i] = hdb_port; + } else + kprintf("??%x\n", t); + } + kputchar('\n'); + } + mpi_set_slot(bootslot); +} diff --git a/Kernel/platform-dragon-mooh/dragon.s b/Kernel/platform-dragon-mooh/dragon.s new file mode 100644 index 00000000..1f3aa63c --- /dev/null +++ b/Kernel/platform-dragon-mooh/dragon.s @@ -0,0 +1,305 @@ + ; + ; MOOH platform + ; + + .module dragon_mooh + + ; exported + .globl _mpi_present + .globl _mpi_set_slot + .globl _cart_hash + .globl _cart_analyze_hdb + .globl _hdb_offset + .globl _hdb_id + .globl _hdb_port + .globl _hdb_timeout + .globl _bufpool + .globl _discard_size + + ; imported + .globl unix_syscall_entry + .globl fd_nmi_handler + .globl size_ram + .globl null_handler + .globl _vid256x192 + .globl _vtoutput + + ; exported debugging tools + .globl _platform_monitor + .globl _platform_reboot + .globl outchar + .globl ___hard_di + .globl ___hard_ei + .globl ___hard_irqrestore + + include "kernel.def" + include "../kernel09.def" + + + .area .vectors + ; + ; Will be at FFF0 once CRM is enabled + ; + .dw badswi_handler ; 6809 Reserved / 6309 Trap + .dw badswi_handler ; SWI3 + .dw badswi_handler ; SWI2 + .dw firq_handler ; FIRQ + .dw interrupt_handler ; IRQ + .dw unix_syscall_entry ; SWI + .dw fd_nmi_handler ; NMI + .dw badswi_handler ; Restart + + .area .buffers + ; + ; We use the linker to place these just below + ; the discard area + ; +_bufpool: + .ds BUFSIZE*NBUFS + + ; And expose the discard buffer count to C - but in discard + ; so we can blow it away and precomputed at link time + .area .discard +_discard_size: + .db __sectionlen_.discard__/BUFSIZE + +init_early: + ldx #null_handler + stx 1 + lda #0x7E + sta 0 + sta 0x0071 ; BASIC cold boot flag + rts + +init_hardware: + jsr size_ram + ; Turn on PIA CB1 (50Hz interrupt) + lda 0xFF03 + ora #1 + sta 0xFF03 + jsr _vid256x192 + jsr _vtinit + rts + + +; old p6809.s stuff below + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl _need_resched + + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl unix_syscall_entry + .globl fd_nmi_handler + + .area .common + +_platform_reboot: + orcc #0x10 + clr 0xFF90 ; disable MMU on MOOH + clr 0x0071 + jmp [0xFFFE] ; BASIC ROM & vectors are back + +_platform_monitor: + orcc #0x10 + bra _platform_monitor + +___hard_di: + tfr cc,b ; return the old irq state + orcc #0x10 + rts +___hard_ei: + andcc #0xef + rts + +___hard_irqrestore: ; B holds the data + tfr b,cc + rts + + +; +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + + .area .common + +; +; In the Dragon nx32 case our vectors live in a fixed block +; and is not banked out. +; +_program_vectors: + rts + + +; +; Helpers for the MPI and Cartridge Detect +; + + .area .text +; +; oldslot = mpi_set_slot(uint8_t newslot) +; +_mpi_set_slot: + tfr b,a + ldb 0xff7f + sta 0xff7f + rts +; +; int8_t mpi_present(void) +; +_mpi_present: + lda 0xff7f ; Save bits + tfr a,b + lsrb + lsrb + lsrb + lsrb + eorb 0xff7f + andb #0x03 ; We expect to see the bits 5-4 and 1-0 matching + bne nompi ; not guaranteed but a good rule of thumb for us + ldb #0xff ; Will get back 33 from an MPI cartridge + stb 0xff7f ; if the emulator is right on this + ldb 0xff7f + andb #0x33 + cmpb #0x33 + bne nompi + clr 0xff7f ; Switch to slot 0 + ldb 0xff7f + andb #0x33 ; We can't trust the high bits + bne nompi + incb + sta 0xff7f ; Our becker port for debug will be on the default + ; slot so put it back for now + rts ; B = 0 +nompi: ldb #0 + sta 0xff7f ; Restore bits just in case + rts + + +; this can be anywhere below 0xC000 + .area .ncart +; +; uint16_t cart_hash(void) +; +_cart_hash: + pshs cc + orcc #0x10 + ldx #0xC000 + lda #$3F + sta $FFA6 ; unmap kernel in cartridge area C000-DFFF + ldd #0 +hashl: + addd ,x++ + cmpx #0xC200 + bne hashl + tfr d,x + lda #2 + sta $FFA6 ; map kernel back + puls cc,pc + +_cart_analyze_hdb: + pshs cc + orcc #0x10 + lda #$3F + sta $FFA6 ; unmap kernel in cartridge area C000-DFFF + ldd 0xD93B ; I/O port + std _hdb_port + ldd 0xD93D ; Timeout and ID if SCSI + std _hdb_timeout + ; Shortly after that fixed block we will find the sign on and + ; copyright, which tell us what interface we are for. + ldx #0xD940 +hdb_s_next: + cmpx #0xE000 + beq no_sign ; No sign of the sign on ! + lda ,x+ + cmpa #'H' + bne hdb_s_next + lda ,x+ + cmpa #'D' ; This is safe as we know the bytes before + bne hdb_s_next ; our match are AUTOEXEC.BAS so won't partially + lda ,x+ ; match ! + cmpa #'B' + bne hdb_s_next + lda ,x+ + cmpa #'-' + bne hdb_s_next + ; + ; We have found the HDB-. X now points at the D of DOS + ; + leax 6,x ; Skip version + ; + ; We now have to find a space + ; +hdb_s_spc: + cmpx #0xE000 + beq no_sign + lda ,x+ + cmpa #0x20 + bne hdb_s_spc + ; + ; This is followed by a string. For those we care about the first + ; letters are sufficient to tell them apart + ; + ; LB : IDE LBA + ; ID : IDE CHS + ; TC : TC^3 SCSI + ; KE : Kenton + ; LR : LR Tech + ; HD : HD-II + ; 4- : 4-N-1 + ; DW : Drivewire stuff } Need more identification but are not + ; BE : Becker ports } interesting to us anyway + ; J& : J&M CP + ldx ,x +ret1: + lda #2 + sta $FFA6 ; map kernel back + puls cc,pc +no_sign: + ldx #-1 + bra ret1 + +; Need to be here so they can be written with cart paged in + .area .ncartdata + +_hdb_port: + .dw 0 +_hdb_timeout: + .db 0 +_hdb_id: + .db 0 +_hdb_type: + .db 0 + + + .area .common + +; +; FIXME: +; +firq_handler: +badswi_handler: + rti + +; +; debug via printer port +; +outchar: + sta 0xFF02 + lda 0xFF20 + ora #0x02 + sta 0xFF20 + anda #0xFD + sta 0xFF20 + rts + + .area .commondata + +_need_resched: .db 0 diff --git a/Kernel/platform-dragon-mooh/fuzix.link b/Kernel/platform-dragon-mooh/fuzix.link new file mode 100644 index 00000000..7426ef77 --- /dev/null +++ b/Kernel/platform-dragon-mooh/fuzix.link @@ -0,0 +1,23 @@ +define basesympat __sectionbase_%s__ +define lensympat __sectionlen_%s__ +# NUL pointer trap at 0x0000 +section .commondata load 0x0010 +section .ncartdata +section .udata load 0x0500 +# video memory overlaps 0x0800-0x1fff (6KB) +section .common load 0x0800 +# ncart must be below 0xc000 +section .ncart load 0x2000 +section .start +section .text +section .text2 +section .buffers +section .discard +section .data +# video code/data must be above 0x2000 +section .videodata +section .video +section .bss +section .crm load 0xfe00 +section .vectors load 0xfef0 +entry start diff --git a/Kernel/platform-dragon-mooh/kernel.def b/Kernel/platform-dragon-mooh/kernel.def new file mode 100644 index 00000000..1a1c6adb --- /dev/null +++ b/Kernel/platform-dragon-mooh/kernel.def @@ -0,0 +1,25 @@ +; UZI mnemonics for memory addresses etc + +U_DATA equ 0x0500 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE equ 0x200 ; 256+256 (we don't save istack) + +U_DATA_STASH equ 0xFC00 ; FC00-FDFF + +VIDEO_BASE equ 0x0800 ; 6K for the display +VIDEO_END equ 0x2000 +KBANKV equ 0x4 ; Kernel bank overlapping video memory + +IDEDATA equ 0xFF50 +IDEDATA_L equ 0xFF58 + +SPIDATA equ 0xFF6C +SPISTATUS equ SPIDATA+1 +SPICTRL equ SPISTATUS +SPICLK equ SPICTRL+1 +SPISIE equ SPICLK+1 + +SPICS equ 0x01 ; hardcode SEL0 for now + +PROGBASE equ 0x2000 ; programs and data start here + +NBUFS equ 5 diff --git a/Kernel/platform-dragon-mooh/mem-mooh.s b/Kernel/platform-dragon-mooh/mem-mooh.s new file mode 100644 index 00000000..9c158c94 --- /dev/null +++ b/Kernel/platform-dragon-mooh/mem-mooh.s @@ -0,0 +1,136 @@ +; +; Flexible 8K banks on external MOOH memory cartridge +; +; Copyright 2015-2018 Tormod Volden +; + + .module mem_mooh + + ; exported + .globl reloc + .globl size_ram + .globl map_kernel + .globl map_process_a + .globl map_process_always + .globl map_save + .globl map_restore + .globl copybank + + ; imported + .globl _ramsize + .globl _procmem + .globl _membanks + .globl _internal32k + .globl start + +; mmuctl equ 0xFF90 +; mmuen equ 0x40 +; crmen equ 0x08 +; mmutask equ 0xFF91 + + include "kernel.def" + include "../kernel09.def" + + .area .discard + +; Sets ramsize, procmem, membanks +size_ram + ; we know what we should have + lda #56 + sta _membanks ; not really used anywhere + ldd #512 + std _ramsize ; in KB + ldd #512-64 + std _procmem ; minus 64KB for kernel + rts + + .area .common + +; must preserve register a but not x +map_kernel + clr map_copy + clr map_copy+1 + clr 0xff91 ; MMU task 0 + rts + +map_process_a + pshs a,b,x,y + bra map_x + +map_process_always + pshs a,b,x,y + ldx U_DATA__U_PAGE +map_x + ; could try to skip this if maps already in place + stx map_copy + ldy #0xFFA9 + ldb #7 +maplp lda ,x+ + bmi fillm ; PAGE_INVALID (0xFF) means we are done + sta ,y+ + decb + bne maplp +mapdn lda #1 + sta 0xff91 ; MMU task 1 + puls a,b,x,y,pc +fillm lda -2,x ; should not happen on first page +fillp sta ,y+ ; fill map by repeating last page + decb + bne fillp + bra mapdn + +map_save + pshs x + ldx map_copy + stx map_store + puls x,pc + +map_restore + pshs x + ldx map_store + bne usr + jsr map_kernel + puls x,pc +usr jsr map_process_a + puls x,pc + + +; fast bank copy for fork (called with kernel mapped) +; src bank in A, dst bank in B + +; we simply copy the full 8KB bank here + +copybank + pshs x,y,u + ldy 0xFFA4 ; save the two MMU regs + sta 0xFFA5 ; map src at 0xA000 (task 0, kernel mapped) + stb 0xFFA4 ; map dst at 0x8000 + ldu #0xA000 + ldx #0x8000 + +copylp ldd ,u++ ; read from src bank + std ,x++ ; write to dst bank + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + ldd ,u++ + std ,x++ + cmpx #0xA000 + blo copylp + + sty 0xFFA4 ; restore MMU regs + puls x,y,u,pc + + .area .commondata + +map_store .dw 0 +map_copy .dw 0 diff --git a/Kernel/platform-dragon-mooh/multihead.s b/Kernel/platform-dragon-mooh/multihead.s new file mode 100644 index 00000000..4acf8b81 --- /dev/null +++ b/Kernel/platform-dragon-mooh/multihead.s @@ -0,0 +1,124 @@ +; +; dispatches vt calls to different screen routines +; + + .module multihead + + .globl _set_vid_mode + .globl _set_vc_mode + + .area .videodata + + .globl _curtty +_curtty .db 0 + + .area .video + + .globl _clear_across +_clear_across: + lda _curtty + lbeq _m6847_clear_across + deca + lbeq _crt9128_clear_across + jmp _vc_clear_across + + .globl _clear_lines +_clear_lines: + lda _curtty + lbeq _m6847_clear_lines + deca + lbeq _crt9128_clear_lines + jmp _vc_clear_lines + + .globl _scroll_up +_scroll_up: + lda _curtty + lbeq _m6847_scroll_up + deca + lbeq _crt9128_scroll_up + jmp _vc_scroll_up + + .globl _scroll_down +_scroll_down: + lda _curtty + lbeq _m6847_scroll_down + deca + lbeq _crt9128_scroll_down + jmp _vc_scroll_down + + .globl _plot_char +_plot_char: + lda _curtty + lbeq _m6847_plot_char + deca + lbeq _crt9128_plot_char + jmp _vc_plot_char + + .globl _cursor_off +_cursor_off: + lda _curtty + lbeq _m6847_cursor_off + deca + lbeq _crt9128_cursor_off + jmp _vc_cursor_off + + .globl _cursor_on +_cursor_on: + lda _curtty + lbeq _m6847_cursor_on + deca + lbeq _crt9128_cursor_on + jmp _vc_cursor_on + + .globl _cursor_disable +_cursor_disable: + rts + + .globl _vtattr_notify +_vtattr_notify: + lda _curtty + lbeq _m6847_vtattr_notify + deca + lbeq _crt9128_vtattr_notify + jmp _vc_vtattr_notify + + .globl _video_cmd +_video_cmd: + tst _curtty + lbeq _m6847_video_cmd + rts + + .globl _video_read +_video_read: + tst _curtty + lbeq _m6847_video_read + rts + + .globl _video_write +_video_write: + tst _curtty + lbeq _m6847_video_write + rts + +_set_vc_mode: + ldx #$ffc6 + sta -4,x ; reset V1 $ffc2 + sta -2,x ; reset V2 $ffc4 ; set resolution + + ; set video base 0x0800 = 0x200 * 0b100 + sta b,x ; set/reset bit F0 for b = 0 or 1 + sta 2+0,x ; reset F1 + sta 4+1,x ; set F2 + + lda $ff22 + anda #$07 + sta $ff22 ; set PIA for VDG + rts + +_set_vid_mode: + ; video base 0x0800 = 0x200 * 0b100 + sta $ffc6+0 ; reset F0 + sta $ffc8+0 ; reset F1 + sta $ffca+1 ; set F2 + jmp _vid256x192 + diff --git a/Kernel/platform-dragon-mooh/rules.mk b/Kernel/platform-dragon-mooh/rules.mk new file mode 100644 index 00000000..39f80b06 --- /dev/null +++ b/Kernel/platform-dragon-mooh/rules.mk @@ -0,0 +1,5 @@ + +CROSS_CCOPTS += -Iplatform-dragon-nx32/ + +vt.o: vt.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_VIDEO) $< diff --git a/Kernel/platform-dragon-mooh/target.mk b/Kernel/platform-dragon-mooh/target.mk new file mode 100644 index 00000000..6f5e1df5 --- /dev/null +++ b/Kernel/platform-dragon-mooh/target.mk @@ -0,0 +1,3 @@ +export CPU = 6809 +export CROSS_CC_FONT = -mcode-section=.video +vpath %.s platform-dragon-mooh diff --git a/Kernel/platform-dragon-mooh/tricks.s b/Kernel/platform-dragon-mooh/tricks.s new file mode 100644 index 00000000..dacc4a1d --- /dev/null +++ b/Kernel/platform-dragon-mooh/tricks.s @@ -0,0 +1,233 @@ +; +; 6809 version +; + .module tricks + + #imported + .globl _newproc + .globl _chksigs + .globl _getproc + .globl _platform_monitor + .globl _inint + .globl map_kernel + .globl map_process_a + .globl map_process_always + .globl copybank + .globl _nready + .globl _platform_idle + + # exported + .globl _platform_switchout + .globl _switchin + .globl _dofork + .globl _ramtop + + include "kernel.def" + include "../kernel09.def" + + .area .commondata + + ; ramtop must be in common although not used here +_ramtop: + .dw 0 + +newpp .dw 0 + + .area .common + +; Switchout switches out the current process, finds another that is READY, +; possibly the same process, and switches it in. When a process is +; restarted after calling switchout, it thinks it has just returned +; from switchout(). +; +_platform_switchout: + orcc #0x10 ; irq off + + ; save machine state, including Y and U used by our C code + ldd #0 ; return code set here is ignored, but _switchin can + ; return from either _switchout OR _dofork, so they must both write + ; U_DATA__U_SP with the following on the stack: + pshs d,y,u + sts U_DATA__U_SP ; this is where the SP is restored in _switchin + + ; Stash the uarea into process memory bank + ; FIXME could map in only the bank that holds the stash + jsr map_process_always + + ldx #U_DATA + ldy #U_DATA_STASH +stash: ldd ,x++ + std ,y++ + cmpx #U_DATA+U_DATA__TOTALSIZE + bne stash + + ; get process table in + jsr map_kernel + + ; find another (or same) process to run, returned in X + jsr _getproc + jsr _switchin + ; we should never get here + jsr _platform_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .db 13 + .db 10 + .db 0 + + +; new process pointer is in X +_switchin: + orcc #0x10 ; irq off + + stx newpp + ; get process table + ldx P_TAB__P_PAGE_OFFSET,x ; process map pointer + + ; check if we are switching to the same process + cmpx U_DATA__U_PAGE + beq nostash + + ; process was swapped out? + cmpx #0 + bne not_swapped + jsr _swapper ; void swapper(ptptr p) + ldx newpp + ldx P_TAB__P_PAGE_OFFSET,x + +not_swapped: + jsr map_process_a + + ; fetch uarea from process memory + ldx #U_DATA_STASH + ldy #U_DATA +stashb ldd ,x++ + std ,y++ + cmpx #U_DATA_STASH+U_DATA__TOTALSIZE + bne stashb + + ; we have now new stacks so get new stack pointer before any jsr + lds U_DATA__U_SP + + ; get back kernel page so that we see process table + jsr map_kernel + +nostash: + ldx newpp + ; check u_data->u_ptab matches what we wanted + cmpx U_DATA__U_PTAB + bne switchinfail + + lda #P_RUNNING + sta P_TAB__P_STATUS_OFFSET,x + + ; fix any moved page pointers + ldx P_TAB__P_PAGE_OFFSET,x + stx U_DATA__U_PAGE + + ldx #0 + stx _runticks + + ; restore machine state -- note we may be returning from either + ; _switchout or _dofork + lds U_DATA__U_SP + puls x,y,u ; return code and saved U and Y + + ; enable interrupts, if the ISR isn't already running + lda U_DATA__U_ININTERRUPT + bne swtchdone ; in ISR, leave interrupts off + andcc #0xef +swtchdone: + rts + +switchinfail: + jsr outx + ldx #badswitchmsg + jsr outstring + ; something went wrong and we didn't switch in what we asked for + jmp _platform_monitor + + .area .data + +fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + + .area .common +; +; Called from _fork. We are in a syscall, the uarea is live as the +; parent uarea. The kernel is the mapped object. +; +_dofork: + ; always disconnect the vehicle battery before performing maintenance + orcc #0x10 ; should already be the case ... belt and braces. + + ; new process in X, get parent pid into X + + stx fork_proc_ptr + ldx P_TAB__P_PID_OFFSET,x + + ; Save the stack pointer and critical registers (Y and U used by C). + ; When this process (the parent) is switched back in, it will be as if + ; it returns with the value of the child's pid. + pshs x,y,u ; x has p->p_pid from above, the return value in the parent + + ; save kernel stack pointer -- when it comes back in the parent we'll be in + ; _switchin which will immediately return (appearing to be _dofork() + ; returning) and with X (ie return code) containing the child PID. + ; Hurray. + sts U_DATA__U_SP + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + jsr fork_copy ; copy process memory to new bank + ; and save parents uarea + + ; We are now in the kernel child context + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + puls x + + ldx fork_proc_ptr + jsr _newproc + + ; any calls to map process will now map the childs memory + + ; in the child process, fork() returns zero. + ldx #0 + ; runticks = 0; + stx _runticks + ; + ; And we exit, with the kernel mapped, the child now being deemed + ; to be the live uarea. The parent is frozen in time and space as + ; if it had done a switchout(). + puls y,u,pc + +fork_copy: +; copy the process memory to the new banks and stash parent uarea to old banks + lda #7 + pshs a ; counter + ldx fork_proc_ptr + ldx P_TAB__P_PAGE_OFFSET,x ; new bank map + ldy U_DATA__U_PAGE ; old bank map +cpbank lda ,y+ ; src + bmi dnbank ; PAGE_INVALID means we are done + ldb ,x+ ; dst + jsr copybank ; clobbers only A,B + dec ,s + bne cpbank +dnbank puls a + +; stash parent uarea (including kernel stack) + ldx U_DATA__U_PAGE ; old bank + jsr map_process_a + ldx #U_DATA + ldu #U_DATA_STASH +stashf ldd ,x++ + std ,u++ + cmpx #U_DATA+U_DATA__TOTALSIZE + bne stashf + jsr map_kernel + ; --- we are now on the stack copy, parent stack is locked away --- + rts ; this stack is copied so safe to return on + diff --git a/Kernel/platform-dragon-mooh/usermem_sam.s b/Kernel/platform-dragon-mooh/usermem_sam.s new file mode 100644 index 00000000..904c5d98 --- /dev/null +++ b/Kernel/platform-dragon-mooh/usermem_sam.s @@ -0,0 +1,128 @@ + .module usermem + +; +; 6809 copy to and from userspace +; +; This is lightly optimised for the dragon-mooh platform +; using MMU task switching + + + include "kernel.def" + include "../kernel09.def" + + ; exported + .globl __ugetc + .globl __ugetw + .globl __uget + + .globl __uputc + .globl __uputw + .globl __uput + .globl __uzero + + ; imported + .globl map_process_always + .globl map_kernel + + .area .common + +__ugetc: + pshs cc ; save IRQ state + orcc #0x10 + jsr map_process_always + ldb ,x + jsr map_kernel + clra + tfr d,x + puls cc,pc ; back and return + +__ugetw: + pshs cc + orcc #0x10 + jsr map_process_always + ldx ,x + jsr map_kernel + puls cc,pc + +__uget: + pshs u,y,cc + ldu 7,s ; user address + ldy 9,s ; count + orcc #0x10 + ldb #1 + jsr map_process_always ; make sure user task regs are set up +ugetl: + stb 0xff91 + lda ,x+ + clr 0xff91 + sta ,u+ + leay -1,y + bne ugetl + jsr map_kernel ; make sure map_copy is up to date + ldx #0 + puls u,y,cc,pc + +__uputc: + pshs cc + orcc #0x10 + ldd 3,s + jsr map_process_always + exg d,x + stb ,x + jsr map_kernel + ldx #0 + puls cc,pc + +__uputw: + pshs cc + orcc #0x10 + ldd 3,s + jsr map_process_always + exg d,x + std ,x + jsr map_kernel + ldx #0 + puls cc,pc + +; X = source, user, size on stack +__uput: + pshs u,y,cc + orcc #0x10 + ldu 7,s ; user address + ldy 9,s ; count + ldb #1 + jsr map_process_always ; make sure user task regs are set up + clr 0xff91 +uputl: + lda ,x+ + stb 0xff91 + sta ,u+ + clr 0xff91 + leay -1,y + bne uputl + jsr map_kernel ; make sure map_copy is up to date + ldx #0 + puls u,y,cc,pc + +__uzero: + pshs y,cc + ldy 5,s + orcc #0x10 + jsr map_process_always + tfr y,d + clra + lsrb ; odd count? + bcc evenc + sta ,x+ + leay -1,y + beq zdone +evenc: + clrb +uzloop: + std ,x++ + leay -2,y + bne uzloop +zdone: + jsr map_kernel + ldx #0 + puls y,cc,pc diff --git a/Kernel/platform-dragon-mooh/video.s b/Kernel/platform-dragon-mooh/video.s new file mode 100644 index 00000000..487985b0 --- /dev/null +++ b/Kernel/platform-dragon-mooh/video.s @@ -0,0 +1,481 @@ + .module dragonvideo + + ; Methods provided + .globl _map_video + .globl _unmap_video + .globl _vid256x192 + .globl _m6847_plot_char + .globl _m6847_scroll_up + .globl _m6847_scroll_down + .globl _m6847_clear_across + .globl _m6847_clear_lines + .globl _m6847_cursor_on + .globl _m6847_cursor_off + .globl _m6847_cursor_disable + .globl _m6847_vtattr_notify + + .globl _m6847_video_read + .globl _m6847_video_write + .globl _m6847_video_cmd + + ; + ; Imports + ; + .globl _fontdata_8x8 + .globl _vidattr + + include "kernel.def" + include "../kernel09.def" + + .area .video + +; These are not used yet. +; When we unmap the common page to work on the video below, whatever +; has been written there (kstack in particular) can still be read +; but if anything is written it will be lost once we remap the common. +_map_video: + tfr cc,a + sta cc_video + orcc #$10 ; disable interrupt while video is mapped + lda #$3F ; since common disappears + sta $FFA0 ; unmap kernel above video memory + rts ; return address bled through + +_unmap_video: + ldx ,s ; save return address written to video + lda #KBANKV + sta $FFA0 ; remap kernel + stx ,s ; rewrite return address + lda cc_video + tfr a,cc + rts + +; +; Dragon video drivers +; +; SAM V2=1 V1=1 V0=- +; 6847 A/G=1 GM2=1 GM1=1 GM0=1 +; +_vid256x192: + sta $ffc0 + sta $ffc3 + sta $ffc5 + lda $ff22 + anda #$07 + ora #$f0 + sta $ff22 + ; shift VDU scanout to 0x0800 = VIDEO_START + sta $ffc8+0 + sta $ffca+1 + rts + +; +; Compute the video base address +; A = X, B = Y +; +vidaddr: + ldy #VIDEO_BASE + exg a,b + leay d,y ; 256 x Y + X + rts +; +; plot_char(int8_t y, int8_t x, uint16_t c) +; +_m6847_plot_char: + pshs y + lda #$3F + sta $FFA0 ; unmap kernel above video memory + lda 4,s + bsr vidaddr ; preserves X (holding the char) + tfr x,d + rolb ; multiply by 8 + rola + rolb + rola + rolb + rola + tfr d,x + leax _fontdata_8x8,x ; relative to font + ldb _vtattr + andb #0x3F ; drop the bits that don't affect our video + beq plot_fast + + ; + ; General purpose plot with attributes, we only fastpath + ; the simple case + ; + clra +plot_loop: + sta _vtrow + ldb _vtattr + cmpa #7 ; Underline only applies on the bottom row + beq ul_this + andb #0xFD +ul_this: + cmpa #3 ; italic shift right for < 3 + blt ital_1 + andb #0xFB + bra maskdone +ital_1: + cmpa #5 ; italic shift right for >= 5 + blt maskdone + bitb #0x04 + bne maskdone + orb #0x40 ; spare bit borrow for bottom of italic + andb #0xFB +maskdone: + lda ,x+ ; now throw the row away for a bit + bitb #0x10 + bne notbold + lsra + ora -1,x ; shift and or to make it bold +notbold: + bitb #0x04 ; italic by shifting top and bottom + beq notital1 + lsra +notital1: + bitb #0x40 + beq notital2 + lsla +notital2: + bitb #0x02 + beq notuline + lda #0xff ; underline by setting bottom row +notuline: + bitb #0x01 ; inverse or not: we are really in inverse + bne plot_inv ; by default so we complement except if + coma ; inverted +plot_inv: + bitb #0x20 ; overstrike or plot ? + bne overstrike + sta ,y + bra plotnext +overstrike: + anda ,y + sta ,y +plotnext: + leay 32,y + lda _vtrow + inca + cmpa #8 + bne plot_loop + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc +; +; Fast path for normal attributes +; +plot_fast: + lda ,x+ ; simple 8x8 renderer for now + coma + sta 0,y + lda ,x+ + coma + sta 32,y + lda ,x+ + coma + sta 64,y + lda ,x+ + coma + sta 96,y + lda ,x+ + coma + sta 128,y + lda ,x+ + coma + sta 160,y + lda ,x+ + coma + sta 192,y + lda ,x+ + coma + sta 224,y + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc + +; +; void scroll_up(void) +; +_m6847_scroll_up: + pshs y + lda #$3F + sta $FFA0 ; unmap kernel above video memory + ldy #VIDEO_BASE + leax 256,y +vscrolln: + ; Unrolled line by line copy + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + ldd ,x++ + std ,y++ + cmpx #VIDEO_END + bne vscrolln + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc + +; +; void scroll_down(void) +; +_m6847_scroll_down: + pshs y + lda #$3F + sta $FFA0 ; unmap kernel above video memory + ldy #VIDEO_END + leax -256,y +vscrolld: + ; Unrolled line by line loop + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + ldd ,--x + std ,--y + cmpx #VIDEO_BASE + bne vscrolld + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc + +; +; clear_across(int8_t y, int8_t x, uint16_t l) +; +_m6847_clear_across: + pshs y + lda #$3F + sta $FFA0 ; unmap kernel above video memory + lda 4,s ; x into A, B already has y + jsr vidaddr ; Y now holds the address + tfr x,d ; Shuffle so we are writng to X and the counter + tfr y,x ; l is in d + lda #$ff +clearnext: + sta ,x + sta 32,x + sta 64,x + sta 96,x + sta 128,x + sta 160,x + sta 192,x + sta 224,x + leax 1,x + decb + bne clearnext + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc +; +; clear_lines(int8_t y, int8_t ct) +; +_m6847_clear_lines: + pshs y + lda #$3F + sta $FFA0 ; unmap kernel above video memory + clra ; b holds Y pos already + jsr vidaddr ; y now holds ptr to line start + tfr y,x + ldd #$ffff + lsl 4,s + lsl 4,s + lsl 4,s +wipel: + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + std ,x++ + dec 4,s ; count of lines + bne wipel + lda #KBANKV + sta $FFA0 ; remap kernel + puls y,pc + +_m6847_cursor_on: + pshs y + lda 4,s + jsr vidaddr + tfr y,x + puls y + stx cursor_save + ; Fall through +_m6847_cursor_off: + lda #$3F + sta $FFA0 ; unmap kernel above video memory + ldb _vtattr + bitb #0x80 + bne nocursor + ldx cursor_save + com ,x + com 32,x + com 64,x + com 96,x + com 128,x + com 160,x + com 192,x + com 224,x + lda #KBANKV + sta $FFA0 ; remap kernel +nocursor: +_m6847_cursor_disable: +_m6847_vtattr_notify: + rts +; +; These routines work in both 256x192x2 and 128x192x4 modes +; because everything in the X plane is byte-wide. +; +_m6847_video_write: + clra ; clr C + bra tfr_cmd +_m6847_video_read: + coma ; set C + bra tfr_cmd ; go + +;;; This does the job of READ & WRITE +;;; takes: C = direction 0=write, 1=read +;;; takes: X = transfer buffer ptr + 2 +tfr_cmd: + pshs u,y ; save regs + orcc #$10 ; turn off interrupt - int might remap kernel + lda #$3F + sta $FFA0 ; unmap kernel above video memory + ldd #$80c0 ; this is writing + bcc c@ ; if carry clear then keep D write + exg a,b ; else flip D: now is reading +c@ sta b@+1 ; !!! self modify inner loop + stb b@+3 ; !!! + bsr vidptr ; U = screen addr + tfr x,y ; Y = ptr to Height, width + leax 4,x ; X = pixel data + ;; outter loop: iterate over pixel rows +a@ lda 3,y ; count = width + pshs u ; save screen ptr + ;; inner loop: iterate over columns + ;; modify mod+1 and mod+3 to switch directions +b@ ldb ,x+ ; get a byte from src + stb ,u+ ; save byte to dest + deca ; bump counter + bne b@ ; loop + ;; increment outer loop + puls u ; restore original screen ptr + leau 32,u ; add byte span of screen (goto next line) + dec 1,y ; bump row counter + bne a@ ; loop + lda #KBANKV + sta $FFA0 ; remap kernel + puls u,y,pc ; restore regs, return + + +; +; Find the address we need on a pixel row basis +; +vidptr: + ldu #VIDEO_BASE + ldd ,x++ ; Y into B + lda #32 + mul + leau d,u + ldd ,x++ ; X + leau d,u + rts + +_m6847_video_cmd: + pshs u + lda #$3F + sta $FFA0 ; unmap kernel above video memory + bsr vidptr ; u now points to the screen +nextline: + pshs u ; save it for the next line +nextop: + ldb ,x+ ; op code, 0 = end of line + beq endline +oploop: + lda ,u ; do one screen byte + anda ,x + eora 1,x + sta ,u+ + decb + bne oploop ; keep going for run + leax 2,x + bra nextop ; next triplet +endline: + puls u ; get position back + leau 32,u ; down one scan line + ldb ,x+ ; get next op - 0,0 means end and done + bne oploop + lda #KBANKV + sta $FFA0 ; remap kernel + puls u,pc + + .area .videodata +cursor_save: + .dw 0 +_vtrow: + .db 0 +cc_video: + .db 0 -- 2.34.1