diff --git a/parts/platforms/rc2014.inc b/parts/platforms/rc2014.inc index 7fd92f0..69b7efa 100644 --- a/parts/platforms/rc2014.inc +++ b/parts/platforms/rc2014.inc @@ -1,5 +1,7 @@ ; classic RC2014 setup (8K ROM + 32K RAM) and a stock Serial I/O module -RAMEND .equ 0xa000 +; The RAM module is selected on A15, so it has the range 0x8000-0xffff +RAMSTART .equ 0x8000 +RAMEND .equ 0xffff ACIA_CTL .equ 0x80 ; Control and status. RS off. ACIA_IO .equ 0x81 ; Transmit. RS on. diff --git a/parts/shell/shell.asm b/parts/shell/shell.asm index f61ee21..a44939b 100644 --- a/parts/shell/shell.asm +++ b/parts/shell/shell.asm @@ -2,8 +2,9 @@ ; ; Runs a shell over an asynchronous communication interface adapter (ACIA). -; *** STATUS *** -; Incomplete. This just outputs the welcome prompt then halts +; Incomplete. For now, this outputs a welcome prompt and then waits for input. +; Whenever input is CR or LF, we echo back what we've received and empty the +; input buffer. This also happen when the buffer is full. #include "platform.inc" @@ -11,28 +12,50 @@ CR .equ 0x0d LF .equ 0x0a +; size of the input buffer. If our input goes over this size, we echo +; immediately. +BUFSIZE .equ 0x20 + +; *** VARIABLES *** +; Our input buffer starts there +INPTBUF .equ RAMSTART + +; index, in the buffer, where our next character will go. 0 when the buffer is +; empty, BUFSIZE-1 when it's almost full. +BUFIDX .equ INPTBUF+BUFSIZE + ; *** CODE *** jr init init: - di ; no need for interrupts yet + ; disable interrupts we don't need them + di ; setup stack ld hl, RAMEND ld sp, hl + ; initialize variables + xor a + ld (BUFIDX), a ; starts at 0 + ; setup ACIA - ; CR7 (1) - Receive Interrupt enabled + ; CR7 (1) - Receive Interrupt disabled ; CR6:5 (00) - RTS low, transmit interrupt disabled. ; CR4:2 (101) - 8 bits + 1 stop bit ; CR1:0 (10) - Counter divide: 64 - ld a, 0b10010110 + ld a, 0b00010110 out (ACIA_CTL), a ; print prompt ld hl, d_welcome call printstr - halt + call printcrlf + +mainloop: + call readc + call chkbuf + jr mainloop ; spits character in A in port SER_OUT printc: @@ -55,5 +78,84 @@ printstr: jr printstr ; no ret because our only way out is ret z above +printcrlf: + ld a, CR + call printc + ld a, LF + call printc + ret + +; wait until a char is read in the ACIA and put it in the read buffer +readc: + ; first thing first: is our input buffer full? If yes, we don't even + ; bother reading the ACIA. Something is wrong: we don't process data + ; fast enough. + ld a, (BUFIDX) + cp BUFSIZE + ret z ; if BUFIDX == BUFSIZE, our buffer is full. + + call getbufptr + + ; increase our buf ptr while we still have it in A + inc a + ld (BUFIDX), a + +.loop: + ; Read our character from ACIA into our BUFIDX + in a, (ACIA_CTL) + bit 0, a ; is our ACIA rcv buffer full? + jr z, .loop ; no? loop + + in a, (ACIA_IO) + ld (hl), a + + ret + +; check if the input buffer is full or ends in CR or LF. If it does, prints it +; back and empty it. +chkbuf: + ld a, (BUFIDX) + cp 0 + ret z ; BUFIDX is zero? nothing to check. + + cp BUFSIZE + jr z, .do ; if BUFIDX == BUFSIZE? do! + + call getbufptr + ; our previous char is in BUFIDX - 1. Fetch this + dec hl + ld a, (hl) ; now, that's our char we have in A + inc hl ; put HL back where it was + + cp CR + jr z, .do ; char is CR? do! + cp LF + jr z, .do ; char is LF? do! + + ; nothing matched? don't do anything + ret + +.do: + ; terminate our string with 0 + xor a + ld (hl), a + ; reset buffer index + ld (BUFIDX), a + + ; alright, let's go! + ld hl, INPTBUF + call printstr + call printcrlf + ret + +; Set current buffer pointer in HL. The buffer pointer is where our *next* char +; will be written. +getbufptr: + ld hl, INPTBUF + xor b + ld c, a + add hl, bc ; hl now points to INPTBUF + BUFIDX + ret + ; *** DATA *** -d_welcome: .byte "Welcome to Collapse OS", CR, LF, 0 +d_welcome: .byte "Welcome to Collapse OS", 0