mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 14:18:06 +11:00
Add tools/emul
This commit is contained in:
parent
02808572e6
commit
193e6e066c
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "tools/emul/libz80"]
|
||||||
|
path = tools/emul/libz80
|
||||||
|
url = https://github.com/ggambetta/libz80.git
|
@ -1,9 +1,13 @@
|
|||||||
# Running Collapse OS on an emulated RC2014
|
# Running Collapse OS on an emulator
|
||||||
|
|
||||||
To give Collapse OS a whirl or to use emulation as a development tool, I
|
The quickest way to give Collapse OS a whirl is to use `tools/emul` which is
|
||||||
recommend using Alan Cox's [RC2014 emulator][rc2014-emul]. It runs Collapse OS
|
built around [libz80][libz80]. Everything is set up, you just have to run
|
||||||
fine. One caveat, however, is that it requires a ROM image bigger than 8K, so
|
`make`.
|
||||||
you have to pad the binary.
|
|
||||||
|
To emulate something at a lower level, I recommend using Alan Cox's [RC2014
|
||||||
|
emulator][rc2014-emul]. It runs Collapse OS fine but you have to write the
|
||||||
|
glue code yourself. One caveat, also, is that it requires a ROM image bigger
|
||||||
|
than 8K, so you have to pad the binary.
|
||||||
|
|
||||||
A working Makefile for a project with a glue code being called `main.asm` could
|
A working Makefile for a project with a glue code being called `main.asm` could
|
||||||
look like:
|
look like:
|
||||||
@ -27,4 +31,5 @@ look like:
|
|||||||
|
|
||||||
`CTRL+\` stops the emulation.
|
`CTRL+\` stops the emulation.
|
||||||
|
|
||||||
|
[libz80]: https://github.com/ggambetta/libz80
|
||||||
[rc2014-emul]: https://github.com/EtchedPixels/RC2014
|
[rc2014-emul]: https://github.com/EtchedPixels/RC2014
|
||||||
|
2
tools/emul/.gitignore
vendored
Normal file
2
tools/emul/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/shell
|
||||||
|
/shell-kernel.h
|
16
tools/emul/Makefile
Normal file
16
tools/emul/Makefile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.PHONY: all
|
||||||
|
all: shell
|
||||||
|
|
||||||
|
shell-kernel.h: shell_.asm
|
||||||
|
scas -o - -I ../../parts/z80 $< | ./bin2c.sh SHELL_KERNEL | tee $@ > /dev/null
|
||||||
|
|
||||||
|
shell: shell.c libz80/libz80.o shell-kernel.h
|
||||||
|
cc $< libz80/libz80.o -o $@
|
||||||
|
|
||||||
|
libz80/libz80.o: libz80/z80.c
|
||||||
|
make -C libz80/codegen opcodes
|
||||||
|
gcc -Wall -ansi -g -c -o libz80/libz80.o libz80/z80.c
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm shell shell-kernel.h
|
26
tools/emul/README.md
Normal file
26
tools/emul/README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# emul
|
||||||
|
|
||||||
|
This is an emulator for a virtual machine that is suitable for running Collapse
|
||||||
|
OS. The goal of this machine is not to emulate real hardware, but rather to
|
||||||
|
serve as a development platform. What we do here is we emulate the z80 part,
|
||||||
|
the 64K memory space and then hook some fake I/Os to stdin, stdout and a small
|
||||||
|
storage device that is suitable for Collapse OS's filesystem to run on.
|
||||||
|
|
||||||
|
Through that, it becomes easier to develop userspace applications for Collapse
|
||||||
|
OS.
|
||||||
|
|
||||||
|
We don't try to emulate real hardware to ease the development of device drivers
|
||||||
|
because so far, I don't see the advantage of emulation versus running code on
|
||||||
|
the real thing.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
First, make sure that the `libz80` git submodule is checked out. If not, run
|
||||||
|
`git submodule init && git submodule update`.
|
||||||
|
|
||||||
|
The Makefile in this folder has multiple targets that all use libz80 as its
|
||||||
|
core. For example, `make shell` will build `./shell`, a vanilla Collapse OS
|
||||||
|
shell. `make zasm` will build a `./zasm` executable, and so on.
|
||||||
|
|
||||||
|
See documentation is corresponding source files for usage documentation of
|
||||||
|
each target.
|
5
tools/emul/bin2c.sh
Executable file
5
tools/emul/bin2c.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "unsigned char $1[] = { "
|
||||||
|
xxd -i -
|
||||||
|
echo " };"
|
1
tools/emul/libz80
Submodule
1
tools/emul/libz80
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 8a1f935daa3c288b68121051e8e45068684f80a4
|
102
tools/emul/shell.c
Normal file
102
tools/emul/shell.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include "libz80/z80.h"
|
||||||
|
#include "shell-kernel.h"
|
||||||
|
|
||||||
|
/* Collapse OS vanilla shell
|
||||||
|
*
|
||||||
|
* Memory layout:
|
||||||
|
*
|
||||||
|
* 0x0000 - 0x3fff: ROM code from shell.asm
|
||||||
|
* 0x4000 - 0x4fff: Kernel memory
|
||||||
|
* 0x5000 - 0xffff: Userspace
|
||||||
|
*
|
||||||
|
* I/O Ports:
|
||||||
|
*
|
||||||
|
* 0 - stdin / stdout
|
||||||
|
*/
|
||||||
|
|
||||||
|
// in sync with shell.asm
|
||||||
|
#define RAMSTART 0x4000
|
||||||
|
#define STDIO_PORT 0x00
|
||||||
|
#define STDIN_ST_PORT 0x01
|
||||||
|
|
||||||
|
static Z80Context cpu;
|
||||||
|
static uint8_t mem[0xffff];
|
||||||
|
static int running;
|
||||||
|
|
||||||
|
static uint8_t io_read(int unused, uint16_t addr)
|
||||||
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
|
uint8_t c = getchar();
|
||||||
|
if (c == EOF) {
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void io_write(int unused, uint16_t addr, uint8_t val)
|
||||||
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
|
if (val == 0x04) { // CTRL+D
|
||||||
|
running = 0;
|
||||||
|
} else {
|
||||||
|
putchar(val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O write: %d / %d\n", addr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t mem_read(int unused, uint16_t addr)
|
||||||
|
{
|
||||||
|
return mem[addr];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mem_write(int unused, uint16_t addr, uint8_t val)
|
||||||
|
{
|
||||||
|
mem[addr] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Turn echo off: the shell takes care of its own echoing.
|
||||||
|
struct termios termInfo;
|
||||||
|
if (tcgetattr(0, &termInfo) == -1) {
|
||||||
|
printf("Can't setup terminal.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
termInfo.c_lflag &= ~ECHO;
|
||||||
|
termInfo.c_lflag &= ~ICANON;
|
||||||
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
|
|
||||||
|
|
||||||
|
// initialize memory
|
||||||
|
for (int i=0; i<sizeof(SHELL_KERNEL); i++) {
|
||||||
|
mem[i] = SHELL_KERNEL[i];
|
||||||
|
}
|
||||||
|
// Run!
|
||||||
|
running = 1;
|
||||||
|
Z80RESET(&cpu);
|
||||||
|
cpu.ioRead = io_read;
|
||||||
|
cpu.ioWrite = io_write;
|
||||||
|
cpu.memRead = mem_read;
|
||||||
|
cpu.memWrite = mem_write;
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
Z80Execute(&cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Done!\n");
|
||||||
|
termInfo.c_lflag |= ECHO;
|
||||||
|
termInfo.c_lflag |= ICANON;
|
||||||
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
|
return 0;
|
||||||
|
}
|
46
tools/emul/shell_.asm
Normal file
46
tools/emul/shell_.asm
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
; named shell_.asm to avoid infinite include loop.
|
||||||
|
RAMSTART .equ 0x4000
|
||||||
|
RAMEND .equ 0x5000
|
||||||
|
STDIO_PORT .equ 0x00
|
||||||
|
|
||||||
|
jr init
|
||||||
|
|
||||||
|
init:
|
||||||
|
di
|
||||||
|
; setup stack
|
||||||
|
ld hl, RAMEND
|
||||||
|
ld sp, hl
|
||||||
|
call shellInit
|
||||||
|
jp shellLoop
|
||||||
|
|
||||||
|
#include "core.asm"
|
||||||
|
.define STDIO_GETC call emulGetC
|
||||||
|
.define STDIO_PUTC call emulPutC
|
||||||
|
STDIO_RAMSTART .equ RAMEND
|
||||||
|
#include "stdio.asm"
|
||||||
|
|
||||||
|
BLOCKDEV_RAMSTART .equ STDIO_RAMEND
|
||||||
|
BLOCKDEV_COUNT .equ 1
|
||||||
|
#include "blockdev.asm"
|
||||||
|
; List of devices
|
||||||
|
.dw emulGetC, emulPutC, 0, 0
|
||||||
|
|
||||||
|
#include "blockdev_cmds.asm"
|
||||||
|
|
||||||
|
SHELL_RAMSTART .equ BLOCKDEV_RAMEND
|
||||||
|
.define SHELL_IO_GETC call blkGetCW
|
||||||
|
.define SHELL_IO_PUTC call blkPutC
|
||||||
|
SHELL_EXTRA_CMD_COUNT .equ 2
|
||||||
|
#include "shell.asm"
|
||||||
|
.dw blkBselCmd, blkSeekCmd
|
||||||
|
|
||||||
|
emulGetC:
|
||||||
|
; Blocks until a char is returned
|
||||||
|
in a, (STDIO_PORT)
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
||||||
|
|
||||||
|
emulPutC:
|
||||||
|
out (STDIO_PORT), a
|
||||||
|
ret
|
||||||
|
|
Loading…
Reference in New Issue
Block a user