basic framework for json validation

This commit is contained in:
folkert van heusden 2024-03-28 00:51:06 +01:00
parent 81f7d8f1ad
commit c62aadd318
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
7 changed files with 143 additions and 26 deletions

View file

@ -95,3 +95,8 @@ pkg_check_modules(PANEL REQUIRED panel)
target_link_libraries(kek ${PANEL_LIBRARIES})
target_include_directories(kek PUBLIC ${PANEL_INCLUDE_DIRS})
target_compile_options(kek PUBLIC ${PANEL_CFLAGS_OTHER})
pkg_check_modules(JANSSON REQUIRED jansson)
target_link_libraries(kek ${JANSSON_LIBRARIES})
target_include_directories(kek PUBLIC ${JANSSON_INCLUDE_DIRS})
target_compile_options(kek PUBLIC ${JANSSON_CFLAGS_OTHER})

12
cpu.cpp
View file

@ -1637,7 +1637,6 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
{
DOLOG(debug, true, "*** CPU::TRAP %o, new-ipl: %d, is-interrupt: %d ***", vector, new_ipl, is_interrupt);
int processing_trap_depth = 0;
uint16_t before_psw = 0;
uint16_t before_pc = 0;
@ -1650,14 +1649,15 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
if (processing_trap_depth >= 2) {
DOLOG(debug, true, "Trap depth %d", processing_trap_depth);
if (processing_trap_depth >= 3) {
*event = EVENT_HALT;
break;
}
if (kernel_mode)
vector = 4;
setRegister(6, 04);
if (processing_trap_depth >= 3) {
// TODO: halt?
}
}
else {
before_psw = getPSW();
@ -1689,6 +1689,8 @@ void cpu::trap(uint16_t vector, const int new_ipl, const bool is_interrupt)
pushStack(before_psw);
pushStack(before_pc);
processing_trap_depth = 0;
// if we reach this point then the trap was processed without causing
// another trap
break;

1
cpu.h
View file

@ -35,6 +35,7 @@ private:
uint16_t psw { 0 };
uint16_t fpsr { 0 };
uint16_t stackLimitRegister { 0377 };
int processing_trap_depth { 0 };
uint64_t instruction_count { 0 };
uint64_t running_since { 0 };

View file

@ -4,5 +4,6 @@
#include "bus.h"
#include "console.h"
int disassemble(cpu *const c, console *const cnsl, const uint16_t pc, const bool instruction_only);
void debugger(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing);
void run_bic(console *const cnsl, bus *const b, std::atomic_uint32_t *const stop_event, const bool tracing, const uint16_t bic_start);

View file

@ -13,25 +13,29 @@ class PDP1170_wrapper(PDP1170):
self.reset_mem_transactions_dict()
def reset_mem_transactions_dict(self):
self.mem_transactions_w = dict()
self.mem_transactions = dict()
def get_mem_transactions_dict(self):
return self.mem_transactions_w
return self.mem_transactions
def physRW(self, physaddr, value=None):
if value == None: # read
return super().physRW(physaddr, value)
self.mem_transactions[physaddr] = random.randint(0, 65536)
return super().physRW(physaddr, self.mem_transactions[physaddr])
self.mem_transactions_w[physaddr] = value
self.mem_transactions[physaddr] = value
super().physRW(physaddr, value)
def physRW_N(self, physaddr, nwords, words=None):
temp_addr = physaddr
if words == None:
for i in range(nwords):
physRW(temp_addr, random.randint(0, 65536))
temp_addr += 2
return super().physRW_N(physaddr, nwords)
temp_addr = physaddr
for w in words:
self.mem_transactions_w[temp_addr] = w
self.mem_transactions[temp_addr] = w
temp_addr += 2
super().physRW_N(physaddr, nwords, words=words)
@ -40,8 +44,8 @@ class test_generator:
def _invoke_bp(self, a, i):
return True
def _run_test(self, mem_setup, reg_setup):
p = PDP1170_wrapper()
def _run_test(self, addr, mem_setup, reg_setup, psw):
p = PDP1170_wrapper(loglevel='DEBUG')
for a, v in mem_setup:
p.mmu.wordRW(a, v)
@ -51,19 +55,23 @@ class test_generator:
p.reset_mem_transactions_dict()
p.run(breakpoint=self._invoke_bp)
p._syncregs()
p.run_steps(pc=addr, steps=1)
p._syncregs()
return p
def create_test(self):
out = { }
addr = random.randint(0, 65536) & ~3
# TODO what is the maximum size of an instruction?
mem_kv = []
mem_kv.append((0o1000, random.randint(0, 65536)))
mem_kv.append((0o1002, random.randint(0, 65536)))
mem_kv.append((0o1004, random.randint(0, 65536)))
mem_kv.append((0o1006, random.randint(0, 65536)))
mem_kv.append((addr + 0, random.randint(0, 65536)))
mem_kv.append((addr + 2, random.randint(0, 65536)))
mem_kv.append((addr + 4, random.randint(0, 65536)))
mem_kv.append((addr + 6, random.randint(0, 65536)))
out['memory-before'] = dict()
for a, v in mem_kv:
@ -72,18 +80,21 @@ class test_generator:
reg_kv = []
for i in range(7):
reg_kv.append((i, random.randint(0, 65536)))
reg_kv.append((7, 0o1000))
reg_kv.append((7, addr))
out['registers-before'] = dict()
for r, v in reg_kv:
out['registers-before'][r] = v
out['registers-before']['psw'] = 0 # TODO random.randint(0, 65536)
try:
p = self._run_test(mem_kv, reg_kv)
p = self._run_test(addr, mem_kv, reg_kv, out['registers-before']['psw'])
out['registers-after'] = dict()
for r, v in reg_kv:
out['registers-after'][r] = v
out['registers-after']['psw'] = p.psw
out['memory-after'] = dict()
for a, v in mem_kv:
@ -96,8 +107,9 @@ class test_generator:
return out
except:
print('test failed')
except Exception as e:
# handle PDP11 traps; store them
print('test failed', e)
return None
fh = open(sys.argv[1], 'w')
@ -105,7 +117,7 @@ fh = open(sys.argv[1], 'w')
t = test_generator()
tests = []
for i in range(0, 1024):
for i in range(0, 4096):
test = t.create_test()
if test != None:
tests.append(test)

View file

@ -15,7 +15,7 @@
#include "win32.h"
static const char *logfile = strdup("/tmp/myip.log");
static const char *logfile = strdup("/tmp/kek.log");
log_level_t log_level_file = warning;
log_level_t log_level_screen = warning;
FILE *lfh = nullptr;

100
main.cpp
View file

@ -1,7 +1,8 @@
// (C) 2018-2023 by Folkert van Heusden
// (C) 2018-2024 by Folkert van Heusden
// Released under MIT license
#include <atomic>
#include <jansson.h>
#include <signal.h>
#include <stdlib.h>
#include <string>
@ -49,6 +50,91 @@ void sw_handler(int s)
}
#endif
int run_cpu_validation(const std::string & filename)
{
json_error_t error;
json_t *json = json_load_file(filename.c_str(), 0, &error);
if (!json)
error_exit(false, "%s", error.text);
size_t n_ok = 0;
size_t array_size = json_array_size(json);
for(size_t i=0; i<array_size; i++) {
json_t *test = json_array_get(json, i);
// create environment
event = 0;
bus *b = new bus();
cpu *c = new cpu(b, &event);
b->add_cpu(c);
// {"memory-before": {"512": 51435, "514": 45610, "516": 15091, "518": 43544}, "registers-before": {"0": 64423, "1": 1, "2": 41733, "3": 14269, "4": 48972, "5": 42770, "6": 57736, "7": 512}, "registers-after": {"0": 64423, "1": 1, "2": 41733, "3": 14269, "4": 48972, "5": 42770, "6": 57736, "7": 512}, "memory-after": {"512": 51435, "514": 45610, "516": 15091, "518": 43544}}
// initialize
json_t *memory_before = json_object_get(test, "memory-before");
const char *key = nullptr;
json_t *value = nullptr;
json_object_foreach(memory_before, key, value) {
b->writePhysical(atoi(key), json_integer_value(value));
}
json_t *registers_before = json_object_get(test, "registers-before");
json_object_foreach(registers_before, key, value) {
if (strcmp(key, "psw") == 0)
c->setPSW(uint16_t(json_integer_value(value)), false); // TODO: without the AND
else
c->setRegister(atoi(key), json_integer_value(value), rm_cur);
}
c->step_a();
disassemble(c, nullptr, c->getPC(), false);
c->step_b();
// validate
bool err = false;
json_t *memory_after = json_object_get(test, "memory-after");
json_object_foreach(memory_before, key, value) {
uint16_t mem_contains = b->readPhysical(atoi(key));
uint16_t should_be = json_integer_value(value);
if (mem_contains != should_be) {
DOLOG(warning, true, "memory address %s mismatch (is: %06o, should be: %06o)", key, mem_contains, should_be);
err = true;
}
}
json_t *registers_after = json_object_get(test, "registers-after");
json_object_foreach(registers_before, key, value) {
uint16_t register_is = 0;
if (strcmp(key, "psw") == 0)
register_is = c->getPSW();
else
register_is = c->getRegister(atoi(key), rm_cur);
uint16_t should_be = json_integer_value(value);
if (register_is != should_be) {
DOLOG(warning, true, "register %s mismatch (is: %06o, should be: %06o)", key, register_is, should_be);
err = true;
}
}
if (err)
DOLOG(warning, true, "%s", json_dumps(test, 0));
else
n_ok++;
// clean-up
delete b;
}
json_decref(json);
printf("# ok: %zu out of %zu\n", n_ok, array_size);
return 0;
}
void help()
{
printf("-h this help\n");
@ -65,6 +151,7 @@ void help()
printf("-t enable tracing (disassemble to stderr, requires -d as well)\n");
printf("-l x log to file x\n");
printf("-L x,y set log level for screen (x) and file (y)\n");
printf("-J x run validation suite x against the CPU emulation\n");
}
int main(int argc, char *argv[])
@ -95,14 +182,20 @@ int main(int argc, char *argv[])
disk_backend *temp_d = nullptr;
std::string validate_json;
int opt = -1;
while((opt = getopt(argc, argv, "hm:T:Br:R:p:ndtL:b:l:s:Q:N:")) != -1)
while((opt = getopt(argc, argv, "hm:T:Br:R:p:ndtL:b:l:s:Q:N:J:")) != -1)
{
switch(opt) {
case 'h':
help();
return 1;
case 'J':
validate_json = optarg;
break;
case 'Q':
test = optarg;
break;
@ -210,6 +303,9 @@ int main(int argc, char *argv[])
setlog(logfile, ll_file, ll_screen);
if (validate_json.empty() == false)
return run_cpu_validation(validate_json);
bus *b = new bus();
b->set_console_switches(console_switches);