Skip to content

Commit e33b7e8

Browse files
committed
main: wire parport CLI flags (-parport_test / -parport_out / -parport_in)
Signed-off-by: Sol Astrius <sol@astrius.ink>
1 parent 50af5d1 commit e33b7e8

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

src/main.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2525

2626
#include <rvvm/rvvm.h>
2727

28+
#include <util/threading.h>
2829
#include <util/utils.h>
2930

31+
#include <stdio.h> // parport sink/source use FILE* on all targets
32+
3033
#include <core/rvvm_isolation.h>
3134
#include <core/gdbstub.h>
3235
#include <core/rvvm_user.h>
@@ -37,6 +40,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
3740
#include <devices/i2c-oc.h>
3841
#include <devices/ns16550a.h>
3942
#include <devices/nvme.h>
43+
#include <devices/parport-pci.h>
4044
#include <devices/pci-bus.h>
4145
#include <devices/pci-vfio.h>
4246
#include <devices/riscv-aclint.h>
@@ -199,6 +203,9 @@ static void rvvm_print_help(void)
199203
" -ata ... Explicitly attach storage image as ATA (IDE) device\n"
200204
" -nogui Disable display GUI\n"
201205
" -nosound Disable sound support\n"
206+
" -parport_test Attach an emulated NetMos 9900 PCI parallel port\n"
207+
" -parport_out ... File to receive parport output (default: /tmp/rvvm-parport0.out)\n"
208+
" -parport_in ... File/fifo to source parport reverse-channel input from\n"
202209
" -nonet Disable networking\n"
203210
" -serial ... Add more serial ports (Via pty/pipe path), or null\n"
204211
" -dtb ... Pass custom Device Tree Blob to the machine\n"
@@ -212,6 +219,42 @@ static void rvvm_print_help(void)
212219
print_stderr(help);
213220
}
214221

222+
// Bridge for the -parport_test default backend: each strobed byte from the
223+
// guest's parallel port is appended to a host file. user_data carries the
224+
// FILE* opened in rvvm_cli_configure. Called outside the device's lock so
225+
// the write may safely block briefly.
226+
static void parport_main_write_fn(void* user_data, uint8_t byte)
227+
{
228+
FILE* fp = (FILE*)user_data;
229+
if (fp) fputc(byte, fp);
230+
}
231+
232+
// Reader thread for -parport_in: blocks on read() from a host file or
233+
// fifo and pushes each byte into the device's reverse-channel ring.
234+
// EOF / error ends the thread, leaving any further guest reads to see
235+
// nFault asserted (end-of-data) on Status.
236+
typedef struct {
237+
pci_dev_t* dev;
238+
FILE* fp;
239+
} parport_in_ctx_t;
240+
241+
static void* parport_in_thread(void* arg)
242+
{
243+
parport_in_ctx_t* ctx = arg;
244+
int c;
245+
while ((c = fgetc(ctx->fp)) != EOF) {
246+
// Spin until the ring has space. Slow guest readers shouldn't
247+
// burn the CPU, so back off when full — sched_yield is plenty
248+
// for ringbuffer pacing.
249+
while (!parport_pci_inject_byte(ctx->dev, (uint8_t)c)) {
250+
rvvm_sched_yield();
251+
}
252+
}
253+
fclose(ctx->fp);
254+
free(ctx);
255+
return NULL;
256+
}
257+
215258
static bool rvvm_cli_configure(rvvm_machine_t* machine, const char* bios, tap_dev_t* tap)
216259
{
217260
UNUSED(tap);
@@ -374,6 +417,39 @@ static int rvvm_cli_main(int argc, char** argv)
374417
sound_hda_init_auto(machine);
375418
}
376419

420+
if (rvvm_has_arg("parport_test")) {
421+
// Default backend writes guest parport output to a host file.
422+
// Override path with -parport_out <path>; /dev/stdout dumps to
423+
// the controlling terminal.
424+
const char* path = rvvm_getarg("parport_out");
425+
if (path == NULL) path = "/tmp/rvvm-parport0.out";
426+
FILE* fp = fopen(path, "wb");
427+
pci_dev_t* parport_dev = NULL;
428+
if (fp) {
429+
setvbuf(fp, NULL, _IONBF, 0); // unbuffered — bytes appear immediately
430+
rvvm_info("parport: writes go to %s", path);
431+
parport_dev = parport_pci_init_auto(machine, parport_main_write_fn, fp);
432+
} else {
433+
rvvm_warn("parport: failed to open %s, attaching with no backend", path);
434+
parport_dev = parport_pci_init_auto(machine, NULL, NULL);
435+
}
436+
// Reverse channel: feed bytes from -parport_in <path> into the
437+
// ring. Useful for guest-side dd/cat tests of bidirectional 1284.
438+
const char* in_path = rvvm_getarg("parport_in");
439+
if (parport_dev && in_path) {
440+
FILE* in_fp = fopen(in_path, "rb");
441+
if (in_fp) {
442+
rvvm_info("parport: reverse-channel input from %s", in_path);
443+
parport_in_ctx_t* ctx = safe_new_obj(parport_in_ctx_t);
444+
ctx->dev = parport_dev;
445+
ctx->fp = in_fp;
446+
rvvm_thread_detach(rvvm_thread_create(parport_in_thread, ctx));
447+
} else {
448+
rvvm_warn("parport: failed to open %s for reverse channel", in_path);
449+
}
450+
}
451+
}
452+
377453
tap_dev_t* tap = NULL;
378454
#ifdef USE_NET
379455
if (!rvvm_has_arg("nonet")) {

0 commit comments

Comments
 (0)