mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 22:20:55 +11:00
Compare commits
No commits in common. "66dacd1816b2fe1086a4e614df37d587b2b7ae2d" and "105acedab8f70c5301e98414f378842a247d4d91" have entirely different histories.
66dacd1816
...
105acedab8
@ -13,11 +13,3 @@
|
|||||||
* [Using block devices](blockdev.md)
|
* [Using block devices](blockdev.md)
|
||||||
* [Using the filesystem](fs.md)
|
* [Using the filesystem](fs.md)
|
||||||
* [Assembling z80 source from the shell](zasm.md)
|
* [Assembling z80 source from the shell](zasm.md)
|
||||||
|
|
||||||
## Hardware
|
|
||||||
|
|
||||||
Some consolidated documentation about various hardware supported by Collapse OS.
|
|
||||||
Most of that information can already be found elsewhere, but the goal is to have
|
|
||||||
the most vital documentation in one single place.
|
|
||||||
|
|
||||||
* [TI-83+/TI-84+](ti8x.md)
|
|
||||||
|
38
doc/ti8x.md
38
doc/ti8x.md
@ -1,38 +0,0 @@
|
|||||||
# TI-83+/TI-84+
|
|
||||||
|
|
||||||
Texas Instruments is well known for its calculators. Among those, two models
|
|
||||||
are particularly interesting to us because they have a z80 CPU: the TI-83+ and
|
|
||||||
TI-84+ (the "+" is important).
|
|
||||||
|
|
||||||
They lack accessible I/O ports, but they have plenty of flash and RAM. Collapse
|
|
||||||
OS runs on it (see `recipes/ti84`).
|
|
||||||
|
|
||||||
I haven't opened one up yet, but apparently, they have limited scavenging value
|
|
||||||
because its z80 CPU is packaged in a TI-specific chip. Due to its sturdy design,
|
|
||||||
and its ample RAM and flash, we could imagine it becoming a valuable piece of
|
|
||||||
equipment if found intact.
|
|
||||||
|
|
||||||
The best pre-collapse ressource about it is
|
|
||||||
[WikiTI](http://wikiti.brandonw.net/index.php).
|
|
||||||
|
|
||||||
## Getting software on it
|
|
||||||
|
|
||||||
Getting software to run on it is a bit tricky because it needs to be signed
|
|
||||||
with TI-issued private keys. Those keys have long been found and are included
|
|
||||||
in `recipes/ti84`. With the help of the
|
|
||||||
[mktiupgrade](https://github.com/KnightOS/mktiupgrade), an upgrade file can be
|
|
||||||
prepared and then sent through the USB port with the help of
|
|
||||||
[tilp](http://lpg.ticalc.org/prj_tilp/).
|
|
||||||
|
|
||||||
That, however, requires a modern computing environment. As of now, there is no
|
|
||||||
way of installing Collapse OS on a TI-8X+ calculator from another Collapse OS
|
|
||||||
system.
|
|
||||||
|
|
||||||
Because it is not on the roadmap to implement complex cryptography in Collapse
|
|
||||||
OS, the plan is to build a series of pre-signed bootloader images. The
|
|
||||||
bootloader would then receive data through either the Link jack or the USB port
|
|
||||||
and write that to flash (I haven't verified that yet, but I hope that data
|
|
||||||
written to flash this way isn't verified cryptographically by the calculator).
|
|
||||||
|
|
||||||
As modern computing fades away, those pre-signed binaries would become opaque,
|
|
||||||
but at least, would allow bootstrapping from post-modern computers.
|
|
@ -8,8 +8,6 @@ screen. With a tiny font, the best we can get is a 24x10 console.
|
|||||||
|
|
||||||
There is, however, a built-in USB controller that might prove very handy.
|
There is, however, a built-in USB controller that might prove very handy.
|
||||||
|
|
||||||
[Further reading](../../doc/ti8x.md)
|
|
||||||
|
|
||||||
## Recipe
|
## Recipe
|
||||||
|
|
||||||
This recipe gets the Collapse OS BASIC shell to run on the TI-84+, using its LCD
|
This recipe gets the Collapse OS BASIC shell to run on the TI-84+, using its LCD
|
||||||
|
1
tools/emul/.gitignore
vendored
1
tools/emul/.gitignore
vendored
@ -8,4 +8,3 @@
|
|||||||
/cfsin/ed
|
/cfsin/ed
|
||||||
/cfsin/basic
|
/cfsin/basic
|
||||||
/cfsin/user.h
|
/cfsin/user.h
|
||||||
*.o
|
|
||||||
|
@ -31,18 +31,15 @@ zasm/zasm-bin.h: zasm/zasm.bin
|
|||||||
|
|
||||||
shell/shell: shell/shell.c libz80/libz80.o shell/kernel-bin.h
|
shell/shell: shell/shell.c libz80/libz80.o shell/kernel-bin.h
|
||||||
bshell/shell: bshell/shell.c libz80/libz80.o bshell/shell-bin.h
|
bshell/shell: bshell/shell.c libz80/libz80.o bshell/shell-bin.h
|
||||||
$(ZASMBIN): zasm/zasm.c emul.o libz80/libz80.o zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
|
$(ZASMBIN): zasm/zasm.c libz80/libz80.o zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
|
||||||
runbin/runbin: runbin/runbin.c libz80/libz80.o
|
runbin/runbin: runbin/runbin.c libz80/libz80.o
|
||||||
$(TARGETS):
|
$(TARGETS):
|
||||||
$(CC) $< emul.o libz80/libz80.o -o $@
|
$(CC) $< libz80/libz80.o -o $@
|
||||||
|
|
||||||
libz80/libz80.o: libz80/z80.c
|
libz80/libz80.o: libz80/z80.c
|
||||||
$(MAKE) -C libz80/codegen opcodes
|
$(MAKE) -C libz80/codegen opcodes
|
||||||
$(CC) -Wall -ansi -g -c -o libz80/libz80.o libz80/z80.c
|
$(CC) -Wall -ansi -g -c -o libz80/libz80.o libz80/z80.c
|
||||||
|
|
||||||
emul.o: emul.c
|
|
||||||
$(CC) -c -o emul.o emul.c
|
|
||||||
|
|
||||||
$(CFSPACK):
|
$(CFSPACK):
|
||||||
$(MAKE) -C ../cfspack
|
$(MAKE) -C ../cfspack
|
||||||
|
|
||||||
@ -60,4 +57,4 @@ updatebootstrap: $(ZASMBIN) $(INCCFS)
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGETS) $(SHELLAPPS) emul.o zasm/*-bin.h shell/*-bin.h
|
rm -f $(TARGETS) $(SHELLAPPS) zasm/*-bin.h shell/*-bin.h
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include "../emul.h"
|
#include "../libz80/z80.h"
|
||||||
#include "shell-bin.h"
|
#include "shell-bin.h"
|
||||||
|
|
||||||
/* Collapse OS shell with filesystem
|
/* Collapse OS shell with filesystem
|
||||||
@ -39,6 +39,8 @@
|
|||||||
// 3 means incomplete addr setting
|
// 3 means incomplete addr setting
|
||||||
#define FS_ADDR_PORT 0x02
|
#define FS_ADDR_PORT 0x02
|
||||||
|
|
||||||
|
static Z80Context cpu;
|
||||||
|
static uint8_t mem[0x10000] = {0};
|
||||||
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
|
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
|
||||||
static uint32_t fsdev_size = 0;
|
static uint32_t fsdev_size = 0;
|
||||||
static uint32_t fsdev_ptr = 0;
|
static uint32_t fsdev_ptr = 0;
|
||||||
@ -46,17 +48,16 @@ static uint32_t fsdev_ptr = 0;
|
|||||||
static int fsdev_addr_lvl = 0;
|
static int fsdev_addr_lvl = 0;
|
||||||
static int running;
|
static int running;
|
||||||
|
|
||||||
static uint8_t iord_stdio()
|
static uint8_t io_read(int unused, uint16_t addr)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
running = 0;
|
running = 0;
|
||||||
}
|
}
|
||||||
return (uint8_t)c;
|
return (uint8_t)c;
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsdata()
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -73,10 +74,7 @@ static uint8_t iord_fsdata()
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_ADDR_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsaddr()
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
return 3;
|
return 3;
|
||||||
} else if (fsdev_ptr > fsdev_size) {
|
} else if (fsdev_ptr > fsdev_size) {
|
||||||
@ -87,19 +85,22 @@ static uint8_t iord_fsaddr()
|
|||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iowr_stdio(uint8_t val)
|
static void io_write(int unused, uint16_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
if (val == 0x04) { // CTRL+D
|
if (val == 0x04) { // CTRL+D
|
||||||
running = 0;
|
running = 0;
|
||||||
} else {
|
} else {
|
||||||
putchar(val);
|
putchar(val);
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static void iowr_fsdata(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
||||||
return;
|
return;
|
||||||
@ -119,10 +120,7 @@ static void iowr_fsdata(uint8_t val)
|
|||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
|
fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_ADDR_PORT) {
|
||||||
|
|
||||||
static void iowr_fsaddr(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl == 0) {
|
if (fsdev_addr_lvl == 0) {
|
||||||
fsdev_ptr = val << 16;
|
fsdev_ptr = val << 16;
|
||||||
fsdev_addr_lvl = 1;
|
fsdev_addr_lvl = 1;
|
||||||
@ -133,6 +131,22 @@ static void iowr_fsaddr(uint8_t val)
|
|||||||
fsdev_ptr |= val;
|
fsdev_ptr |= val;
|
||||||
fsdev_addr_lvl = 0;
|
fsdev_addr_lvl = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, 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)
|
||||||
|
{
|
||||||
|
if (addr < RAMSTART) {
|
||||||
|
fprintf(stderr, "Writing to ROM (%d)!\n", addr);
|
||||||
|
}
|
||||||
|
mem[addr] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -165,27 +179,25 @@ int main()
|
|||||||
tcsetattr(0, TCSAFLUSH, &termInfo);
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
|
|
||||||
|
|
||||||
Machine *m = emul_init();
|
|
||||||
m->ramstart = RAMSTART;
|
|
||||||
m->iord[STDIO_PORT] = iord_stdio;
|
|
||||||
m->iord[FS_DATA_PORT] = iord_fsdata;
|
|
||||||
m->iord[FS_ADDR_PORT] = iord_fsaddr;
|
|
||||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
|
||||||
m->iowr[FS_DATA_PORT] = iowr_fsdata;
|
|
||||||
m->iowr[FS_ADDR_PORT] = iowr_fsaddr;
|
|
||||||
// initialize memory
|
// initialize memory
|
||||||
for (int i=0; i<sizeof(KERNEL); i++) {
|
for (int i=0; i<sizeof(KERNEL); i++) {
|
||||||
m->mem[i] = KERNEL[i];
|
mem[i] = KERNEL[i];
|
||||||
}
|
}
|
||||||
// Run!
|
// Run!
|
||||||
running = 1;
|
running = 1;
|
||||||
|
Z80RESET(&cpu);
|
||||||
|
cpu.ioRead = io_read;
|
||||||
|
cpu.ioWrite = io_write;
|
||||||
|
cpu.memRead = mem_read;
|
||||||
|
cpu.memWrite = mem_write;
|
||||||
|
|
||||||
while (running && emul_step());
|
while (running && !cpu.halted) {
|
||||||
|
Z80Execute(&cpu);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Done!\n");
|
printf("Done!\n");
|
||||||
termInfo.c_lflag |= ECHO;
|
termInfo.c_lflag |= ECHO;
|
||||||
termInfo.c_lflag |= ICANON;
|
termInfo.c_lflag |= ICANON;
|
||||||
tcsetattr(0, TCSAFLUSH, &termInfo);
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
emul_printdebug();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
/* Common code between shell, zasm and runbin.
|
|
||||||
|
|
||||||
They all run on the same kind of virtual machine: A z80 CPU, 64K of RAM/ROM.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "emul.h"
|
|
||||||
|
|
||||||
static Machine m;
|
|
||||||
|
|
||||||
static uint8_t io_read(int unused, uint16_t addr)
|
|
||||||
{
|
|
||||||
addr &= 0xff;
|
|
||||||
IORD fn = m.iord[addr];
|
|
||||||
if (fn != NULL) {
|
|
||||||
return fn();
|
|
||||||
} 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;
|
|
||||||
IOWR fn = m.iowr[addr];
|
|
||||||
if (fn != NULL) {
|
|
||||||
fn(val);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t mem_read(int unused, uint16_t addr)
|
|
||||||
{
|
|
||||||
return m.mem[addr];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mem_write(int unused, uint16_t addr, uint8_t val)
|
|
||||||
{
|
|
||||||
if (addr < m.ramstart) {
|
|
||||||
fprintf(stderr, "Writing to ROM (%d)!\n", addr);
|
|
||||||
}
|
|
||||||
m.mem[addr] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
Machine* emul_init()
|
|
||||||
{
|
|
||||||
memset(m.mem, 0, 0x10000);
|
|
||||||
m.ramstart = 0;
|
|
||||||
m.minsp = 0xffff;
|
|
||||||
for (int i=0; i<0x100; i++) {
|
|
||||||
m.iord[i] = NULL;
|
|
||||||
m.iowr[i] = NULL;
|
|
||||||
}
|
|
||||||
Z80RESET(&m.cpu);
|
|
||||||
m.cpu.memRead = mem_read;
|
|
||||||
m.cpu.memWrite = mem_write;
|
|
||||||
m.cpu.ioRead = io_read;
|
|
||||||
m.cpu.ioWrite = io_write;
|
|
||||||
return &m;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool emul_step()
|
|
||||||
{
|
|
||||||
if (!m.cpu.halted) {
|
|
||||||
Z80Execute(&m.cpu);
|
|
||||||
ushort newsp = m.cpu.R1.wr.SP;
|
|
||||||
if (newsp != 0 && newsp < m.minsp) {
|
|
||||||
m.minsp = newsp;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void emul_loop()
|
|
||||||
{
|
|
||||||
while (emul_step());
|
|
||||||
}
|
|
||||||
|
|
||||||
void emul_printdebug()
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Min SP: %04x\n", m.minsp);
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "libz80/z80.h"
|
|
||||||
|
|
||||||
typedef byte (*IORD) ();
|
|
||||||
typedef void (*IOWR) (byte data);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Z80Context cpu;
|
|
||||||
byte mem[0x10000];
|
|
||||||
// Set to non-zero to specify where ROM ends. Any memory write attempt
|
|
||||||
// below ramstart will trigger a warning.
|
|
||||||
ushort ramstart;
|
|
||||||
// The minimum value reached by SP at any point during execution.
|
|
||||||
ushort minsp;
|
|
||||||
// Array of 0x100 function pointers to IO read and write routines. Leave to
|
|
||||||
// NULL when IO port is unhandled.
|
|
||||||
IORD iord[0x100];
|
|
||||||
IOWR iowr[0x100];
|
|
||||||
} Machine;
|
|
||||||
|
|
||||||
Machine* emul_init();
|
|
||||||
bool emul_step();
|
|
||||||
void emul_loop();
|
|
||||||
void emul_printdebug();
|
|
@ -1,19 +1,44 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../emul.h"
|
#include "../libz80/z80.h"
|
||||||
|
|
||||||
/* runbin loads binary from stdin directly in memory address 0 then runs it
|
/* runbin loads binary from stdin directly in memory address 0 then runs it
|
||||||
* until it halts. The return code is the value of the register A at halt time.
|
* until it halts. The return code is the value of the register A at halt time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static Z80Context cpu;
|
||||||
|
static uint8_t mem[0x10000];
|
||||||
|
|
||||||
|
static uint8_t io_read(int unused, uint16_t addr)
|
||||||
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
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;
|
||||||
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
Machine *m = emul_init();
|
|
||||||
// read stdin in mem
|
// read stdin in mem
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
while (c != EOF) {
|
while (c != EOF) {
|
||||||
m->mem[i] = c & 0xff;
|
mem[i] = c & 0xff;
|
||||||
i++;
|
i++;
|
||||||
c = getchar();
|
c = getchar();
|
||||||
}
|
}
|
||||||
@ -21,7 +46,15 @@ int main()
|
|||||||
fprintf(stderr, "No input, aborting\n");
|
fprintf(stderr, "No input, aborting\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
emul_loop();
|
Z80RESET(&cpu);
|
||||||
return m->cpu.R1.br.A;
|
cpu.ioRead = io_read;
|
||||||
|
cpu.ioWrite = io_write;
|
||||||
|
cpu.memRead = mem_read;
|
||||||
|
cpu.memWrite = mem_write;
|
||||||
|
|
||||||
|
while (!cpu.halted) {
|
||||||
|
Z80Execute(&cpu);
|
||||||
|
}
|
||||||
|
return cpu.R1.br.A;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include "../emul.h"
|
#include "../libz80/z80.h"
|
||||||
#include "kernel-bin.h"
|
#include "kernel-bin.h"
|
||||||
|
|
||||||
/* Collapse OS shell with filesystem
|
/* Collapse OS shell with filesystem
|
||||||
@ -39,6 +39,8 @@
|
|||||||
// 3 means incomplete addr setting
|
// 3 means incomplete addr setting
|
||||||
#define FS_ADDR_PORT 0x02
|
#define FS_ADDR_PORT 0x02
|
||||||
|
|
||||||
|
static Z80Context cpu;
|
||||||
|
static uint8_t mem[0x10000] = {0};
|
||||||
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
|
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
|
||||||
static uint32_t fsdev_size = 0;
|
static uint32_t fsdev_size = 0;
|
||||||
static uint32_t fsdev_ptr = 0;
|
static uint32_t fsdev_ptr = 0;
|
||||||
@ -46,17 +48,16 @@ static uint32_t fsdev_ptr = 0;
|
|||||||
static int fsdev_addr_lvl = 0;
|
static int fsdev_addr_lvl = 0;
|
||||||
static int running;
|
static int running;
|
||||||
|
|
||||||
static uint8_t iord_stdio()
|
static uint8_t io_read(int unused, uint16_t addr)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
if (c == EOF) {
|
if (c == EOF) {
|
||||||
running = 0;
|
running = 0;
|
||||||
}
|
}
|
||||||
return (uint8_t)c;
|
return (uint8_t)c;
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsdata()
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
||||||
return 0;
|
return 0;
|
||||||
@ -73,10 +74,7 @@ static uint8_t iord_fsdata()
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_ADDR_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsaddr()
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
return 3;
|
return 3;
|
||||||
} else if (fsdev_ptr > fsdev_size) {
|
} else if (fsdev_ptr > fsdev_size) {
|
||||||
@ -87,19 +85,22 @@ static uint8_t iord_fsaddr()
|
|||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iowr_stdio(uint8_t val)
|
static void io_write(int unused, uint16_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
if (val == 0x04) { // CTRL+D
|
if (val == 0x04) { // CTRL+D
|
||||||
running = 0;
|
running = 0;
|
||||||
} else {
|
} else {
|
||||||
putchar(val);
|
putchar(val);
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static void iowr_fsdata(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl != 0) {
|
if (fsdev_addr_lvl != 0) {
|
||||||
fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
|
||||||
return;
|
return;
|
||||||
@ -119,10 +120,7 @@ static void iowr_fsdata(uint8_t val)
|
|||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
|
fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_ADDR_PORT) {
|
||||||
|
|
||||||
static void iowr_fsaddr(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_addr_lvl == 0) {
|
if (fsdev_addr_lvl == 0) {
|
||||||
fsdev_ptr = val << 16;
|
fsdev_ptr = val << 16;
|
||||||
fsdev_addr_lvl = 1;
|
fsdev_addr_lvl = 1;
|
||||||
@ -133,6 +131,22 @@ static void iowr_fsaddr(uint8_t val)
|
|||||||
fsdev_ptr |= val;
|
fsdev_ptr |= val;
|
||||||
fsdev_addr_lvl = 0;
|
fsdev_addr_lvl = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, 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)
|
||||||
|
{
|
||||||
|
if (addr < RAMSTART) {
|
||||||
|
fprintf(stderr, "Writing to ROM (%d)!\n", addr);
|
||||||
|
}
|
||||||
|
mem[addr] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -165,27 +179,25 @@ int main()
|
|||||||
tcsetattr(0, TCSAFLUSH, &termInfo);
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
|
|
||||||
|
|
||||||
Machine *m = emul_init();
|
|
||||||
m->ramstart = RAMSTART;
|
|
||||||
m->iord[STDIO_PORT] = iord_stdio;
|
|
||||||
m->iord[FS_DATA_PORT] = iord_fsdata;
|
|
||||||
m->iord[FS_ADDR_PORT] = iord_fsaddr;
|
|
||||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
|
||||||
m->iowr[FS_DATA_PORT] = iowr_fsdata;
|
|
||||||
m->iowr[FS_ADDR_PORT] = iowr_fsaddr;
|
|
||||||
// initialize memory
|
// initialize memory
|
||||||
for (int i=0; i<sizeof(KERNEL); i++) {
|
for (int i=0; i<sizeof(KERNEL); i++) {
|
||||||
m->mem[i] = KERNEL[i];
|
mem[i] = KERNEL[i];
|
||||||
}
|
}
|
||||||
// Run!
|
// Run!
|
||||||
running = 1;
|
running = 1;
|
||||||
|
Z80RESET(&cpu);
|
||||||
|
cpu.ioRead = io_read;
|
||||||
|
cpu.ioWrite = io_write;
|
||||||
|
cpu.memRead = mem_read;
|
||||||
|
cpu.memWrite = mem_write;
|
||||||
|
|
||||||
while (running && emul_step());
|
while (running && !cpu.halted) {
|
||||||
|
Z80Execute(&cpu);
|
||||||
|
}
|
||||||
|
|
||||||
printf("Done!\n");
|
printf("Done!\n");
|
||||||
termInfo.c_lflag |= ECHO;
|
termInfo.c_lflag |= ECHO;
|
||||||
termInfo.c_lflag |= ICANON;
|
termInfo.c_lflag |= ICANON;
|
||||||
tcsetattr(0, TCSAFLUSH, &termInfo);
|
tcsetattr(0, TCSAFLUSH, &termInfo);
|
||||||
emul_printdebug();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../emul.h"
|
#include "../libz80/z80.h"
|
||||||
#include "kernel-bin.h"
|
#include "kernel-bin.h"
|
||||||
#include "zasm-bin.h"
|
#include "zasm-bin.h"
|
||||||
|
|
||||||
@ -48,6 +48,8 @@
|
|||||||
// you want to spit this content to stderr.
|
// you want to spit this content to stderr.
|
||||||
//#define VERBOSE
|
//#define VERBOSE
|
||||||
|
|
||||||
|
static Z80Context cpu;
|
||||||
|
static uint8_t mem[0x10000];
|
||||||
// STDIN buffer, allows us to seek and tell
|
// STDIN buffer, allows us to seek and tell
|
||||||
static uint8_t inpt[STDIN_BUFSIZE];
|
static uint8_t inpt[STDIN_BUFSIZE];
|
||||||
static int inpt_size;
|
static int inpt_size;
|
||||||
@ -59,17 +61,16 @@ static uint32_t fsdev_size = 0;
|
|||||||
static uint32_t fsdev_ptr = 0;
|
static uint32_t fsdev_ptr = 0;
|
||||||
static uint8_t fsdev_seek_tell_cnt = 0;
|
static uint8_t fsdev_seek_tell_cnt = 0;
|
||||||
|
|
||||||
static uint8_t iord_stdio()
|
static uint8_t io_read(int unused, uint16_t addr)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
if (inpt_ptr < inpt_size) {
|
if (inpt_ptr < inpt_size) {
|
||||||
return inpt[inpt_ptr++];
|
return inpt[inpt_ptr++];
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == STDIN_SEEK_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_stdin_seek()
|
|
||||||
{
|
|
||||||
if (middle_of_seek_tell) {
|
if (middle_of_seek_tell) {
|
||||||
middle_of_seek_tell = 0;
|
middle_of_seek_tell = 0;
|
||||||
return inpt_ptr & 0xff;
|
return inpt_ptr & 0xff;
|
||||||
@ -80,19 +81,13 @@ static uint8_t iord_stdin_seek()
|
|||||||
middle_of_seek_tell = 1;
|
middle_of_seek_tell = 1;
|
||||||
return inpt_ptr >> 8;
|
return inpt_ptr >> 8;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsdata()
|
|
||||||
{
|
|
||||||
if (fsdev_ptr < fsdev_size) {
|
if (fsdev_ptr < fsdev_size) {
|
||||||
return fsdev[fsdev_ptr++];
|
return fsdev[fsdev_ptr++];
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_SEEK_PORT) {
|
||||||
|
|
||||||
static uint8_t iord_fsseek()
|
|
||||||
{
|
|
||||||
if (fsdev_seek_tell_cnt != 0) {
|
if (fsdev_seek_tell_cnt != 0) {
|
||||||
return fsdev_seek_tell_cnt;
|
return fsdev_seek_tell_cnt;
|
||||||
} else if (fsdev_ptr >= fsdev_size) {
|
} else if (fsdev_ptr >= fsdev_size) {
|
||||||
@ -100,18 +95,21 @@ static uint8_t iord_fsseek()
|
|||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O read: %d\n", addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iowr_stdio(uint8_t val)
|
static void io_write(int unused, uint16_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
|
addr &= 0xff;
|
||||||
|
if (addr == STDIO_PORT) {
|
||||||
// When mem-dumping, we don't output regular stuff.
|
// When mem-dumping, we don't output regular stuff.
|
||||||
#ifndef MEMDUMP
|
#ifndef MEMDUMP
|
||||||
putchar(val);
|
putchar(val);
|
||||||
#endif
|
#endif
|
||||||
}
|
} else if (addr == STDIN_SEEK_PORT) {
|
||||||
|
|
||||||
static void iowr_stdin_seek(uint8_t val)
|
|
||||||
{
|
|
||||||
if (middle_of_seek_tell) {
|
if (middle_of_seek_tell) {
|
||||||
inpt_ptr |= val;
|
inpt_ptr |= val;
|
||||||
middle_of_seek_tell = 0;
|
middle_of_seek_tell = 0;
|
||||||
@ -122,17 +120,11 @@ static void iowr_stdin_seek(uint8_t val)
|
|||||||
inpt_ptr = (val << 8) & 0xff00;
|
inpt_ptr = (val << 8) & 0xff00;
|
||||||
middle_of_seek_tell = 1;
|
middle_of_seek_tell = 1;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_DATA_PORT) {
|
||||||
|
|
||||||
static void iowr_fsdata(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_ptr < fsdev_size) {
|
if (fsdev_ptr < fsdev_size) {
|
||||||
fsdev[fsdev_ptr++] = val;
|
fsdev[fsdev_ptr++] = val;
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == FS_SEEK_PORT) {
|
||||||
|
|
||||||
static void iowr_fsseek(uint8_t val)
|
|
||||||
{
|
|
||||||
if (fsdev_seek_tell_cnt == 0) {
|
if (fsdev_seek_tell_cnt == 0) {
|
||||||
fsdev_ptr = val << 16;
|
fsdev_ptr = val << 16;
|
||||||
fsdev_seek_tell_cnt = 1;
|
fsdev_seek_tell_cnt = 1;
|
||||||
@ -146,13 +138,23 @@ static void iowr_fsseek(uint8_t val)
|
|||||||
fprintf(stderr, "FS seek %d\n", fsdev_ptr);
|
fprintf(stderr, "FS seek %d\n", fsdev_ptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
} else if (addr == STDERR_PORT) {
|
||||||
|
|
||||||
static void iowr_stderr(uint8_t val)
|
|
||||||
{
|
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
fputc(val, stderr);
|
fputc(val, stderr);
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, 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(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -161,22 +163,12 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "Too many args\n");
|
fprintf(stderr, "Too many args\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Machine *m = emul_init();
|
|
||||||
m->iord[STDIO_PORT] = iord_stdio;
|
|
||||||
m->iord[STDIN_SEEK_PORT] = iord_stdin_seek;
|
|
||||||
m->iord[FS_DATA_PORT] = iord_fsdata;
|
|
||||||
m->iord[FS_SEEK_PORT] = iord_fsseek;
|
|
||||||
m->iowr[STDIO_PORT] = iowr_stdio;
|
|
||||||
m->iowr[STDIN_SEEK_PORT] = iowr_stdin_seek;
|
|
||||||
m->iowr[FS_DATA_PORT] = iowr_fsdata;
|
|
||||||
m->iowr[FS_SEEK_PORT] = iowr_fsseek;
|
|
||||||
m->iowr[STDERR_PORT] = iowr_stderr;
|
|
||||||
// initialize memory
|
// initialize memory
|
||||||
for (int i=0; i<sizeof(KERNEL); i++) {
|
for (int i=0; i<sizeof(KERNEL); i++) {
|
||||||
m->mem[i] = KERNEL[i];
|
mem[i] = KERNEL[i];
|
||||||
}
|
}
|
||||||
for (int i=0; i<sizeof(USERSPACE); i++) {
|
for (int i=0; i<sizeof(USERSPACE); i++) {
|
||||||
m->mem[i+USER_CODE] = USERSPACE[i];
|
mem[i+USER_CODE] = USERSPACE[i];
|
||||||
}
|
}
|
||||||
char *init_org = "00";
|
char *init_org = "00";
|
||||||
if (argc >= 2) {
|
if (argc >= 2) {
|
||||||
@ -186,8 +178,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// glue.asm knows that it needs to fetch these arguments at this address.
|
// glue.asm knows that it needs to fetch these arguments at this address.
|
||||||
m->mem[0xff00] = init_org[0];
|
mem[0xff00] = init_org[0];
|
||||||
m->mem[0xff01] = init_org[1];
|
mem[0xff01] = init_org[1];
|
||||||
fsdev_size = 0;
|
fsdev_size = 0;
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
FILE *fp = fopen(argv[2], "r");
|
FILE *fp = fopen(argv[2], "r");
|
||||||
@ -217,18 +209,25 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
inpt_size = inpt_ptr;
|
inpt_size = inpt_ptr;
|
||||||
inpt_ptr = 0;
|
inpt_ptr = 0;
|
||||||
|
Z80RESET(&cpu);
|
||||||
|
cpu.ioRead = io_read;
|
||||||
|
cpu.ioWrite = io_write;
|
||||||
|
cpu.memRead = mem_read;
|
||||||
|
cpu.memWrite = mem_write;
|
||||||
|
|
||||||
emul_loop();
|
while (!cpu.halted) {
|
||||||
|
Z80Execute(&cpu);
|
||||||
|
}
|
||||||
#ifdef MEMDUMP
|
#ifdef MEMDUMP
|
||||||
for (int i=0; i<0x10000; i++) {
|
for (int i=0; i<0x10000; i++) {
|
||||||
putchar(mem[i]);
|
putchar(mem[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
int res = m->cpu.R1.br.A;
|
int res = cpu.R1.br.A;
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
int lineno = m->cpu.R1.wr.HL;
|
int lineno = cpu.R1.wr.HL;
|
||||||
int inclineno = m->cpu.R1.wr.DE;
|
int inclineno = cpu.R1.wr.DE;
|
||||||
if (inclineno) {
|
if (inclineno) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
|
Loading…
Reference in New Issue
Block a user