WIP reimplementing serial terminal with DATA_AVAILABLE register

This commit is contained in:
Daniele Verducci (ZenPenguin) 2020-12-16 08:49:28 +01:00
parent f1e7622e17
commit 2c9675b8f0
3 changed files with 54 additions and 22 deletions

View File

@ -2,19 +2,28 @@
* Terminal interface.
* This sketch allow an Arduino to be used as a terminal to log into Pat80.
* The Arduino is connected to the Pat80 I/O bus and to the terminal computer via USB.
* The Arduino IDE serial monitor is used to send and receive commands to the Z80.
* The Python Terminal Monitor or the Arduino IDE serial monitor is used to send
* and receive commands to/from the Z80.
*
* Seen from the Pat80, the terminal interface has two registers:
* DATA Register at addr 0x00 (\RS) contains the last received byte from the pc
* DATA_AVAILABLE Register at addr 0x01 (RS) contains the number of bytes in the buffer,
* waiting to be read from the Pat80. A READ operation on DATA register removes the
* byte from the buffer and decrements DATA_AVAILABLE.
*/
// EN 2 // Input, Active low
// WR 11 // Input, Active low
// RS 12 // Input, low = DATA register, high = DATA_AVAILABLE register
// DATA BUS (Input/Output, active high): 3, 4, 5, 6, 7, 8, 9, 10;
byte incomingBuffer = 0; // Incoming from computer, to the Pat80
byte outgoingBuffer = 0; // Outgoing to computer, from the Pat80
byte availableBytes = 0; // Available bytes in the incoming buffer (for the DATA_AVAILABLE register)
void setup() {
DDRD = B00000010; // Port D (used arduino pins 2 (EN) and 3 to 7 (DATA)) is input. Avoid changing serial pins.
DDRB = B00000000; // Port B (used arduino pins 8 to 10 (DATA) and 11 (WR)) is input
DDRB = B00000000; // Port B (used arduino pins 8 to 10 (DATA), 11 (WR) and 12 (RS) is input
Serial.begin(2000000);
Serial.println("Pat80 terminal");
@ -25,6 +34,7 @@ void setup() {
void loop() {
if (Serial.available() > 0) {
incomingBuffer = Serial.read();
availableBytes = 1; // TODO: Implement a 256 byte buffer and store the avail bytes number in this var
}
if (outgoingBuffer != 0) {
if ((outgoingBuffer >= 8 && outgoingBuffer <= 13) || (outgoingBuffer >= 32 && outgoingBuffer <= 127)) {
@ -49,10 +59,17 @@ void onClk() {
if ((PINB & B00001000) == B00001000) { // WR is HIGH (Pat80 wants to Read (we send data))
DDRD = DDRD | B11111000; // Port D (arduino pins 3 to 7) is output. In or to preserve serial pins and interrupt pin
DDRB = B00000111; // Port B (0,1,2) = pins 8,9,10 output
// Split byte to two parts
PORTD = incomingBuffer << 3;
PORTB = incomingBuffer >> 5;
incomingBuffer = 0;
if ((PINB & B00010000) == B00010000) { // RS is HIGH: we send number of bytes available in buffer
// Split byte to two parts
PORTD = availableBytes << 3;
PORTB = availableBytes >> 5;
} else {
// Split byte to two parts
PORTD = incomingBuffer << 3;
PORTB = incomingBuffer >> 5;
incomingBuffer = 0;
availableBytes = 0;
}
} else {
// Pat80 wants to Write (we receive data)
outgoingBuffer = (PIND >> 3) | (PINB << 5); // Compose the final byte from the two parts

View File

@ -3,6 +3,7 @@
; config (IO port 0)
TERM_DATA_REG: EQU IO_0
TERM_DATA_AVAIL_REG: EQU IO_0 + 1
; variables
TERM_VAR_SPACE: EQU DRV_VAR_SPACE + 128
@ -26,7 +27,9 @@ Term_printc:
out (TERM_DATA_REG),a
ret
; Reads a single character. 0s are ignored (can be used with keyboard)
; Reads a single character. 0s are ignored (can be used with keyboard).
; Doesn't check DATA_AVAILABLE register of parallel port, because a 0 byte
; is ignored anyway (it represents the ASCII NUL control char).
; @return A The read character
Term_readc:
in a, (TERM_DATA_REG) ; reads a character
@ -35,6 +38,8 @@ Term_readc:
ret ; if not NULL, returns it in the a register
; Reads a line. 0s are ignored (can be used with keyboard)
; Doesn't check DATA_AVAILABLE register of parallel port, because a 0 byte
; is ignored anyway (it represents the ASCII NUL control char).
; @return BC The pointer to a null-terminated read string
Term_readline:
ld bc, incoming_string ; this array will contain read string
@ -56,9 +61,17 @@ Term_readline:
ld bc, incoming_string ; Returns read string pointer
ret
; Reads the byte currently on the I/O bus at the provided address.
; Returns the number of bytes available on the parallel port using the
; DATA_AVAILABLE register.
; @return a the number of available bytes
Term_availb:
in a, (TERM_DATA_AVAIL_REG)
ret
; Reads the first available byte on the serial port using the DATA register.
; 0s are not ignored (cannot be used with keyboard)
; Affects NO condition bits!
; @return the available byte, even if 0
Term_readb:
in a, (TERM_DATA_REG) ; reads a byte
ret

View File

@ -25,6 +25,7 @@ MON_ARG_HEX: DB " 0x",0
MON_HELP: DB 10,"Available commands:\nHELP prints this message\nDUMP shows memory content\nSET sets memory content LOAD\nRUN executes code\nADB starts Assembly Deploy Bridge",0
MON_MSG_ADB: DB 10,"Waiting for data.",0
MON_ERR_SYNTAX: DB " Syntax error",0
;MON_ADB_TIMEOUT: EQU 0xFF // Number of cycles after an ADB binary transfer is considered completed
Monitor_main:
; Print welcome string
@ -101,8 +102,10 @@ monitor_adb:
call Print
; start copying incoming data to application space
call monitor_copyTermToAppMem
jp APP_SPACE ; Start executing code
;jp monitor_main_loop
;jp APP_SPACE ; Start executing code
ld bc, APP_SPACE
call Print
jp monitor_main_loop
; Read 1 hex byte (e.g. 0x8C)
monitor_arg_byte:
@ -160,22 +163,21 @@ monitor_readHexDigit:
ret
; Copy data from STDIN to application memory. This is tought to be used with parallel terminal, not keyboard:
; 0s are not ignored and the sequence is complete when found 8 zeros.
; 0s are not ignored and the sequence is complete when no data is available for 8 cpu cycles.
monitor_copyTermToAppMem:
call Term_readb
cp 0
jp z, monitor_copyTermToAppMem ; wait for data stream to begin: ignore leading zeros
ld hl, APP_SPACE ; we will write in APP_SPACE
ld b, 8 ; the number of zeros that represent the end of stream
ld b, 255; MON_ADB_TIMEOUT ; the timeout counter (number cycles without available data that represent the end of stream)
monitor_copyTermToAppMem_loop:
dec b ; decrement the timeout counter
ret 0 ; if counter is 0, timeout reached: return
; check if bytes are available
call Term_availb
cp 0
jp z, monitor_copyTermToAppMem ; no bytes available, next loop
; bytes are available
ld b, 255 ;MON_ADB_TIMEOUT; reset the counter
ld (hl), a ; copy byte to memory
inc hl ; move to next memory position
cp 0 ; compare A to 0
; load next byte to A (this doesn't affect condition bits, so flag Z from previous cp is still valid)
call Term_readb
jp nz, monitor_copyTermToAppMem_loop ; if during previous cp A was not 0, execute next cycle
dec b ; if A is 0, decrement "end of stream" counter
ret z ; if B is 0, we found 8 zeros, so the stream is finished: return.
jp monitor_copyTermToAppMem_loop ; otherwise, continue loop
jp monitor_copyTermToAppMem_loop ; continue loop