Compare commits
6 Commits
c-emulator
...
master
Author | SHA1 | Date | |
---|---|---|---|
f7afa69f66 | |||
bf91ff680d | |||
64d57bdb31 | |||
9960d81a44 | |||
7d89deaa02 | |||
169ea2a292 |
@ -35,8 +35,8 @@ There is an experimental and unfinished quick load function using a python termi
|
|||||||

|

|
||||||
|
|
||||||
## Emulator
|
## Emulator
|
||||||
The pat80 memory monitor (the os) can be run in a z80 emulator. This repository contains an emulator as submodule, already set up to run the os.
|
The pat80 memory monitor (the os) can be run in a z80 emulator. You can find a very simple one I wrote ad hoc in `pat80-emulator`. It's based (and depends on) the excellent [Z80 emulator library by redcode](https://github.com/redcode/Z80). Follow the instructions on `pat80-emulator/README.md` to build and run it.
|
||||||
To try it, head to `pat80-computer/software/z80-assembly/os/` and run `make run` to build the rom from assembly and start the emulator. You will see some windows showing the emulated computer's memory and register status and the pat80 memory monitor prompt.
|
The emulator requires a rom file to run. To obtain a pat80 rom, head to `pat80-computer/software/z80-assembly/os/` and run `make run` to build the rom from assembly and start the emulator. You will see some windows showing the emulated computer's memory and register status and the pat80 memory monitor prompt.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 100 KiB |
@ -1,3 +1,5 @@
|
|||||||
|
PAT80_EMU_PATH := "../../../../pat80-emulator/build/pat80-emulator"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@echo "Building PAT80 rom..."
|
@echo "Building PAT80 rom..."
|
||||||
@z80asm -i main.asm -o rom.bin || (exit 1)
|
@z80asm -i main.asm -o rom.bin || (exit 1)
|
||||||
@ -13,5 +15,9 @@ write: build
|
|||||||
@minipro -w rom.bin -p "AT28C64B"
|
@minipro -w rom.bin -p "AT28C64B"
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
@echo "Starting emulator..."
|
@echo "Starting emulator" $(PAT80_EMU_PATH)
|
||||||
@../../../../pat80-emulator/z80-python-emulator/src/z80sbc.py -b rom.bin
|
@if [ -f "$(PAT80_EMU_PATH)" ]; then\
|
||||||
|
"$(PAT80_EMU_PATH)" "rom.bin";\
|
||||||
|
else\
|
||||||
|
echo -e "\e[31mYou must build the emulator first. Check pat80-emulator/README.md\e[0m";\
|
||||||
|
fi
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
# Pat80 Operating System and Memory Monitor
|
# Pat80 Operating System and Memory Monitor
|
||||||
|
|
||||||
## Intro
|
## Intro
|
||||||
|
|
||||||
This folder contains the Pat80 Operating System.
|
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...).
|
It is a System Monitor that makes available also some system API to access hardware (monitor, sound, keyboard, parallel terminal...).
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
z80asm, minipro
|
|
||||||
|
z80asm
|
||||||
|
minipro (if you want to write to an EEPROM)
|
||||||
|
|
||||||
### Make
|
### Make
|
||||||
The os can be build issuing command `make`.
|
|
||||||
|
The os can be **built** issuing command `make build`.
|
||||||
Two files will be generated:
|
Two files will be generated:
|
||||||
- `rom.bin` is the rom file to be flashed on the eeprom
|
- `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/)
|
- `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.
|
|
||||||
|
The os can be **written to an EEPROM** with a minipro-compatible programmer issuing command `make write`. This runs the build and then tries to write the rom to a MiniPRO.
|
||||||
|
|
||||||
|
The os can otherwise be **runned in the emulator** issuing command `make run`. This requires to have the emulator executable already built (follow the instructions on `pat80-emulator/README.md` to build it).
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
; TM404A 40x4 characters LCD display (based on SN76489 chip) driver
|
||||||
|
; @author Daniele Verducci
|
||||||
|
; @language: Z80 ASM
|
||||||
|
;
|
||||||
|
;
|
||||||
|
; This file is part of Pat80 Memory Monitor.
|
||||||
|
;
|
||||||
|
; Pat80 Memory Monitor is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; Pat80 Memory Monitor is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with Pat80 Memory Monitor. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
;
|
||||||
|
|
||||||
|
; --------------------------------------------------------------------------
|
||||||
|
;
|
||||||
|
; This is meant to be used with a 40x4 character display (containing a dual hd44780-compatible controller) like the TM404A.
|
||||||
|
; This kind of display uses two controllers to overcome the hd44780 controllers limitation of 80 addressable characters.
|
||||||
|
; It is seen as two separate displays, and thus have two EN pins. A finer implementation would apply some deconding logic to
|
||||||
|
; an address bit to use a single port, but here we will use two different IO ports to save an IC.
|
||||||
|
;
|
||||||
|
; LCD config (IO port 0)
|
||||||
|
LCD4004_TOP2LINES_PORT: EQU IO_2
|
||||||
|
LCD4004_BOTTOM2LINES_PORT: EQU IO_3
|
||||||
|
|
||||||
|
|
||||||
|
; PIN CONNECTIONS
|
||||||
|
;
|
||||||
|
; PIN DESCRIPTION TO PAT80 BUS PIN INFO
|
||||||
|
; ---------------------------------------------------------------------------------------------------
|
||||||
|
; 1‐8 DB7‐DB0 DATA BUS
|
||||||
|
; 9 E1 (chip en 1) IOEN on LCD_TOP2LINES_PORT Chip enable for top 2 lines
|
||||||
|
; 10 R/W IOWR
|
||||||
|
; 11 RS A4 0: Command, 1: Data
|
||||||
|
; 12 V0 - Power supply for contrast (approx. +0.5V)
|
||||||
|
; 13 Vss - Ground
|
||||||
|
; 14 VDD - Power Supply Supply voltage for logic (+5.0V)
|
||||||
|
; 15 E2 (chip en 2) IOEN on LCD_BOTTOM2LINES_PORT Chip enable for bottom 2 lines
|
||||||
|
; 16 NC ‐ No Connect
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
; The 40x4 LCD memory map is the following:
|
||||||
|
;
|
||||||
|
; LINE CHIP EN PIN START ADDR END ADDR
|
||||||
|
; ----------------------------------------------------
|
||||||
|
; 1 9 0x00 (0) 0x27 (39)
|
||||||
|
; 2 9 0x40 (64) 0x67 (103)
|
||||||
|
; 3 15 0x00 (0) 0x27 (39)
|
||||||
|
; 4 15 0x40 (64) 0x67 (103)
|
||||||
|
;
|
||||||
|
; When we reach 0x40 on the first controller, we switch to the second.
|
||||||
|
; When we reach 0x40 on the second controller, we must shift
|
||||||
|
; all the lines up by one and position the cursor at 0x40.
|
||||||
|
|
||||||
|
; variables
|
||||||
|
LCD4004_VAR_SPACE: EQU DRV_IO_2_VAR_SPACE
|
||||||
|
LCD4004_CURSOR_POSITION_CONTROLLER: EQU DRV_IO_2_VAR_SPACE ; In which LCD controller is the cursor (0 or 1)
|
||||||
|
LCD4004_CURSOR_POSITION_CONTROLLER_MEMORY: EQU DRV_IO_2_VAR_SPACE + 1 ; Memory position of the cursor inside the controller's memory
|
||||||
|
|
||||||
|
; functions
|
||||||
|
|
||||||
|
; Initializes the driver and the LCD screen
|
||||||
|
LCD4004_Initialize:
|
||||||
|
; The following are documented as in the datasheet: RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
|
||||||
|
; Function set: 0 0 0 0 1 DL N F 0 0 (DL: 8-bit/4-bit, N: number of display lines 2/1, F: Font type 11dots/8dots)
|
||||||
|
; 0000111000 (8 bit, 2 lines)
|
||||||
|
|
||||||
|
; Display ON/OFF Control: 0 0 0 0 0 0 1 D C B (D: display on/off, C: cursor on/off, B: blinking cursor on/off)
|
||||||
|
; 0000001111 (display on, blinking cursor)
|
||||||
|
; Clear display
|
||||||
|
; 0000000001
|
||||||
|
|
||||||
|
|
||||||
|
; Move cursor (set DDRAM address in address counter)
|
||||||
|
LCD4004_MoveCursor:
|
||||||
|
; 0 0 1 AC6 AC5 AC4 AC3 AC2 AC1 AC0 (ACx: Address)
|
||||||
|
|
||||||
|
|
||||||
|
; Sends string
|
||||||
|
; @param BC Pointer to a null-terminated string first character
|
||||||
|
LCD4004_print:
|
||||||
|
ld a, (bc) ; bc is the pointer to passed string's first char
|
||||||
|
cp 0 ; compare A content with 0 (subtract 0 from value and set zero flag Z if result is 0)
|
||||||
|
ret z ; if prev compare is true (Z flag set), string is finished, return
|
||||||
|
out (TERM_DATA_REG),a ; output char
|
||||||
|
inc bc ; increment bc to move to next char
|
||||||
|
jp LCD4004_print
|
||||||
|
|
||||||
|
; Writes a single character
|
||||||
|
; @param A Value of character to print
|
||||||
|
LCD4004_printc:
|
||||||
|
out (TERM_DATA_REG),a
|
||||||
|
ret
|
||||||
|
|
@ -23,7 +23,7 @@ TERM_DATA_REG: EQU IO_0
|
|||||||
TERM_DATA_AVAIL_REG: EQU IO_0 + 1
|
TERM_DATA_AVAIL_REG: EQU IO_0 + 1
|
||||||
|
|
||||||
; variables
|
; variables
|
||||||
TERM_VAR_SPACE: EQU DRV_VAR_SPACE + 128
|
TERM_VAR_SPACE: EQU DRV_IO_0_VAR_SPACE
|
||||||
incoming_string: EQU TERM_VAR_SPACE
|
incoming_string: EQU TERM_VAR_SPACE
|
||||||
|
|
||||||
; functions
|
; functions
|
||||||
|
@ -30,8 +30,8 @@ jp Sysinit ; Startup vector: DO NOT MOVE! Must be the first instruction
|
|||||||
; I/O MAP
|
; I/O MAP
|
||||||
; I/O 0 (0x00 - 0x1F) Parallel terminal (uses addr 0x00 and 0x01)
|
; I/O 0 (0x00 - 0x1F) Parallel terminal (uses addr 0x00 and 0x01)
|
||||||
; I/O 1 (0x20 - 0x3F) Sound card (uses addr 0x20 only)
|
; I/O 1 (0x20 - 0x3F) Sound card (uses addr 0x20 only)
|
||||||
; I/O 2 (0x40 - 0x5F) PS2 Keyboard (uses 0x40 and 0x41)
|
; I/O 2 (0x40 - 0x5F) 40x4 LCD, first controller (lines 1 and 2)
|
||||||
; I/O 3 (0x60 - 0x7F)
|
; I/O 3 (0x60 - 0x7F) 40x4 LCD, second controller (lines 3 and 4)
|
||||||
; I/O 4 (0x80 - 0x9F)
|
; I/O 4 (0x80 - 0x9F)
|
||||||
; I/O 5 (0xA0 - 0xBF)
|
; I/O 5 (0xA0 - 0xBF)
|
||||||
; I/O 6 (0xC0 - 0xDF)
|
; I/O 6 (0xC0 - 0xDF)
|
||||||
@ -89,12 +89,20 @@ Sys_Beep:
|
|||||||
|
|
||||||
|
|
||||||
; MEMORY CONFIGURATION
|
; MEMORY CONFIGURATION
|
||||||
SYS_VAR_SPACE: EQU 0x8000
|
SYS_VAR_SPACE: EQU 0x8000 ; OS may allocate here memory for its own use
|
||||||
DRV_VAR_SPACE: EQU 0x9000
|
DRV_VAR_SPACE: EQU 0x9000 ; IO devices drivers may allocate here memory, each has a chunk of 512 bytes
|
||||||
APP_SPACE: EQU 0xA000
|
DRV_IO_0_VAR_SPACE: EQU DRV_VAR_SPACE
|
||||||
|
DRV_IO_1_VAR_SPACE: EQU DRV_IO_0_VAR_SPACE + 512
|
||||||
|
DRV_IO_2_VAR_SPACE: EQU DRV_IO_1_VAR_SPACE + 512
|
||||||
|
DRV_IO_3_VAR_SPACE: EQU DRV_IO_2_VAR_SPACE + 512
|
||||||
|
DRV_IO_4_VAR_SPACE: EQU DRV_IO_3_VAR_SPACE + 512
|
||||||
|
DRV_IO_5_VAR_SPACE: EQU DRV_IO_4_VAR_SPACE + 512
|
||||||
|
DRV_IO_6_VAR_SPACE: EQU DRV_IO_5_VAR_SPACE + 512
|
||||||
|
DRV_IO_7_VAR_SPACE: EQU DRV_IO_6_VAR_SPACE + 512
|
||||||
|
APP_SPACE: EQU 0xA000 ; App may only allocate between there and MEM_END
|
||||||
MEM_END: EQU 0xFFFF
|
MEM_END: EQU 0xFFFF
|
||||||
|
|
||||||
; SYSTEM CONFIGURATION
|
; DEVICES ("cards" on the IO bus) I/O space
|
||||||
IO_0: EQU 0x00
|
IO_0: EQU 0x00
|
||||||
IO_1: EQU 0x20
|
IO_1: EQU 0x20
|
||||||
IO_2: EQU 0x40
|
IO_2: EQU 0x40
|
||||||
@ -111,7 +119,7 @@ IO_7: EQU 0xE0
|
|||||||
|
|
||||||
;include 'drivers/hd44780.asm'
|
;include 'drivers/hd44780.asm'
|
||||||
;include 'drivers/keyboard.asm'
|
;include 'drivers/keyboard.asm'
|
||||||
include 'drivers/ps2_keyboard.asm'
|
;include 'drivers/ps2_keyboard.asm'
|
||||||
include 'drivers/arduino_terminal.asm'
|
include 'drivers/arduino_terminal.asm'
|
||||||
include 'drivers/sn76489.asm'
|
include 'drivers/sn76489.asm'
|
||||||
include 'monitor.asm'
|
include 'monitor.asm'
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
; S (SET) $pos $val Replaces byte at $pos with $val
|
; S (SET) $pos $val Replaces byte at $pos with $val
|
||||||
; L (LOAD) $pos $val
|
; L (LOAD) $pos $val
|
||||||
; R (RUN) $pos Starts executing code from $pos
|
; R (RUN) $pos Starts executing code from $pos
|
||||||
; A (ADB) Enters in Assembly Depoy Bridge mode: loads all the incoming bytes in application memory and starts executing.
|
|
||||||
; The commands are entered with a single letter and the program completes the command
|
; The commands are entered with a single letter and the program completes the command
|
||||||
|
|
||||||
include 'libs/strings.asm'
|
include 'libs/strings.asm'
|
||||||
@ -38,13 +37,13 @@ MON_COMMAND_SET: DB "SET",0
|
|||||||
MON_COMMAND_ZERO: DB "ZERO",0
|
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_MEMTEST: DB "MEMTEST",0
|
MON_COMMAND_MEMTEST: DB "MEMTEST",0
|
||||||
MON_COMMAND_QUIT: DB "QUIT",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\nMEMTEST checks ram boundaries\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 [ADDR] loads a program or data from tape at ADDR\nRUN [ADDR] executes code starting from ADDR\nADB starts Assembly Deploy Bridge\nMEMTEST checks ram boundaries\nQUIT exits",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_COMMAND_LOAD_PRESSPLAY: DB "Press play on tape",0
|
||||||
; MON_RAMTEST_INTRO: DB " Checking memory... ",0
|
; MON_RAMTEST_INTRO: DB " Checking memory... ",0
|
||||||
; MON_RAMTEST_RAMSTART: DB " Ram starts at 0x",0
|
; MON_RAMTEST_RAMSTART: DB " Ram starts at 0x",0
|
||||||
MON_DUMP_BYTES_LINES: EQU 8
|
MON_DUMP_BYTES_LINES: EQU 8
|
||||||
@ -84,9 +83,6 @@ Monitor_main:
|
|||||||
ld hl, MON_COMMAND_RUN
|
ld hl, MON_COMMAND_RUN
|
||||||
cp (hl)
|
cp (hl)
|
||||||
jp z, monitor_run
|
jp z, monitor_run
|
||||||
ld hl, MON_COMMAND_ADB
|
|
||||||
cp (hl)
|
|
||||||
jp z, monitor_adb
|
|
||||||
; ld hl, MON_COMMAND_MEMTEST
|
; ld hl, MON_COMMAND_MEMTEST
|
||||||
; cp (hl)
|
; cp (hl)
|
||||||
; jp z, monitor_memtest
|
; jp z, monitor_memtest
|
||||||
@ -298,10 +294,18 @@ monitor_zero: ; TODO: bugged, doesn't exit cycle
|
|||||||
ld (hl), 0 ; set byte to 0 in memory
|
ld (hl), 0 ; set byte to 0 in memory
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; Asks user for a memory position, then wait for data from tape and place it
|
||||||
|
; from the specified position on until it receives 4 consecutive 0x00 (EOF)
|
||||||
|
; @uses b, c, h, l
|
||||||
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
|
; Now read the memory address from the user
|
||||||
|
call monitor_arg_2byte ; returns the read bytes in hl
|
||||||
|
; Ask user to press play
|
||||||
|
ld bc, MON_COMMAND_LOAD_PRESSPLAY
|
||||||
|
; TODO: wait for data
|
||||||
jp monitor_main_loop
|
jp monitor_main_loop
|
||||||
|
|
||||||
monitor_run:
|
monitor_run:
|
||||||
@ -320,19 +324,6 @@ monitor_run:
|
|||||||
; execute code
|
; execute code
|
||||||
jp (hl)
|
jp (hl)
|
||||||
|
|
||||||
monitor_adb:
|
|
||||||
ld bc, MON_COMMAND_ADB + 1 ; autocomplete command
|
|
||||||
call Sys_Print
|
|
||||||
; start copying incoming data to application space
|
|
||||||
call monitor_copyTermToAppMem
|
|
||||||
; call monitor_enable_int ; re-enable interrupts
|
|
||||||
;jp APP_SPACE ; Start executing code
|
|
||||||
|
|
||||||
|
|
||||||
; ld bc, APP_SPACE
|
|
||||||
; call Sys_Print
|
|
||||||
jp monitor_main_loop
|
|
||||||
|
|
||||||
; Prints "0x" and read 1 hex byte (2 hex digits, e.g. 0x8C)
|
; Prints "0x" and read 1 hex byte (2 hex digits, e.g. 0x8C)
|
||||||
; Can be cancelled with Q/ENTER
|
; Can be cancelled with Q/ENTER
|
||||||
; @return a the read byte, b the exit code (0=valid byte in a, 1=Q, 2=ENTER)
|
; @return a the read byte, b the exit code (0=valid byte in a, 1=Q, 2=ENTER)
|
||||||
@ -524,53 +515,6 @@ monitor_printAsciiByte:
|
|||||||
call Sys_Printc
|
call Sys_Printc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; 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
|
|
||||||
monitor_copyTermToAppMem_loop:
|
|
||||||
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 ; reads a byte from terminal
|
|
||||||
ld (hl), a ; copy byte to memory
|
|
||||||
inc hl ; move to next memory position
|
|
||||||
dec bc ; decrement remaining bytes counter
|
|
||||||
; check if we reached the number of bytes to be transferred
|
|
||||||
ld a, b
|
|
||||||
cp 0
|
|
||||||
jp nz, monitor_copyTermToAppMem_loop ; continue loop
|
|
||||||
ld a, c
|
|
||||||
cp 0
|
|
||||||
jp nz, monitor_copyTermToAppMem_loop ; continue loop
|
|
||||||
; all bytes received, return
|
|
||||||
ret
|
|
||||||
|
|
||||||
monitor_copyTermToAppMem_loop_rec_head_byte_1:
|
|
||||||
; we are receiving first header byte: read byte and save to b
|
|
||||||
call Term_readb ; reads a byte from terminal
|
|
||||||
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 ; reads a byte from terminal
|
|
||||||
ld c, a
|
|
||||||
dec d
|
|
||||||
jp monitor_copyTermToAppMem_loop ; continue loop
|
|
||||||
|
|
||||||
; Runs a memory test to identify ram memory boundaries and check the ram is working.
|
; Runs a memory test to identify ram memory boundaries and check the ram is working.
|
||||||
; Starting from last memory position, writes 0xFF, reads it back, writes 0x00, reads it back.
|
; Starting from last memory position, writes 0xFF, reads it back, writes 0x00, reads it back.
|
||||||
; Exits when the first value differs from the written value (this may be caused by a bad ram
|
; Exits when the first value differs from the written value (this may be caused by a bad ram
|
||||||
|
116
pat80-computer/software/z80-assembly/os/tests/TM404A.asm
Normal file
116
pat80-computer/software/z80-assembly/os/tests/TM404A.asm
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
jp main ; Startup vector: DO NOT MOVE! Must be the first instruction
|
||||||
|
|
||||||
|
; Tests TM404A, on ports 2 and 3
|
||||||
|
|
||||||
|
IO_2: EQU 0x40
|
||||||
|
IO_3: EQU 0x60
|
||||||
|
|
||||||
|
LCD_TOP_INSTR_REG: EQU IO_2
|
||||||
|
LCD_TOP_DATA_REG: EQU IO_2 + 1
|
||||||
|
LCD_BOTTOM_INSTR_REG: EQU IO_3
|
||||||
|
LCD_BOTTOM_DATA_REG: EQU IO_3 + 1
|
||||||
|
|
||||||
|
|
||||||
|
; Inits the lcd display
|
||||||
|
LCD4004_init:
|
||||||
|
; --- Init first controller ---
|
||||||
|
|
||||||
|
; The following are documented as in the datasheet: RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
|
||||||
|
; Function set: 0 0 0 0 1 DL N F 0 0 (DL: 8-bit/4-bit, N: number of display lines 2/1, F: Font type 11dots/8dots)
|
||||||
|
; 0000111000 (8 bit, 2 lines)
|
||||||
|
ld a,0x38
|
||||||
|
out (LCD_TOP_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
; Display ON/OFF Control: 0 0 0 0 0 0 1 D C B (D: display on/off, C: cursor on/off, B: blinking cursor on/off)
|
||||||
|
; 0000001111 (display on, blinking cursor)
|
||||||
|
ld a,0x0F
|
||||||
|
out (LCD_TOP_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
; Clear display
|
||||||
|
; 0000000001
|
||||||
|
ld a,0x01
|
||||||
|
out (LCD_TOP_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
; --- Init second controller ---
|
||||||
|
|
||||||
|
; The following are documented as in the datasheet: RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
|
||||||
|
; Function set: 0 0 0 0 1 DL N F 0 0 (DL: 8-bit/4-bit, N: number of display lines 2/1, F: Font type 11dots/8dots)
|
||||||
|
; 0000111000 (8 bit, 2 lines)
|
||||||
|
ld a,0x38
|
||||||
|
out (LCD_BOTTOM_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
; Display ON/OFF Control: 0 0 0 0 0 0 1 D C B (D: display on/off, C: cursor on/off, B: blinking cursor on/off)
|
||||||
|
; 0000001111 (display on, blinking cursor)
|
||||||
|
ld a,0x0F
|
||||||
|
out (LCD_BOTTOM_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
; Clear display
|
||||||
|
; 0000000001
|
||||||
|
ld a,0x01
|
||||||
|
out (LCD_BOTTOM_INSTR_REG),a
|
||||||
|
|
||||||
|
call LCD4004_wait_busy_clear
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; Prints string
|
||||||
|
; @param BC Pointer to a null-terminated string first character
|
||||||
|
LCD4004_TOP_print:
|
||||||
|
ld a, (bc) ; bc is the pointer to passed string's first char
|
||||||
|
cp 0 ; compare A content with 0 (subtract 0 from value and set zero flag Z if result is 0)
|
||||||
|
ret z ; if prev compare is true (Z flag set), string is finished, return
|
||||||
|
out (LCD_TOP_DATA_REG),a ; output char
|
||||||
|
call LCD4004_wait_busy_clear ; wait for the lcd to execute (busy signal check)
|
||||||
|
inc bc ; increment bc to move to next char
|
||||||
|
jp LCD4004_TOP_print
|
||||||
|
|
||||||
|
; Prints string
|
||||||
|
; @param BC Pointer to a null-terminated string first character
|
||||||
|
LCD4004_BOTTOM_print:
|
||||||
|
ld a, (bc) ; bc is the pointer to passed string's first char
|
||||||
|
cp 0 ; compare A content with 0 (subtract 0 from value and set zero flag Z if result is 0)
|
||||||
|
ret z ; if prev compare is true (Z flag set), string is finished, return
|
||||||
|
out (LCD_BOTTOM_DATA_REG),a ; output char
|
||||||
|
call LCD4004_wait_busy_clear ; wait for the lcd to execute (busy signal check)
|
||||||
|
inc bc ; increment bc to move to next char
|
||||||
|
jp LCD4004_BOTTOM_print
|
||||||
|
|
||||||
|
; Waits for the busy flag to be clear, indicating the LCD controllers to have finished their work
|
||||||
|
LCD4004_wait_busy_clear:
|
||||||
|
ret
|
||||||
|
in a, (LCD_TOP_INSTR_REG) ; reads the status
|
||||||
|
rla ; busy flag is DB7, so we shift it into carry to check it
|
||||||
|
jp c, LCD4004_wait_busy_clear ; if carry is set, lcd is busy
|
||||||
|
in a, (LCD_BOTTOM_INSTR_REG) ; reads the status
|
||||||
|
rla ; busy flag is DB7, so we shift it into carry to check it
|
||||||
|
jp c, LCD4004_wait_busy_clear ; if carry is set, lcd is busy
|
||||||
|
ret
|
||||||
|
|
||||||
|
; --- TEST CODE ---
|
||||||
|
main:
|
||||||
|
TEST_STR_80: DB "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam augue tortor sed.",0 ; null terminated string
|
||||||
|
TEST_STR_85: DB "2Lorem ipsum dolor sit amet, consectetur adipiscing elit praesent pellentesque nisi.",0 ; null terminated string
|
||||||
|
|
||||||
|
; Init display
|
||||||
|
call LCD4004_init
|
||||||
|
|
||||||
|
; Write string on first 2 lines
|
||||||
|
ld bc, TEST_STR_80
|
||||||
|
call LCD4004_TOP_print
|
||||||
|
|
||||||
|
; Write long string on last 2 lines (to see how it wraps)
|
||||||
|
ld bc, TEST_STR_85
|
||||||
|
call LCD4004_BOTTOM_print
|
||||||
|
|
||||||
|
halt
|
@ -1,5 +1,7 @@
|
|||||||
# Pat80 emulator
|
# Pat80 emulator
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
Install the required Z80 emulator by redcode following the instructions for your Linux distribution at https://github.com/redcode/Z80
|
Install the required Z80 emulator by redcode following the instructions for your Linux distribution at https://github.com/redcode/Z80
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* PAT80 Emulator
|
* PAT80 Emulator
|
||||||
*
|
*
|
||||||
* Emulates a PAT80.
|
* Emulates a PAT80.
|
||||||
|
* Based on https://github.com/redcode/Z80
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Z/constants/pointer.h> /* Z_NULL */
|
#include <Z/constants/pointer.h> /* Z_NULL */
|
||||||
@ -29,6 +30,8 @@ typedef struct {
|
|||||||
Z80 cpu;
|
Z80 cpu;
|
||||||
WINDOW *terminal_win;
|
WINDOW *terminal_win;
|
||||||
WINDOW *status_win;
|
WINDOW *status_win;
|
||||||
|
WINDOW *lcd_top_win; // 40x4 LCD, top two lines
|
||||||
|
WINDOW *lcd_bottom_win; // 40x4 LCD, bottom two lines
|
||||||
} Machine;
|
} Machine;
|
||||||
|
|
||||||
|
|
||||||
@ -49,8 +52,8 @@ static zuint8 machine_cpu_in(Machine *self, zuint16 port) {
|
|||||||
// so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits
|
// so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits
|
||||||
// A4-A0 may be used by the single device, at its own discretion.
|
// A4-A0 may be used by the single device, at its own discretion.
|
||||||
zuint16 bitmask = 7; // 0000000000000111
|
zuint16 bitmask = 7; // 0000000000000111
|
||||||
int decoded = port & bitmask;
|
int ioDevice = port & bitmask;
|
||||||
if (decoded <= 0x1F) {
|
if (ioDevice <= 0x1F) {
|
||||||
// Port 0 (0x00 to 0x1F): terminal
|
// Port 0 (0x00 to 0x1F): terminal
|
||||||
// Read char from stin
|
// Read char from stin
|
||||||
char c = getch();
|
char c = getch();
|
||||||
@ -65,37 +68,45 @@ static zuint8 machine_cpu_in(Machine *self, zuint16 port) {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (decoded <= 0x3F) {
|
if (ioDevice <= 0x3F) {
|
||||||
// Port 1 (0x20 to 0x3F): sound card (sn76489)
|
// Port 1 (0x20 to 0x3F): sound card (sn76489)
|
||||||
wprintw(self->status_win, "sound_cmd[IN]: Not supported!\n");
|
wprintw(self->status_win, "sound_cmd[IN]: Not supported!\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x5F) {
|
if (ioDevice <= 0x5F) {
|
||||||
// Port 2 (0x40 to 0x5F)
|
// Port 2 (0x40 to 0x5F): LCD top 2 lines
|
||||||
|
if (port == 0x40 || port == 0x60) {
|
||||||
|
// TODO: Simulate busy flag and cursor position
|
||||||
|
return 0x00; // Busy flag clear, for now
|
||||||
|
}
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 2\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 2\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x7F) {
|
if (ioDevice <= 0x7F) {
|
||||||
// Port 3 (0x60 to 0x7F)
|
// Port 3 (0x60 to 0x7F): LCD bottom 2 lines
|
||||||
|
if (port == 0x0) {
|
||||||
|
// TODO: Simulate busy flag and cursor position
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 3\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 3\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x9F) {
|
if (ioDevice <= 0x9F) {
|
||||||
// Port 4 (0x80 to 0x9F)
|
// Port 4 (0x80 to 0x9F)
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 4\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 4\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x5F) {
|
if (ioDevice <= 0x5F) {
|
||||||
// Port 5 (0xA0 to 0xBF)
|
// Port 5 (0xA0 to 0xBF)
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 5\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 5\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x5F) {
|
if (ioDevice <= 0x5F) {
|
||||||
// Port 6 (0xC0 to 0xDF)
|
// Port 6 (0xC0 to 0xDF)
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 6\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 6\n");
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
if (decoded <= 0x5F) {
|
if (ioDevice <= 0x5F) {
|
||||||
// Port 7 (0xE0 to 0xFF)
|
// Port 7 (0xE0 to 0xFF)
|
||||||
wprintw(self->status_win, "IO_ERROR_IN: No device at port 7\n");
|
wprintw(self->status_win, "IO_ERROR_IN: No device at port 7\n");
|
||||||
} else {
|
} else {
|
||||||
@ -106,6 +117,8 @@ static zuint8 machine_cpu_in(Machine *self, zuint16 port) {
|
|||||||
refresh();
|
refresh();
|
||||||
wrefresh(self->terminal_win);
|
wrefresh(self->terminal_win);
|
||||||
wrefresh(self->status_win);
|
wrefresh(self->status_win);
|
||||||
|
wrefresh(self->lcd_top_win);
|
||||||
|
wrefresh(self->lcd_bottom_win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -115,29 +128,56 @@ static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value) {
|
|||||||
// so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits
|
// so the 3 most significant IO addr bits in this case are A7, A6, A5. The bits
|
||||||
// A4-A0 may be used by the single device, at its own discretion.
|
// A4-A0 may be used by the single device, at its own discretion.
|
||||||
zuint16 bitmask = 0xE0; // 0000000011100000
|
zuint16 bitmask = 0xE0; // 0000000011100000
|
||||||
int decoded = port & bitmask;
|
int ioDevice = port & bitmask;
|
||||||
if (decoded <= 0x1F) {
|
bitmask = 0x1F; // 0000000000011111
|
||||||
|
int ioAddrInsideDevice = port & bitmask;
|
||||||
|
wprintw(self->status_win, "[%#06x]DECODED[%#04x] - ", port, ioDevice);
|
||||||
|
if (ioDevice <= 0x1F) {
|
||||||
// Port 0 (0x00 to 0x1F): terminal
|
// Port 0 (0x00 to 0x1F): terminal
|
||||||
wprintw(self->terminal_win, "%c", value);
|
wprintw(self->terminal_win, "%c", value);
|
||||||
} else if (decoded <= 0x3F) {
|
} else if (ioDevice <= 0x3F) {
|
||||||
// Port 1 (0x20 to 0x3F): sound card (sn76489)
|
// Port 1 (0x20 to 0x3F): sound card (sn76489)
|
||||||
wprintw(self->status_win, "sound_cmd[%#04x]\n", value);
|
wprintw(self->status_win, "sound_cmd[%#04x]\n", value);
|
||||||
} else if (decoded <= 0x5F) {
|
} else if (ioDevice <= 0x5F) {
|
||||||
// Port 2 (0x40 to 0x5F)
|
// Port 2 (0x40 to 0x5F) and Port 3 (0x60 to 0x7F):
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 2\n");
|
// lcd display 40x4 (mod. TM404A, based on 2 KS0066 chips, each one controlling 2 rows,
|
||||||
} else if (decoded <= 0x7F) {
|
// top controller at port 2 and bottom at port 3).
|
||||||
// Port 3 (0x60 to 0x7F)
|
// Instruction register at each port first address, data register at second address
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 3\n");
|
if (ioAddrInsideDevice == 0) {
|
||||||
} else if (decoded <= 0x9F) {
|
// Port 2, A4 LOW = talking to LCD top 2 lines instruction register
|
||||||
|
wprintw(self->status_win, "lcd_top_cmd[%#04x]\n", value);
|
||||||
|
} else if (ioAddrInsideDevice == 1) {
|
||||||
|
// Port 2, A4 HIGH = talking to LCD top 2 lines data register (writing text to screen)
|
||||||
|
wprintw(self->status_win, "lcd_top_data[%#04x](%c)\n", value, value);
|
||||||
|
wprintw(self->lcd_top_win, "%c", value);
|
||||||
|
} else {
|
||||||
|
wprintw(self->status_win, "IO_ERROR_OUT: lcd (top controller) does not listen at addr %#04x\n", ioAddrInsideDevice);
|
||||||
|
}
|
||||||
|
} else if (ioDevice <= 0x7F) {
|
||||||
|
// Port 2 (0x40 to 0x5F) and Port 3 (0x60 to 0x7F):
|
||||||
|
// lcd display 40x4 (mod. TM404A, based on 2 KS0066 chips, each one controlling 2 rows,
|
||||||
|
// top controller at port 2 and bottom at port 3).
|
||||||
|
// Instruction register at each port first address, data register at second address
|
||||||
|
if (ioAddrInsideDevice == 0) {
|
||||||
|
// Port 3, A4 LOW = talking to LCD bottom 2 lines instruction register
|
||||||
|
wprintw(self->status_win, "lcd_bottom_cmd[%#04x]\n", value);
|
||||||
|
} else if (ioAddrInsideDevice == 1) {
|
||||||
|
// Port 3, A4 HIGH = talking to LCD bottom 2 lines data register (writing text to screen)
|
||||||
|
wprintw(self->status_win, "lcd_bottom_data[%#04x](%c)\n", value, value);
|
||||||
|
wprintw(self->lcd_bottom_win, "%c", value);
|
||||||
|
} else {
|
||||||
|
wprintw(self->status_win, "IO_ERROR_OUT: lcd (bottom controller) does not listen at addr %#04x\n", ioAddrInsideDevice);
|
||||||
|
}
|
||||||
|
} else if (ioDevice <= 0x9F) {
|
||||||
// Port 4 (0x80 to 0x9F)
|
// Port 4 (0x80 to 0x9F)
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 4\n");
|
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 4\n");
|
||||||
} else if (decoded <= 0x5F) {
|
} else if (ioDevice <= 0xBF) {
|
||||||
// Port 5 (0xA0 to 0xBF)
|
// Port 5 (0xA0 to 0xBF)
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 5\n");
|
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 5\n");
|
||||||
} else if (decoded <= 0x5F) {
|
} else if (ioDevice <= 0xDF) {
|
||||||
// Port 6 (0xC0 to 0xDF)
|
// Port 6 (0xC0 to 0xDF)
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 6\n");
|
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 6\n");
|
||||||
} else if (decoded <= 0x5F) {
|
} else if (ioDevice <= 0xFF) {
|
||||||
// Port 7 (0xE0 to 0xFF)
|
// Port 7 (0xE0 to 0xFF)
|
||||||
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 7\n");
|
wprintw(self->status_win, "IO_ERROR_OUT: No device at port 7\n");
|
||||||
} else {
|
} else {
|
||||||
@ -148,6 +188,21 @@ static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value) {
|
|||||||
refresh();
|
refresh();
|
||||||
wrefresh(self->terminal_win);
|
wrefresh(self->terminal_win);
|
||||||
wrefresh(self->status_win);
|
wrefresh(self->status_win);
|
||||||
|
wrefresh(self->lcd_top_win);
|
||||||
|
wrefresh(self->lcd_bottom_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_cpu_halt(Machine *self, unsigned char signal) {
|
||||||
|
wprintw(self->status_win, "HALTED (%d)\n", signal);
|
||||||
|
// Refresh all windows
|
||||||
|
refresh();
|
||||||
|
wrefresh(self->terminal_win);
|
||||||
|
wrefresh(self->status_win);
|
||||||
|
wrefresh(self->lcd_top_win);
|
||||||
|
wrefresh(self->lcd_bottom_win);
|
||||||
|
// Wait an ESC before exiting
|
||||||
|
while (getch() != 27) {}
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -160,7 +215,7 @@ void machine_initialize(Machine *self) {
|
|||||||
self->cpu.write = (Z80Write)machine_cpu_write;
|
self->cpu.write = (Z80Write)machine_cpu_write;
|
||||||
self->cpu.in = (Z80Read )machine_cpu_in;
|
self->cpu.in = (Z80Read )machine_cpu_in;
|
||||||
self->cpu.out = (Z80Write)machine_cpu_out;
|
self->cpu.out = (Z80Write)machine_cpu_out;
|
||||||
self->cpu.halt = Z_NULL;
|
self->cpu.halt = (Z80Halt)machine_cpu_halt;
|
||||||
self->cpu.nmia = Z_NULL;
|
self->cpu.nmia = Z_NULL;
|
||||||
self->cpu.inta = Z_NULL;
|
self->cpu.inta = Z_NULL;
|
||||||
self->cpu.int_fetch = Z_NULL;
|
self->cpu.int_fetch = Z_NULL;
|
||||||
@ -210,6 +265,7 @@ int main(int argc, char *argv[]) {
|
|||||||
start_color(); // Use colors
|
start_color(); // Use colors
|
||||||
init_pair(1, COLOR_WHITE, COLOR_BLUE); // Terminal window color
|
init_pair(1, COLOR_WHITE, COLOR_BLUE); // Terminal window color
|
||||||
init_pair(2, COLOR_YELLOW, COLOR_BLACK); // Status window color
|
init_pair(2, COLOR_YELLOW, COLOR_BLACK); // Status window color
|
||||||
|
init_pair(3, COLOR_BLACK, COLOR_GREEN); // LCD window color
|
||||||
int x,y;
|
int x,y;
|
||||||
getmaxyx(stdscr, y,x);
|
getmaxyx(stdscr, y,x);
|
||||||
|
|
||||||
@ -219,13 +275,19 @@ int main(int argc, char *argv[]) {
|
|||||||
/*zusize*/ .cycles = 0,
|
/*zusize*/ .cycles = 0,
|
||||||
/*Z80*/ .cpu = pat80Cpu,
|
/*Z80*/ .cpu = pat80Cpu,
|
||||||
.terminal_win = newwin(TERMINAL_HEIGHT, TERMINAL_WIDTH, INSTRUCTION_WINDOW_HEIGHT, 0),
|
.terminal_win = newwin(TERMINAL_HEIGHT, TERMINAL_WIDTH, INSTRUCTION_WINDOW_HEIGHT, 0),
|
||||||
.status_win = newwin(y, x - TERMINAL_WIDTH - SPACING_BETWEEN_WINDOWS, INSTRUCTION_WINDOW_HEIGHT, TERMINAL_WIDTH + SPACING_BETWEEN_WINDOWS)
|
.status_win = newwin(y, x - TERMINAL_WIDTH - SPACING_BETWEEN_WINDOWS, INSTRUCTION_WINDOW_HEIGHT, TERMINAL_WIDTH + SPACING_BETWEEN_WINDOWS), // To right of terminal window
|
||||||
|
.lcd_top_win = newwin(2, 40, INSTRUCTION_WINDOW_HEIGHT + TERMINAL_HEIGHT + SPACING_BETWEEN_WINDOWS, 0), // Below terminal window
|
||||||
|
.lcd_bottom_win = newwin(2, 40, INSTRUCTION_WINDOW_HEIGHT + TERMINAL_HEIGHT + SPACING_BETWEEN_WINDOWS + 2, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
wbkgd(pat80.terminal_win, COLOR_PAIR(1)); // Ncurses: set terminal window color
|
wbkgd(pat80.terminal_win, COLOR_PAIR(1)); // Ncurses: set terminal window color
|
||||||
wbkgd(pat80.status_win, COLOR_PAIR(2));
|
wbkgd(pat80.status_win, COLOR_PAIR(2));
|
||||||
|
wbkgd(pat80.lcd_top_win, COLOR_PAIR(3));
|
||||||
|
wbkgd(pat80.lcd_bottom_win, COLOR_PAIR(3));
|
||||||
scrollok(pat80.terminal_win, TRUE); // Ncurses: Allow scrolling when reached end of window
|
scrollok(pat80.terminal_win, TRUE); // Ncurses: Allow scrolling when reached end of window
|
||||||
scrollok(pat80.status_win, TRUE);
|
scrollok(pat80.status_win, TRUE);
|
||||||
|
scrollok(pat80.lcd_top_win, FALSE);
|
||||||
|
scrollok(pat80.lcd_bottom_win, FALSE);
|
||||||
attron(A_BOLD); // Print instructions
|
attron(A_BOLD); // Print instructions
|
||||||
printw("Emulator commands\n");
|
printw("Emulator commands\n");
|
||||||
attroff(A_BOLD);
|
attroff(A_BOLD);
|
||||||
@ -251,6 +313,8 @@ int main(int argc, char *argv[]) {
|
|||||||
// Stop ncurses
|
// Stop ncurses
|
||||||
delwin(pat80.terminal_win);
|
delwin(pat80.terminal_win);
|
||||||
delwin(pat80.status_win);
|
delwin(pat80.status_win);
|
||||||
|
delwin(pat80.lcd_top_win);
|
||||||
|
delwin(pat80.lcd_bottom_win);
|
||||||
endwin();
|
endwin();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
(kicad_pcb (version 20240108) (generator "pcbnew") (generator_version "8.0")
|
||||||
|
)
|
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"board": {
|
||||||
|
"active_layer": 0,
|
||||||
|
"active_layer_preset": "",
|
||||||
|
"auto_track_width": true,
|
||||||
|
"hidden_netclasses": [],
|
||||||
|
"hidden_nets": [],
|
||||||
|
"high_contrast_mode": 0,
|
||||||
|
"net_color_mode": 1,
|
||||||
|
"opacity": {
|
||||||
|
"images": 0.6,
|
||||||
|
"pads": 1.0,
|
||||||
|
"tracks": 1.0,
|
||||||
|
"vias": 1.0,
|
||||||
|
"zones": 0.6
|
||||||
|
},
|
||||||
|
"selection_filter": {
|
||||||
|
"dimensions": true,
|
||||||
|
"footprints": true,
|
||||||
|
"graphics": true,
|
||||||
|
"keepouts": true,
|
||||||
|
"lockedItems": false,
|
||||||
|
"otherItems": true,
|
||||||
|
"pads": true,
|
||||||
|
"text": true,
|
||||||
|
"tracks": true,
|
||||||
|
"vias": true,
|
||||||
|
"zones": true
|
||||||
|
},
|
||||||
|
"visible_items": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
12,
|
||||||
|
13,
|
||||||
|
15,
|
||||||
|
16,
|
||||||
|
17,
|
||||||
|
18,
|
||||||
|
19,
|
||||||
|
20,
|
||||||
|
21,
|
||||||
|
22,
|
||||||
|
23,
|
||||||
|
24,
|
||||||
|
25,
|
||||||
|
26,
|
||||||
|
27,
|
||||||
|
28,
|
||||||
|
29,
|
||||||
|
30,
|
||||||
|
32,
|
||||||
|
33,
|
||||||
|
34,
|
||||||
|
35,
|
||||||
|
36,
|
||||||
|
39,
|
||||||
|
40
|
||||||
|
],
|
||||||
|
"visible_layers": "fffffff_ffffffff",
|
||||||
|
"zone_display_mode": 0
|
||||||
|
},
|
||||||
|
"git": {
|
||||||
|
"repo_password": "",
|
||||||
|
"repo_type": "",
|
||||||
|
"repo_username": "",
|
||||||
|
"ssh_key": ""
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"filename": "4004_lcd_display.kicad_prl",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"files": []
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,392 @@
|
|||||||
|
{
|
||||||
|
"board": {
|
||||||
|
"3dviewports": [],
|
||||||
|
"design_settings": {
|
||||||
|
"defaults": {},
|
||||||
|
"diff_pair_dimensions": [],
|
||||||
|
"drc_exclusions": [],
|
||||||
|
"rules": {},
|
||||||
|
"track_widths": [],
|
||||||
|
"via_dimensions": []
|
||||||
|
},
|
||||||
|
"ipc2581": {
|
||||||
|
"dist": "",
|
||||||
|
"distpn": "",
|
||||||
|
"internal_id": "",
|
||||||
|
"mfg": "",
|
||||||
|
"mpn": ""
|
||||||
|
},
|
||||||
|
"layer_presets": [],
|
||||||
|
"viewports": []
|
||||||
|
},
|
||||||
|
"boards": [],
|
||||||
|
"cvpcb": {
|
||||||
|
"equivalence_files": []
|
||||||
|
},
|
||||||
|
"erc": {
|
||||||
|
"erc_exclusions": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"pin_map": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"rule_severities": {
|
||||||
|
"bus_definition_conflict": "error",
|
||||||
|
"bus_entry_needed": "error",
|
||||||
|
"bus_to_bus_conflict": "error",
|
||||||
|
"bus_to_net_conflict": "error",
|
||||||
|
"conflicting_netclasses": "error",
|
||||||
|
"different_unit_footprint": "error",
|
||||||
|
"different_unit_net": "error",
|
||||||
|
"duplicate_reference": "error",
|
||||||
|
"duplicate_sheet_names": "error",
|
||||||
|
"endpoint_off_grid": "warning",
|
||||||
|
"extra_units": "error",
|
||||||
|
"global_label_dangling": "warning",
|
||||||
|
"hier_label_mismatch": "error",
|
||||||
|
"label_dangling": "error",
|
||||||
|
"lib_symbol_issues": "warning",
|
||||||
|
"missing_bidi_pin": "warning",
|
||||||
|
"missing_input_pin": "warning",
|
||||||
|
"missing_power_pin": "error",
|
||||||
|
"missing_unit": "warning",
|
||||||
|
"multiple_net_names": "warning",
|
||||||
|
"net_not_bus_member": "warning",
|
||||||
|
"no_connect_connected": "warning",
|
||||||
|
"no_connect_dangling": "warning",
|
||||||
|
"pin_not_connected": "error",
|
||||||
|
"pin_not_driven": "error",
|
||||||
|
"pin_to_pin": "warning",
|
||||||
|
"power_pin_not_driven": "error",
|
||||||
|
"similar_labels": "warning",
|
||||||
|
"simulation_model_issue": "ignore",
|
||||||
|
"unannotated": "error",
|
||||||
|
"unit_value_mismatch": "error",
|
||||||
|
"unresolved_variable": "error",
|
||||||
|
"wire_dangling": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libraries": {
|
||||||
|
"pinned_footprint_libs": [],
|
||||||
|
"pinned_symbol_libs": []
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"filename": "4004_lcd_display.kicad_pro",
|
||||||
|
"version": 1
|
||||||
|
},
|
||||||
|
"net_settings": {
|
||||||
|
"classes": [
|
||||||
|
{
|
||||||
|
"bus_width": 12,
|
||||||
|
"clearance": 0.2,
|
||||||
|
"diff_pair_gap": 0.25,
|
||||||
|
"diff_pair_via_gap": 0.25,
|
||||||
|
"diff_pair_width": 0.2,
|
||||||
|
"line_style": 0,
|
||||||
|
"microvia_diameter": 0.3,
|
||||||
|
"microvia_drill": 0.1,
|
||||||
|
"name": "Default",
|
||||||
|
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||||
|
"track_width": 0.2,
|
||||||
|
"via_diameter": 0.6,
|
||||||
|
"via_drill": 0.3,
|
||||||
|
"wire_width": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"net_colors": null,
|
||||||
|
"netclass_assignments": null,
|
||||||
|
"netclass_patterns": []
|
||||||
|
},
|
||||||
|
"pcbnew": {
|
||||||
|
"last_paths": {
|
||||||
|
"gencad": "",
|
||||||
|
"idf": "",
|
||||||
|
"netlist": "",
|
||||||
|
"plot": "",
|
||||||
|
"pos_files": "",
|
||||||
|
"specctra_dsn": "",
|
||||||
|
"step": "",
|
||||||
|
"svg": "",
|
||||||
|
"vrml": ""
|
||||||
|
},
|
||||||
|
"page_layout_descr_file": ""
|
||||||
|
},
|
||||||
|
"schematic": {
|
||||||
|
"annotate_start_num": 0,
|
||||||
|
"bom_export_filename": "",
|
||||||
|
"bom_fmt_presets": [],
|
||||||
|
"bom_fmt_settings": {
|
||||||
|
"field_delimiter": ",",
|
||||||
|
"keep_line_breaks": false,
|
||||||
|
"keep_tabs": false,
|
||||||
|
"name": "CSV",
|
||||||
|
"ref_delimiter": ",",
|
||||||
|
"ref_range_delimiter": "",
|
||||||
|
"string_delimiter": "\""
|
||||||
|
},
|
||||||
|
"bom_presets": [],
|
||||||
|
"bom_settings": {
|
||||||
|
"exclude_dnp": false,
|
||||||
|
"fields_ordered": [
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Reference",
|
||||||
|
"name": "Reference",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "Value",
|
||||||
|
"name": "Value",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Datasheet",
|
||||||
|
"name": "Datasheet",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Footprint",
|
||||||
|
"name": "Footprint",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": false,
|
||||||
|
"label": "Qty",
|
||||||
|
"name": "${QUANTITY}",
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_by": true,
|
||||||
|
"label": "DNP",
|
||||||
|
"name": "${DNP}",
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filter_string": "",
|
||||||
|
"group_symbols": true,
|
||||||
|
"name": "Grouped By Value",
|
||||||
|
"sort_asc": true,
|
||||||
|
"sort_field": "Riferimento"
|
||||||
|
},
|
||||||
|
"connection_grid_size": 50.0,
|
||||||
|
"drawing": {
|
||||||
|
"dashed_lines_dash_length_ratio": 12.0,
|
||||||
|
"dashed_lines_gap_length_ratio": 3.0,
|
||||||
|
"default_line_thickness": 6.0,
|
||||||
|
"default_text_size": 50.0,
|
||||||
|
"field_names": [],
|
||||||
|
"intersheets_ref_own_page": false,
|
||||||
|
"intersheets_ref_prefix": "",
|
||||||
|
"intersheets_ref_short": false,
|
||||||
|
"intersheets_ref_show": false,
|
||||||
|
"intersheets_ref_suffix": "",
|
||||||
|
"junction_size_choice": 3,
|
||||||
|
"label_size_ratio": 0.375,
|
||||||
|
"operating_point_overlay_i_precision": 3,
|
||||||
|
"operating_point_overlay_i_range": "~A",
|
||||||
|
"operating_point_overlay_v_precision": 3,
|
||||||
|
"operating_point_overlay_v_range": "~V",
|
||||||
|
"overbar_offset_ratio": 1.23,
|
||||||
|
"pin_symbol_size": 25.0,
|
||||||
|
"text_offset_ratio": 0.15
|
||||||
|
},
|
||||||
|
"legacy_lib_dir": "",
|
||||||
|
"legacy_lib_list": [],
|
||||||
|
"meta": {
|
||||||
|
"version": 1
|
||||||
|
},
|
||||||
|
"net_format_name": "",
|
||||||
|
"page_layout_descr_file": "",
|
||||||
|
"plot_directory": "",
|
||||||
|
"spice_current_sheet_as_root": false,
|
||||||
|
"spice_external_command": "spice \"%I\"",
|
||||||
|
"spice_model_current_sheet_as_root": true,
|
||||||
|
"spice_save_all_currents": false,
|
||||||
|
"spice_save_all_dissipations": false,
|
||||||
|
"spice_save_all_voltages": false,
|
||||||
|
"subpart_first_id": 65,
|
||||||
|
"subpart_id_separator": 0
|
||||||
|
},
|
||||||
|
"sheets": [
|
||||||
|
[
|
||||||
|
"b60673c4-5448-4b81-8c25-50d47b52f4a5",
|
||||||
|
"Root"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"text_variables": {}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user