basic framework for json validation
This commit is contained in:
parent
81f7d8f1ad
commit
c62aadd318
7 changed files with 143 additions and 26 deletions
|
@ -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
12
cpu.cpp
|
@ -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
1
cpu.h
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
2
log.cpp
2
log.cpp
|
@ -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
100
main.cpp
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue