Merge branch 'master' of ichibi:/home/git/Repositories/pato-z80-home-computer
This commit is contained in:
commit
f717ac553b
12
assembly/applications/README.md
Normal file
12
assembly/applications/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Pat80 Applications
|
||||
|
||||
## Intro
|
||||
This folder contains some example applications.
|
||||
The folder `brief` contains little applications that can be entered directly via keyboard in the memory monitor.
|
||||
The folder `big` contains complete applications to be loaded via sdcard or tape.
|
||||
|
||||
## How to write an application
|
||||
When the Pat80 operating system is built, a `abi-generated.asm` file is built along with the rom binary. This file contains the description of the OS available API.
|
||||
An application targeting the last version of the OS should include this file, to make the system calls labels available inside the application code.
|
||||
The application can obtain the operating system ABI version (ABI -> https://en.wikipedia.org/wiki/Application_binary_interface) via the Sys_ABI call (it is a 16 bits integer returned in BC).
|
||||
The application's first command should be an ABI check: if the OS version is not compatible with the app, the app should exit displaying an error message.
|
7
assembly/applications/brief/hello_world.asm
Normal file
7
assembly/applications/brief/hello_world.asm
Normal file
@ -0,0 +1,7 @@
|
||||
org 0xA000
|
||||
include '../../os/abi-generated.asm'
|
||||
|
||||
STRING: DB "Hello",0
|
||||
ld bc, STRING
|
||||
call Sys_Print
|
||||
jp 0
|
@ -1,3 +0,0 @@
|
||||
ld bc, 0xA000
|
||||
call 0x0010
|
||||
jp 0
|
@ -1,9 +0,0 @@
|
||||
org 0x00A0
|
||||
|
||||
test:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
jp test
|
@ -1,16 +0,0 @@
|
||||
; Prints "Hello world" in terminal
|
||||
; Usage: assemble this file with z80asm and insert the resulting bytes
|
||||
; via Memory Monitor from address 0xA000 to test SET and RUN commands.
|
||||
|
||||
org 0xA000 ; Set starting position to ram
|
||||
ld bc, HELLO_WORLD_STR
|
||||
Term_print:
|
||||
ld a, (bc) ; bc is the pointer to string's first char
|
||||
cp 0 ; compare A content with 0 (subtract 0 from value and set zero flag Z if result is 0)
|
||||
jp z, term_print_end
|
||||
out (0x00),a ; output char to IO device 0, addr 0
|
||||
inc bc ; increment bc to move to next char
|
||||
jp Term_print
|
||||
term_print_end:
|
||||
halt
|
||||
HELLO_WORLD_STR: DB "Hello world!",0
|
@ -1,5 +0,0 @@
|
||||
Sys_Beep: equ $0050
|
||||
Sys_Print: equ $0010
|
||||
Sys_Printc: equ $0020
|
||||
Sys_Readc: equ $0030
|
||||
Sys_Readline: equ $0040
|
@ -1,2 +1,2 @@
|
||||
org 0xA000 ; Set starting position to ram
|
||||
include '../bios/main.asm'
|
||||
include '../os/main.asm'
|
@ -1,8 +1,8 @@
|
||||
bios:
|
||||
os:
|
||||
@echo "Building PAT80 rom..."
|
||||
@z80asm -i main.asm -o rom.bin || (exit 1)
|
||||
@echo "Generating label lookup table..."
|
||||
@z80asm -i main.asm -o rom.bin -L 2>&1 | grep "Sys_" > rom.label
|
||||
@z80asm -i main.asm -o rom.bin -L 2>&1 | grep "Sys_" > abi-generated.asm
|
||||
@echo "PAT80 Rom size:"
|
||||
@du -h rom.bin
|
||||
@echo "Stretching rom to EEPROM size..."
|
15
assembly/os/README.md
Normal file
15
assembly/os/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Pat80 Operating System and Memory Monitor
|
||||
|
||||
## Intro
|
||||
This folder contains the Pat80 Operating System.
|
||||
It is a System Monitor that makes available also some system API to access hardware (monitor, sound, keyboard, parallel terminal...).
|
||||
|
||||
## Build
|
||||
### Requirements
|
||||
z80asm, minipro
|
||||
### Make
|
||||
The os can be build issuing command `make`.
|
||||
Two files will be generated:
|
||||
- `rom.bin` is the rom file to be flashed on the eeprom
|
||||
- `abi-generated.asm` is the file to be included in any Pat80 application to access system APIs (see README.md in ../applications/)
|
||||
The build routine will then try to write the rom to a MiniPRO.
|
6
assembly/os/abi-generated.asm
Normal file
6
assembly/os/abi-generated.asm
Normal file
@ -0,0 +1,6 @@
|
||||
Sys_ABI: equ $0003
|
||||
Sys_Beep: equ $0013
|
||||
Sys_Print: equ $0007
|
||||
Sys_Printc: equ $000a
|
||||
Sys_Readc: equ $000d
|
||||
Sys_Readline: equ $0010
|
@ -23,39 +23,37 @@ jp Sysinit ; Startup vector: DO NOT MOVE! Must be the first instruction
|
||||
; System calls provide access to low level functions (input from keyboard, output to screen etc).
|
||||
; The name starts always with Sys_
|
||||
|
||||
; Returns ABI version.
|
||||
; (ABI -> https://en.wikipedia.org/wiki/Application_binary_interface)
|
||||
; Any Pat80 application should check the ABI version on startup, and refuse to run if not compatible.
|
||||
; @return bc the ABI version
|
||||
Sys_ABI:
|
||||
ld bc, 0
|
||||
ret
|
||||
|
||||
; Prints string
|
||||
; @param BC Pointer to a null-terminated string first character
|
||||
org 0x0010
|
||||
Sys_Print:
|
||||
call Term_print
|
||||
ret
|
||||
jp Term_print
|
||||
|
||||
; Writes a single character
|
||||
; @param A Value of character to print
|
||||
org 0x0020
|
||||
Sys_Printc:
|
||||
call Term_printc
|
||||
ret
|
||||
jp Term_printc
|
||||
|
||||
; Reads a single character
|
||||
; @return A The read character
|
||||
org 0x0030
|
||||
Sys_Readc:
|
||||
call Term_readc
|
||||
ret
|
||||
jp Term_readc
|
||||
|
||||
; Reads a line
|
||||
; @return BC The pointer to a null-terminated read string
|
||||
org 0x0040
|
||||
Sys_Readline:
|
||||
call Term_readline
|
||||
ret
|
||||
jp Term_readline
|
||||
|
||||
; Emits system beep
|
||||
org 0x0050
|
||||
Sys_Beep:
|
||||
call Snd_beep
|
||||
ret
|
||||
jp Snd_beep
|
||||
|
||||
|
||||
|
@ -469,22 +469,47 @@ monitor_printAsciiByte:
|
||||
call Sys_Printc
|
||||
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 no data is available for 8 cpu cycles.
|
||||
; Copy data from parallel terminal to application memory. This is tought to be used with the ADB function of the Pat80 Python Terminal.
|
||||
; Uses TERM_DATA_AVAIL_REG to check if a byte is available before reading it.
|
||||
; The first two received bytes (heading bytes) defines the stream length (MSB first), the rest of the bytes are copied to memory.
|
||||
; The copy is completed when the number of bytes defined in the heading bytes are received.
|
||||
; @uses a, b, c, d, h, l
|
||||
monitor_copyTermToAppMem:
|
||||
; d contains the current status.
|
||||
; 2 = waiting for first heading byte
|
||||
; 1 = waiting for second heading byte
|
||||
; 0 = heading bytes received, now receiving binary stream
|
||||
ld d, 2
|
||||
ld hl, APP_SPACE ; we will write in APP_SPACE
|
||||
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 z ; 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
|
||||
; check if bytes are available
|
||||
call Term_availb
|
||||
cp 0
|
||||
jp z, monitor_copyTermToAppMem ; no bytes available, next loop
|
||||
; bytes are available
|
||||
ld a, d
|
||||
cp 2 ; check if we are receiving first header byte
|
||||
jp z, monitor_copyTermToAppMem_loop_rec_head_byte_1
|
||||
ld a, d
|
||||
cp 1 ; check if we are receiving second header byte
|
||||
jp z, monitor_copyTermToAppMem_loop_rec_head_byte_2
|
||||
; we are receiving binary stream: read byte and save to memory
|
||||
call Term_readb
|
||||
ld (hl), a ; copy byte to memory
|
||||
inc hl ; move to next memory position
|
||||
jp monitor_copyTermToAppMem_loop ; continue loop
|
||||
|
||||
monitor_copyTermToAppMem_loop_rec_head_byte_1:
|
||||
; we are receiving first header byte: read byte and save to b
|
||||
call Term_readb
|
||||
ld b, a
|
||||
dec d
|
||||
jp monitor_copyTermToAppMem_loop ; continue loop
|
||||
monitor_copyTermToAppMem_loop_rec_head_byte_2:
|
||||
; we are receiving second header byte: read byte and save to c
|
||||
call Term_readb
|
||||
ld c, a
|
||||
dec d
|
||||
jp monitor_copyTermToAppMem_loop ; continue loop
|
||||
|
||||
|
27
assets/worklog/ita/02-hello-world.md
Normal file
27
assets/worklog/ita/02-hello-world.md
Normal file
@ -0,0 +1,27 @@
|
||||
"Roma non è stata costruita in un giorno".
|
||||
Cominceremo dalle basi. E la base di un computer è proprio il processore.
|
||||
Il contenuto della scatolina vista nello scorso post è lo Zilog Z80, un processore progettato da Federico Faggin nella prima metà degli anni 70, ed utilizzato poi in innumerevoli computer e console, fino agli anni 90 (eh si, a quei tempi non usciva un processore l'anno...).
|
||||
Questa CPU è ancora in produzione, sebbene "aggiornata" facendo uso della tecnologia CMOS, molto più efficiente e parca nei consumi. Il modello in mio possesso può essere clockato fino ad 8Mhz, ma se ne trovano modelli fino a 20Mhz! All'epoca una frequenza comune per questo processore era intorno ai 3Mhz (spesso 3,57 per utilizzare un solo cristallo sia per la CPU che per la [generazione di colore per il video](https://en.wikipedia.org/wiki/NTSC#Color_encoding) ).
|
||||
Oggi, però, la faremo girare moooooolto più lenta.
|
||||
|
||||
Da dove cominciare? Per saperlo, bisogna chiederci quale sia il comportamento atteso di un processore. Non è la sede per una spiegazione approfondita, ma basti sapere che il processore (anche i più moderni) non fa altro che eseguire delle istruzioni. Una istruzione è un byte (o se preferite un numero da 0 a 255) che dice al processore cosa fare.
|
||||
Questo viene ripetuto all'infinito, in un ciclo composto da tre fasi:
|
||||
- Fetch (ottiene l'istruzione da eseguire dalla memoria)
|
||||
- Decode (interpreta l'istruzione)
|
||||
- Execute (la esegue)
|
||||
Per la nostra prima prova abbiamo bisogno di sapere anche come funziona la memoria.
|
||||
Ogni memoria (ROM, RAM, Flash...) è composta da una serie di posizioni che possono contenere dei valori. Si accede al contenuto di una posizione in base al suo indirizzo.
|
||||
Quando il processore viene avviato, non fa altro che cominciare dalla prima posizione di memoria (0), leggere il contenuto (Fetch), capire cosa significa (Decode), eseguirlo (Execute) e passare alla successiva posizione di memoria (1), dove ricomincia da capo.
|
||||
Ovviamente alcune istruzioni possono modificare questo flusso, ad esempio l'istruzione JP (Jump) dice al processore "Non andare a prendere la prossima posizione di memoria, ma salta alla posizione X".
|
||||
Per questo motivo noi siamo interessati all'istruzione NOP, (No OPeration): questa istruzione non fa assolutamente nulla. Spreca un ciclo di cpu senza toccare nulla, per cui il processore andrà a cercare l'istruzione successiva nella posizione di memoria successiva.
|
||||
Ci aspettiamo quindi di vedere i seguenti accessi alla memoria (a destra il valore binario):
|
||||
0 00000000 00000000
|
||||
1 00000000 00000001
|
||||
2 00000000 00000010
|
||||
3 00000000 00000011
|
||||
4 00000000 00000100
|
||||
5 00000000 00000101
|
||||
etc etc ...
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ import serial
|
||||
import curses
|
||||
import time
|
||||
import textwrap
|
||||
import os
|
||||
|
||||
|
||||
class TerminalEmulator:
|
||||
@ -66,6 +67,15 @@ class TerminalEmulator:
|
||||
w.addstr(0, 0, '[ADB MODE] file to load:', curses.A_REVERSE)
|
||||
path = w.getstr()
|
||||
try:
|
||||
size = os.path.getsize(path)
|
||||
# Compute the two header bytes needed to declare the length of the stream
|
||||
h1 = size & 255 # get lower 8 bits
|
||||
size >>= 8 # shift by 8 bits
|
||||
h0 = size & 255 # get second lower 8 bits
|
||||
# Send the two heading bytes (most significant first)
|
||||
ser.write(h0)
|
||||
ser.write(h1)
|
||||
# Send the actual binary stream
|
||||
with open(path, "rb") as f:
|
||||
byte = f.read(1)
|
||||
while byte:
|
||||
|
Loading…
x
Reference in New Issue
Block a user