Compare commits
3 Commits
monitor-in
...
TerminalWi
Author | SHA1 | Date | |
---|---|---|---|
17153486a6 | |||
ff4823b3ad | |||
4d9fd83cdd |
@ -1,6 +1,6 @@
|
|||||||
Sys_ABI: equ $0081
|
Sys_ABI: equ $0003
|
||||||
Sys_Beep: equ $0091
|
Sys_Beep: equ $0013
|
||||||
Sys_Print: equ $0085
|
Sys_Print: equ $0007
|
||||||
Sys_Printc: equ $0088
|
Sys_Printc: equ $000a
|
||||||
Sys_Readc: equ $008b
|
Sys_Readc: equ $000d
|
||||||
Sys_Readline: equ $008e
|
Sys_Readline: equ $0010
|
||||||
|
@ -19,21 +19,9 @@ jp Sysinit ; Startup vector: DO NOT MOVE! Must be the first instruction
|
|||||||
; I/O 6 (0xC0 - 0xDF)
|
; I/O 6 (0xC0 - 0xDF)
|
||||||
; I/O 7 (0xE0 - 0xFF)
|
; I/O 7 (0xE0 - 0xFF)
|
||||||
|
|
||||||
; **** RESET/INTERRUPT VECTOR ****
|
|
||||||
|
|
||||||
; Maskable interrupt mode 1: when the BREAK key is pressed,
|
|
||||||
; a maskable interrupt is generated and the CPU jumps to this address.
|
|
||||||
; In this way, BREAK key brings up memory monitor at any time.
|
|
||||||
ds 0x38
|
|
||||||
di ; Disable maskable interrupts.
|
|
||||||
exx ; exchange registers
|
|
||||||
ex af, af'
|
|
||||||
jp Monitor_main
|
|
||||||
|
|
||||||
; **** SYSTEM CALLS ****
|
; **** SYSTEM CALLS ****
|
||||||
; System calls provide access to low level functions (input from keyboard, output to screen etc).
|
; System calls provide access to low level functions (input from keyboard, output to screen etc).
|
||||||
; The name starts always with Sys_
|
; The name starts always with Sys_
|
||||||
ds 0x40 ; Place system calls after Z80 reset/interrupt subroutines space
|
|
||||||
|
|
||||||
; Returns ABI version.
|
; Returns ABI version.
|
||||||
; (ABI -> https://en.wikipedia.org/wiki/Application_binary_interface)
|
; (ABI -> https://en.wikipedia.org/wiki/Application_binary_interface)
|
||||||
@ -113,18 +101,13 @@ Sysinit:
|
|||||||
; Play startup sound
|
; Play startup sound
|
||||||
call Sys_Beep
|
call Sys_Beep
|
||||||
|
|
||||||
; Run memory monitor
|
; Run memory monitor
|
||||||
ei ; enable maskabpe interrupts
|
call Monitor_main
|
||||||
im 1 ; set interrupt mode 1 (on interrupt jumps to 0x38)
|
|
||||||
rst 0x38 ; throw fake interrupt: jump to interrupt routine to start monitor
|
|
||||||
|
|
||||||
; User exited from memory monitor without loading a program. Do nothing.
|
|
||||||
mloop:
|
|
||||||
; Main loop: do nothing.
|
|
||||||
jp mloop
|
|
||||||
|
|
||||||
; DEBUG: Echo chars
|
; DEBUG: Echo chars
|
||||||
; loop:
|
; loop:
|
||||||
; call Term_readc
|
; call Term_readc
|
||||||
; call Term_printc
|
; call Term_printc
|
||||||
; jp loop
|
; jp loop
|
||||||
|
|
||||||
|
halt
|
||||||
|
@ -21,9 +21,8 @@ MON_COMMAND_ZERO: DB "ZERO",0
|
|||||||
MON_COMMAND_LOAD: DB "LOAD",0
|
MON_COMMAND_LOAD: DB "LOAD",0
|
||||||
MON_COMMAND_RUN: DB "RUN",0
|
MON_COMMAND_RUN: DB "RUN",0
|
||||||
MON_COMMAND_ADB: DB "ADB",0
|
MON_COMMAND_ADB: DB "ADB",0
|
||||||
MON_COMMAND_QUIT: DB "QUIT",0
|
|
||||||
MON_ARG_HEX: DB " 0x",0
|
MON_ARG_HEX: DB " 0x",0
|
||||||
MON_HELP: DB 10,"Available commands:\nHELP prints this message\nDUMP [ADDR] shows memory content\nSET [ADDR] sets memory content\nZERO [ADDR] [ADDR] sets all bytes to 0 in the specified range\nLOAD\nRUN [ADDR] executes code starting from ADDR\nADB starts Assembly Deploy Bridge\nQUIT exits",0
|
MON_HELP: DB 10,"Available commands:\nHELP prints this message\nDUMP [ADDR] shows memory content\nSET [ADDR] sets memory content\nZERO [ADDR] [ADDR] sets all bytes to 0 in the specified range\nLOAD\nRUN [ADDR] executes code starting from ADDR\nADB starts Assembly Deploy Bridge",0
|
||||||
MON_MSG_ADB: DB 10,"Waiting for data.",0
|
MON_MSG_ADB: DB 10,"Waiting for data.",0
|
||||||
MON_ERR_SYNTAX: DB " Syntax error",0
|
MON_ERR_SYNTAX: DB " Syntax error",0
|
||||||
;MON_ADB_TIMEOUT: EQU 0xFF // Number of cycles after an ADB binary transfer is considered completed
|
;MON_ADB_TIMEOUT: EQU 0xFF // Number of cycles after an ADB binary transfer is considered completed
|
||||||
@ -67,9 +66,6 @@ Monitor_main:
|
|||||||
ld hl, MON_COMMAND_ADB
|
ld hl, MON_COMMAND_ADB
|
||||||
cp (hl)
|
cp (hl)
|
||||||
jp z, monitor_adb
|
jp z, monitor_adb
|
||||||
ld hl, MON_COMMAND_QUIT
|
|
||||||
cp (hl)
|
|
||||||
jp z, monitor_quit
|
|
||||||
; Unrecognized command: print error and beep
|
; Unrecognized command: print error and beep
|
||||||
ld bc, MON_ERR_SYNTAX
|
ld bc, MON_ERR_SYNTAX
|
||||||
call Sys_Print
|
call Sys_Print
|
||||||
@ -84,23 +80,6 @@ monitor_help:
|
|||||||
call Sys_Print
|
call Sys_Print
|
||||||
jp monitor_main_loop
|
jp monitor_main_loop
|
||||||
|
|
||||||
monitor_quit:
|
|
||||||
ld bc, MON_COMMAND_QUIT + 1 ; autocomplete command
|
|
||||||
call Sys_Print
|
|
||||||
; newline
|
|
||||||
ld a, 10
|
|
||||||
call Sys_Printc
|
|
||||||
; Restores registers and re-enable interrupts: when the BREAK key is pressed,
|
|
||||||
; a maskable interrupt is generated and the CPU jumps to 0x38 reset vector,
|
|
||||||
; where if finds a call to Memory monitor (see main.asm).
|
|
||||||
exx ; exchange registers
|
|
||||||
ex af, af'
|
|
||||||
; enable interrupts
|
|
||||||
ei
|
|
||||||
im 1 ; set interrupt mode 1 (on interrupt jumps to 0x38)
|
|
||||||
reti ; return from interrupt
|
|
||||||
|
|
||||||
|
|
||||||
; Asks the user for a memory position and shows the following 64 bytes of memory
|
; Asks the user for a memory position and shows the following 64 bytes of memory
|
||||||
; @uses a, b, c, d, e, h, l
|
; @uses a, b, c, d, e, h, l
|
||||||
monitor_dump:
|
monitor_dump:
|
||||||
@ -278,34 +257,23 @@ monitor_zero: ; TODO: bugged, doesn't exit cycle
|
|||||||
monitor_load:
|
monitor_load:
|
||||||
ld bc, MON_COMMAND_LOAD + 1 ; autocomplete command
|
ld bc, MON_COMMAND_LOAD + 1 ; autocomplete command
|
||||||
call Sys_Print
|
call Sys_Print
|
||||||
; TODO: When implemented, re-enable interrupts before run application
|
|
||||||
jp monitor_main_loop
|
jp monitor_main_loop
|
||||||
|
|
||||||
monitor_run:
|
monitor_run:
|
||||||
ld bc, MON_COMMAND_RUN + 1 ; autocomplete command
|
ld bc, MON_COMMAND_RUN + 1 ; autocomplete command
|
||||||
call Sys_Print
|
call Sys_Print
|
||||||
; Now read the memory address to be executed from the user
|
; Now read the memory address to be changed from the user
|
||||||
call monitor_arg_2byte ; returns the read bytes in hl
|
call monitor_arg_2byte ; returns the read bytes in hl
|
||||||
ld a, 10 ; newline
|
ld a, 10 ; newline
|
||||||
call Sys_Printc
|
call Sys_Printc
|
||||||
; enable interrupts
|
jp (hl) ; Start executing code
|
||||||
ei
|
|
||||||
im 1 ; set interrupt mode 1 (on interrupt jumps to 0x38)
|
|
||||||
; pop the last entry on the stack: this is needed (as the monitor
|
|
||||||
; runs in an interrupt) to counter-balance the missing reti statement
|
|
||||||
pop bc
|
|
||||||
; execute code
|
|
||||||
jp (hl)
|
|
||||||
|
|
||||||
monitor_adb:
|
monitor_adb:
|
||||||
ld bc, MON_COMMAND_ADB + 1 ; autocomplete command
|
ld bc, MON_COMMAND_ADB + 1 ; autocomplete command
|
||||||
call Sys_Print
|
call Sys_Print
|
||||||
; start copying incoming data to application space
|
; start copying incoming data to application space
|
||||||
call monitor_copyTermToAppMem
|
call monitor_copyTermToAppMem
|
||||||
; call monitor_enable_int ; re-enable interrupts
|
|
||||||
;jp APP_SPACE ; Start executing code
|
;jp APP_SPACE ; Start executing code
|
||||||
|
|
||||||
|
|
||||||
; ld bc, APP_SPACE
|
; ld bc, APP_SPACE
|
||||||
; call Sys_Print
|
; call Sys_Print
|
||||||
jp monitor_main_loop
|
jp monitor_main_loop
|
||||||
@ -549,5 +517,3 @@ monitor_copyTermToAppMem:
|
|||||||
jp monitor_copyTermToAppMem_loop ; continue loop
|
jp monitor_copyTermToAppMem_loop ; continue loop
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
* The Python Terminal Monitor or the Arduino IDE serial monitor is used to send
|
* The Python Terminal Monitor or the Arduino IDE serial monitor is used to send
|
||||||
* and receive commands to/from the Z80.
|
* and receive commands to/from the Z80.
|
||||||
*
|
*
|
||||||
|
* Seen from the PC, the terminal receives two bytes: a command byte and a value byte.
|
||||||
|
* Commands:
|
||||||
|
* 0x00 WRITE: The next byte is sent as-is to Pat80. If the terminal interface buffer
|
||||||
|
* is not empty, the new byte will replace the older one.
|
||||||
|
* 0x01 BUFFER: The terminal interface returns the number of bytes waiting to be sent.
|
||||||
|
*
|
||||||
* Seen from the Pat80, the terminal interface has two registers:
|
* 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 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,
|
* DATA_AVAILABLE Register at addr 0x01 (RS) contains the number of bytes in the buffer,
|
||||||
@ -17,6 +23,9 @@
|
|||||||
// RS 12 // Input, low = DATA register, high = DATA_AVAILABLE register
|
// RS 12 // Input, low = DATA register, high = DATA_AVAILABLE register
|
||||||
// DATA BUS (Input/Output, active high): 3, 4, 5, 6, 7, 8, 9, 10;
|
// DATA BUS (Input/Output, active high): 3, 4, 5, 6, 7, 8, 9, 10;
|
||||||
|
|
||||||
|
const byte COMMAND_WRITE = 0x00;
|
||||||
|
const byte COMMAND_BUFFER = 0x01;
|
||||||
|
|
||||||
byte incomingBuffer = 0; // Incoming from computer, to the Pat80
|
byte incomingBuffer = 0; // Incoming from computer, to the Pat80
|
||||||
byte outgoingBuffer = 0; // Outgoing to computer, from 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)
|
byte availableBytes = 0; // Available bytes in the incoming buffer (for the DATA_AVAILABLE register)
|
||||||
@ -32,10 +41,19 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (Serial.available() > 0) {
|
if (Serial.available() > 1) {
|
||||||
incomingBuffer = Serial.read();
|
switch (Serial.read()) {
|
||||||
availableBytes = 1; // TODO: Implement a 256 byte buffer and store the avail bytes number in this var
|
case COMMAND_WRITE:
|
||||||
|
while (Serial.available() < 1) {} // Waits for the second byte
|
||||||
|
incomingBuffer = Serial.read();
|
||||||
|
availableBytes = 1; // TODO: Implement a 256 byte buffer and store the avail bytes number in this var
|
||||||
|
break;
|
||||||
|
case COMMAND_BUFFER:
|
||||||
|
Serial.write(availableBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outgoingBuffer != 0) {
|
if (outgoingBuffer != 0) {
|
||||||
if ((outgoingBuffer >= 8 && outgoingBuffer <= 13) || (outgoingBuffer >= 32 && outgoingBuffer <= 127)) {
|
if ((outgoingBuffer >= 8 && outgoingBuffer <= 13) || (outgoingBuffer >= 32 && outgoingBuffer <= 127)) {
|
||||||
// Printable character
|
// Printable character
|
||||||
|
@ -31,7 +31,6 @@ import os
|
|||||||
|
|
||||||
|
|
||||||
class TerminalEmulator:
|
class TerminalEmulator:
|
||||||
SYNC_SLEEP = 0.001
|
|
||||||
|
|
||||||
def __init__(self, w, ser):
|
def __init__(self, w, ser):
|
||||||
w.clear()
|
w.clear()
|
||||||
@ -48,8 +47,7 @@ class TerminalEmulator:
|
|||||||
key = w.getch()
|
key = w.getch()
|
||||||
if key == 10 or (key > 31 and key < 256):
|
if key == 10 or (key > 31 and key < 256):
|
||||||
# Is a character
|
# Is a character
|
||||||
time.sleep(self.SYNC_SLEEP)
|
self.sendByte(bytes([key]))
|
||||||
ser.write(bytes([key]))
|
|
||||||
elif int(key) == 1: # CTRL+A, enter ADB mode
|
elif int(key) == 1: # CTRL+A, enter ADB mode
|
||||||
# Save cursor position
|
# Save cursor position
|
||||||
(xPos, yPos) = w.getyx()
|
(xPos, yPos) = w.getyx()
|
||||||
@ -82,10 +80,8 @@ class TerminalEmulator:
|
|||||||
w.refresh()
|
w.refresh()
|
||||||
|
|
||||||
# Send the two heading bytes (most significant first)
|
# Send the two heading bytes (most significant first)
|
||||||
ser.write(header[0:1])
|
self.sendByte(header[0:1])
|
||||||
time.sleep(self.SYNC_SLEEP)
|
self.sendByte(header[1:2])
|
||||||
ser.write(header[1:2])
|
|
||||||
time.sleep(self.SYNC_SLEEP)
|
|
||||||
|
|
||||||
# Send the actual binary stream
|
# Send the actual binary stream
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
@ -104,7 +100,21 @@ class TerminalEmulator:
|
|||||||
|
|
||||||
curses.noecho()
|
curses.noecho()
|
||||||
stdscr.nodelay(True)
|
stdscr.nodelay(True)
|
||||||
|
|
||||||
|
# Sends a byte checking if the interface is busy
|
||||||
|
def sendByte(self, b):
|
||||||
|
busy = True
|
||||||
|
while busy:
|
||||||
|
# check if busy
|
||||||
|
ser.write(b'\x01') # send COMMAND_BUFFER
|
||||||
|
while not ser.inWaiting():
|
||||||
|
# wait for answer from interface
|
||||||
|
pass
|
||||||
|
busy = ser.read() != 0
|
||||||
|
# interface is free: write byte
|
||||||
|
ser.write(b'\x00') # send COMMAND_WRITE
|
||||||
|
ser.write(b) # send byte
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import argparse
|
import argparse
|
||||||
|
Reference in New Issue
Block a user