format to load the kernel to RAM and pass control to it at its start address
(which is encoded into the DECB file).
+The emulator is started like this:
+./m6809-run -s multicomp09 -b ../6809M.bin -I 240000 -m 100000000
*************************
KEYBOARD
*************************
node major minor description
-/dev/tty1 2 1 console
-/dev/tty2 2 2 RS232 port
+/dev/tty1 2 1 VGA/PS2 console <-+-- swappable by VDUFFD0
+/dev/tty2 2 2 RS232 port <-+ jumper
/dev/tty3 2 3 USB virtual RS232 port
/dev/tty4 2 4 Drivewire Virtual Window #0 (coming soon..)
/dev/dw? 8 0-256 Drivewire Block Drives (coming soon..)
-void devsd_read( char *addr );
-void devsd_write( char *addr );
+void devsd_read( void *addr );
+void devsd_write( void *addr );
#undef DEBUG /* UNdefine to delete debug code sequences */
#undef MC09_VIRTUAL_IN
+/* Hardware Registers */
+#define TIMER (0xffdd)
+#define timer_reg *((volatile uint8_t *)TIMER)
+
/* Multicomp has 3 serial ports. Each is a cut-down 6850, with fixed BAUD rate and word size.
Port 0 is, by default, a virtual UART interface to a VGA output and PS/2 keyboard
Port 0 is used for tty1, Port 1 for tty2.
*/
static uint8_t *uart[] = {
- 0, 0, /* Unused */
- (volatile uint8_t *)0xFFD1, (volatile uint8_t *)0xFFD0, /* Virtual UART Data, Status port0, tty1 */
- (volatile uint8_t *)0xFFD3, (volatile uint8_t *)0xFFD2, /* UART Data, Status port1, tty2 */
- (volatile uint8_t *)0xFFD5, (volatile uint8_t *)0xFFD4, /* UART Data, Status port2, tty3 */
+ 0, 0, /* Unused */
+ (uint8_t *)0xFFD1, (uint8_t *)0xFFD0, /* Virtual UART Data, Status port0, tty1 */
+ (uint8_t *)0xFFD3, (uint8_t *)0xFFD2, /* UART Data, Status port1, tty2 */
+ (uint8_t *)0xFFD5, (uint8_t *)0xFFD4, /* UART Data, Status port2, tty3 */
};
#ifdef MC09_VIRTUAL_IN
static int imatch = 100;
/* X represents a pause at end-of-line*/
/* Without pauses, the input streams ahead of the output */
-static uint8_t input[] = "ls -al\nXpwd\nXps\nX\x04root\nXtime ls\nX\nfforth /usr/src/fforth/fforth_tests.fth\nX";
+/*static uint8_t input[] = "ls -al\nXpwd\nXps\nX\x04root\nXtime ls\nX\nfforth /usr/src/fforth/fforth_tests.fth\nX"; */
+static uint8_t input[] = "ls -al\nXpwd\nX";
static int ccount = 0;
#endif
-
/* A wrapper for tty_close that closes the DW port properly */
int my_tty_close(uint8_t minor)
{
/* Output for the system console (kprintf etc) */
void kputchar(char c)
{
- if (c == '\n')
- tty_putc(minor(TTYDEV), '\r');
- tty_putc(minor(TTYDEV), c);
+ uint8_t minor = minor(TTYDEV);
+
+ while ((*(uart[minor*2 + 1]) & 2) != 2) {
+ /* UART is busy */
+ }
+
+ /* convert from CR to CRLF */
+ if (c == '\n') {
+ tty_putc(minor, '\r');
+ while ((*(uart[minor*2 + 1]) & 2) != 2) {
+ /* UART is busy */
+ }
+ }
+
+ tty_putc(minor, c);
}
ttyready_t tty_writeready(uint8_t minor)
{
uint8_t c;
if ((minor < 1) || (minor > 3)) {
- return TTY_READY_NOW;
+ return TTY_READY_NOW;
}
c = *(uart[minor*2 + 1]); /* 2 entries per UART, +1 to get STATUS */
return (c & 2) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */
if (c & 0x01) { tty_inproc(3, *(uart[3*2])); } */
#endif
- /* [NAC HACK 2016May07] need defines for the timer */
- c = *((volatile uint8_t *)0xFFDD);
+ c = timer_reg;
if (c & 0x80) {
- *((volatile uint8_t *)0xFFDD) = c; /* service the hardware */
- /* tell the OS it happened */
- timer_interrupt();
+ timer_reg = c; /* service the hardware */
+ timer_interrupt(); /* tell the OS it happened */
}
// dw_vpoll();
;;; $ffb0 video colour
;;; coco3 MMU
-;;; accessed through registers $ff91 and $ffa0-$ffa7
+;;; accessed through registers $ff91 and $ffa0-$ffaf
;;; 2 possible memory maps: map0, map1 selected by $ff91[0]
-;;; map0 is used for Kernel mode, map1 is used for User mode.
+;;; map0 is used for User mode, map1 is used for Kernel mode.
;;; map1 is selected at boot (ie, now).
;;; when 0, select map0 using pages stored in $ffa0-$ffa7
;;; when 1, select map1 using pages stored in $ffa8-$ffaf
;;; multicomp09 MMU
;;; accessed through two WRITE-ONLY registers MMUADR, MMUDAT
;;; 2 possible memory maps: map0, map1 selected by MMUADR[6]
-;;; map0 is used for Kernel mode, map1 is used for User mode.
+;;; map0 is used for User mode, map1 is used for Kernel mode.
;;; map0 is selected at boot (ie, now)
-;;; [NAC HACK 2016Apr23] to avoid pointless divergence from
-;;; coco3, the first hardware setup step will be to flip to
-;;; map1.
+;;; .. to avoid pointless divergence from coco3, the first
+;;; hardware setup step will be to flip to map1.
;;; [NAC HACK 2016Apr23] in the future, may handle this in
;;; forth or in the bootstrap
;;; when 0, select map0 using MAPSEL values 0-7
;;; The values of 0-7 set here for _usr_mmu_map reflect how the user mappings
;;; are set up when the kernel is started - so don't change them either!
_krn_mmu_map
- .db 0,1,2,3,4,5,6,7
+ .db 0,1,2,3,4,5,6,7 ; mmu registers 8-f
_usr_mmu_map
- .db 0,1,2,3,4,5,6,7
+ .db 0,1,2,3,4,5,6,7 ; mmu registers 0-7
_trap_monitor:
ldy #MMUADR
;; setup the null pointer / sentinal bytes in low process memory
- lda #(MMU_MAP1|8) ; stay in MAP1, select block 8
+ lda curr_tr ; Select MMU register associated with
+ ora #8 ; block 8
sta ,y
lda ,x ; get process's blk address for address 0
sta 0
;; restore the MMU mapping that we trampled on
- ;; MMUADR still has MAP1, block 8 so no need to re-write it.
+ ;; MMUADR still has block 8 selected so no need to re-write it.
- ;; retrieve value that used to be in MAP1, block 8
+ ;; retrieve value that used to be in block 8
lda _krn_mmu_map
;; and restore it
sta 1,y ; MMUDAT
;;;
;;; CoCo3 ghoulish tricks (boo!) ported to multicomp09
;;;
-
.module tricks
;; imported
stx _swapstack ; save passed page table *
;;; [NAC HACK 2016May03] this is only flipping in top 8K .. as is coco3.
- lda curr_tr ; [NAC HACK 2016May07] I assume we're running in krn but
- ; I'm not 100% sure..
+ lda curr_tr ; Select MMU register associated with
ora #7 ; top 8K of usr map
sta MMUADR
sta MMUDAT
sta _usr_mmu_map+7 ; keep the mirror in sync.
- lda curr_tr ; [NAC HACK 2016May07] I assume we're running in krn but
- ; I'm not 100% sure..
+ lda curr_tr ; Select MMU register associated with
ora #$f ; top 8K of krn map
sta MMUADR
;;
;; stb 0xffaf
;; stb 0xffa7
- lda curr_tr ; [NAC HACK 2016May07] I assume we're running in krn but
- ; I'm not 100% sure..
+ lda curr_tr ; Select MMU register associated with
ora #$f ; top 8K of krn map
sta MMUADR
stb MMUDAT
stb _krn_mmu_map+7 ; keep the mirror in sync.
- lda curr_tr ; [NAC HACK 2016May07] I assume we're running in krn but
- ; I'm not 100% sure..
+ lda curr_tr ; Select MMU register associated with
ora #7 ; top 8K of usr map
sta MMUADR
stb MMUDAT
pshs d,x,u,y ; changing this will affect "ldb 0,s" below
;; map in dest
ldx #MMUADR ; for storing
- lda #(MMU_MAP1+8) ; mapsel=8, for dest, in B
+ lda curr_tr ; Select MMU register associated with
+ ora #8 ; mapsel=8, for dest, in B
std ,x ; mapsel=8, page in B
inca ; mapsel=9
incb ; adjacent page
;; restore mmu
ldy #_krn_mmu_map ; kernel's mmu ptr.. for reading
ldx #MMUADR ; for storing
- lda #(MMU_MAP1+8)
+ lda curr_tr ; Select MMU register associated with
+ ora #8 ; mapsel=8, for dest, in B
ldb ,y+ ; page from krn_mmu_map
std ,x ; Write A to MMUADR to set MAPSEL=8, then write B to MMUDAT
inca ; next mapsel
;;; remapping the mmu, copies those bytes, *then* re-computes the
;;; mmu banking and repeats until all bytes are transfered.
;;;
-;;; assume: map0 (kernel map) is in use.
;;; "borrow" the low 4 kernel MMU mappings; treating them as 2, 16K
;;; windows, map kernel space into the lower and user space into the
;;; upper, then copy from one to the other. At the end of the routine,
;;
;;
;;
- ldb #(MMU_MAP1|8)
+ ldb curr_tr
+ orb #8
stb 0,y ; MMUADR set mapsel=8
;;
ldb a,x ; get mmu entry
stb 1,y ; MMUDAT store in mmu
;;
;;
- ldb #(MMU_MAP1|9)
+ ldb curr_tr
+ orb #9
stb 0,y ; MMUADR set mapsel=9
;;
inca ; increment index [NAC HACK 2016May07] or a,x+ above and omit this??
anda #3 ; mask off junk [NAC HACK 2016May03] why not 7??
ldx #U_DATA__U_PAGE ; X = ptr to user page table
;;
- ldb #(MMU_MAP1|10)
+ ldb curr_tr
+ orb #10
stb 0,y ; MMUADR set mapsel=10
;;
ldb a,x ; B = page table entry
stb 1,y ; MMUDAT store in MMU
incb ; increment for next page no [NAC HACK 2016May03] coz we use page pairs?
;;
- lda #(MMU_MAP1|11) ; use A because B is busy this time
+ lda curr_tr ; use A because B is busy this time
+ ora #11
sta 0,y ; MMUADR set mapsel=11
;;
stb 1,y ; MMUDAT store in mmu
;; clean up kernel mmu's for next mapping or returning
ldx #MMUADR
ldy #_krn_mmu_map
- lda #(MMU_MAP1|8)
+ lda curr_tr ; Select MMU register associated with
+ ora #8 ; mapsel=8
ldb ,y+ ; page from _krn_mmu_map
std ,x ; Write A to MMUADR to set MAPSEL=8, then write B to MMUDAT
inca ; next mapsel