First os version with ABI number and working system calls

This commit is contained in:
Daniele Verducci su MatissePenguin 2020-12-30 19:58:32 +01:00
parent b1f9788772
commit ef58b417e6
12 changed files with 81 additions and 49 deletions

View 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.

View File

@ -0,0 +1,7 @@
org 0xA000
include '../../bios/abi-generated.asm'
STRING: DB "Hello",0
ld bc, STRING
call Sys_Print
jp 0

View File

@ -1,3 +0,0 @@
ld bc, 0xA000
call 0x0010
jp 0

View File

@ -1,9 +0,0 @@
org 0x00A0
test:
nop
nop
nop
nop
nop
jp test

View File

@ -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

View File

@ -2,7 +2,7 @@ bios:
@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/bios/README.md Normal file
View 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.

View 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

View File

@ -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

View File

@ -1,5 +0,0 @@
Sys_Beep: equ $0050
Sys_Print: equ $0010
Sys_Printc: equ $0020
Sys_Readc: equ $0030
Sys_Readline: equ $0040

View 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 ...