fixes
This commit is contained in:
parent
c62aadd318
commit
a0630fd485
5 changed files with 190 additions and 84 deletions
|
@ -6,6 +6,9 @@ cmake_minimum_required(VERSION 3.9)
|
|||
|
||||
add_compile_options(-Wall -pedantic -Wextra)
|
||||
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
|
@ -69,9 +72,9 @@ endif (WIN32)
|
|||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT supported)
|
||||
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||
#set(CMAKE_BUILD_TYPE Debug)
|
||||
#set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
|
|
23
cpu.cpp
23
cpu.cpp
|
@ -1,4 +1,4 @@
|
|||
// (C) 2018-2023 by Folkert van Heusden
|
||||
// (C) 2018-2024 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -179,6 +179,27 @@ uint16_t cpu::addRegister(const int nr, const rm_selection_t mode_selection, con
|
|||
return pc += value;
|
||||
}
|
||||
|
||||
void cpu::lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint16_t value)
|
||||
{
|
||||
if (reg < 6)
|
||||
regs0_5[set][reg] = value;
|
||||
else if (reg == 6)
|
||||
sp[set == 0 ? 0 : 3] = value;
|
||||
else
|
||||
pc = value;
|
||||
}
|
||||
|
||||
uint16_t cpu::lowlevel_register_get(const uint8_t set, const uint8_t reg)
|
||||
{
|
||||
if (reg < 6)
|
||||
return regs0_5[set][reg];
|
||||
|
||||
if (reg == 6)
|
||||
return sp[set == 0 ? 0 : 3];
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
bool cpu::getBitPSW(const int bit) const
|
||||
{
|
||||
return (psw >> bit) & 1;
|
||||
|
|
8
cpu.h
8
cpu.h
|
@ -1,4 +1,4 @@
|
|||
// (C) 2018-2023 by Folkert van Heusden
|
||||
// (C) 2018-2024 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#pragma once
|
||||
|
@ -64,7 +64,6 @@ private:
|
|||
|
||||
void addToMMR1(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode);
|
||||
|
||||
|
||||
gam_rc_t getGAM(const uint8_t mode, const uint8_t reg, const word_mode_t word_mode, const rm_selection_t mode_selection, const bool read_value = true);
|
||||
gam_rc_t getGAMAddress(const uint8_t mode, const int reg, const word_mode_t word_mode);
|
||||
bool putGAM(const gam_rc_t & g, const uint16_t value); // returns false when flag registers should not be updated
|
||||
|
@ -143,8 +142,11 @@ public:
|
|||
uint16_t getPC() const { return pc; }
|
||||
|
||||
void setRegister(const int nr, const uint16_t value, const rm_selection_t mode_selection = rm_cur);
|
||||
|
||||
void setRegisterLowByte(const int nr, const word_mode_t word_mode, const uint16_t value);
|
||||
// used by 'main' for json-validation
|
||||
void lowlevel_register_set(const uint8_t set, const uint8_t reg, const uint16_t value);
|
||||
uint16_t lowlevel_register_get(const uint8_t set, const uint8_t reg);
|
||||
void lowlevel_psw_set(const uint16_t value) { psw = value; }
|
||||
|
||||
void setStackPointer(const int which, const uint16_t value) { assert(which >= 0 && which < 4); sp[which] = value; }
|
||||
void setPC(const uint16_t value) { pc = value; }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import json
|
||||
from machine import PDP1170
|
||||
from pdptraps import PDPTrap, PDPTraps
|
||||
import random
|
||||
import sys
|
||||
|
||||
|
@ -14,23 +15,32 @@ class PDP1170_wrapper(PDP1170):
|
|||
|
||||
def reset_mem_transactions_dict(self):
|
||||
self.mem_transactions = dict()
|
||||
self.before = dict()
|
||||
|
||||
def get_mem_before(self):
|
||||
return self.before
|
||||
|
||||
def get_mem_transactions_dict(self):
|
||||
return self.mem_transactions
|
||||
|
||||
def put(self, physaddr, value):
|
||||
self.before[physaddr] = value
|
||||
super().physRW(physaddr, value)
|
||||
|
||||
def physRW(self, physaddr, value=None):
|
||||
if value == None: # read
|
||||
self.mem_transactions[physaddr] = random.randint(0, 65536)
|
||||
return super().physRW(physaddr, self.mem_transactions[physaddr])
|
||||
if not physaddr in self.mem_transactions and not physaddr in self.before:
|
||||
self.before[physaddr] = random.randint(0, 65536)
|
||||
return super().physRW(physaddr, self.before[physaddr])
|
||||
|
||||
self.mem_transactions[physaddr] = value
|
||||
super().physRW(physaddr, value)
|
||||
return 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))
|
||||
self.physRW(temp_addr, random.randint(0, 65536))
|
||||
temp_addr += 2
|
||||
return super().physRW_N(physaddr, nwords)
|
||||
|
||||
|
@ -38,32 +48,28 @@ class PDP1170_wrapper(PDP1170):
|
|||
self.mem_transactions[temp_addr] = w
|
||||
temp_addr += 2
|
||||
|
||||
super().physRW_N(physaddr, nwords, words=words)
|
||||
return super().physRW_N(physaddr, nwords, words=words)
|
||||
|
||||
class test_generator:
|
||||
def _invoke_bp(self, a, i):
|
||||
return True
|
||||
|
||||
def _run_test(self, addr, mem_setup, reg_setup, psw):
|
||||
p = PDP1170_wrapper(loglevel='DEBUG')
|
||||
def put_registers(self, p, target, tag):
|
||||
target[tag] = dict()
|
||||
target[tag][0] = dict()
|
||||
target[tag][1] = dict()
|
||||
for set_ in range(0, 2):
|
||||
for reg_ in range(0, 6):
|
||||
target[tag][set_][reg_] = p.registerfiles[set_][reg_]
|
||||
|
||||
for a, v in mem_setup:
|
||||
p.mmu.wordRW(a, v)
|
||||
|
||||
for r, v in reg_setup:
|
||||
p.r[r] = v
|
||||
|
||||
p.reset_mem_transactions_dict()
|
||||
|
||||
p._syncregs()
|
||||
p.run_steps(pc=addr, steps=1)
|
||||
p._syncregs()
|
||||
|
||||
return p
|
||||
target[tag]['sp'] = p.stackpointers
|
||||
target[tag]['pc'] = p.PC
|
||||
|
||||
def create_test(self):
|
||||
out = { }
|
||||
|
||||
p = PDP1170_wrapper(loglevel='DEBUG')
|
||||
|
||||
addr = random.randint(0, 65536) & ~3
|
||||
|
||||
# TODO what is the maximum size of an instruction?
|
||||
|
@ -72,41 +78,59 @@ class test_generator:
|
|||
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:
|
||||
out['memory-before'][a] = v
|
||||
|
||||
reg_kv = []
|
||||
for i in range(7):
|
||||
reg_kv.append((i, random.randint(0, 65536)))
|
||||
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)
|
||||
p.put(a, v)
|
||||
|
||||
try:
|
||||
p = self._run_test(addr, mem_kv, reg_kv, out['registers-before']['psw'])
|
||||
# generate & set PSW
|
||||
while True:
|
||||
try:
|
||||
p.psw = random.randint(0, 65536)
|
||||
break
|
||||
except PDPTraps.ReservedInstruction as ri:
|
||||
pass
|
||||
|
||||
out['registers-after'] = dict()
|
||||
# generate other registers
|
||||
reg_kv = []
|
||||
for i in range(7):
|
||||
reg_kv.append((i, random.randint(0, 65536)))
|
||||
reg_kv.append((7, addr))
|
||||
|
||||
# set registers
|
||||
set_ = (p.psw >> 11) & 1
|
||||
for r, v in reg_kv:
|
||||
out['registers-after'][r] = v
|
||||
p.registerfiles[set_][r] = v
|
||||
p.registerfiles[1 - set_][r] = (~v) & 65535 # make sure it triggers errors
|
||||
assert p.registerfiles[set_][r] == p.r[r]
|
||||
p.r[6] = p.registerfiles[set_][6]
|
||||
p._syncregs()
|
||||
|
||||
self.put_registers(p, out, 'registers-before')
|
||||
out['registers-before']['psw'] = p.psw
|
||||
|
||||
p.run_steps(pc=addr, steps=1)
|
||||
|
||||
self.put_registers(p, out, 'registers-after')
|
||||
out['registers-after']['psw'] = p.psw
|
||||
|
||||
mb = p.get_mem_before()
|
||||
for a in mb:
|
||||
out['memory-before'][a] = mb[a]
|
||||
|
||||
out['memory-after'] = dict()
|
||||
for a, v in mem_kv:
|
||||
out['memory-after'][a] = v
|
||||
mem_transactions = p.get_mem_transactions_dict()
|
||||
for a in mem_transactions:
|
||||
out['memory-after'][a] = mem_transactions[a]
|
||||
# TODO originele geheugeninhouden checken
|
||||
|
||||
# TODO check if mem_transactions affects I/O, then return None
|
||||
|
||||
return out
|
||||
|
||||
except PDPTraps.ReservedInstruction as pri:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
# handle PDP11 traps; store them
|
||||
print('test failed', e)
|
||||
|
@ -122,5 +146,5 @@ for i in range(0, 4096):
|
|||
if test != None:
|
||||
tests.append(test)
|
||||
|
||||
fh.write(json.dumps(tests))
|
||||
fh.write(json.dumps(tests, indent=4))
|
||||
fh.close()
|
||||
|
|
132
main.cpp
132
main.cpp
|
@ -1,6 +1,7 @@
|
|||
// (C) 2018-2024 by Folkert van Heusden
|
||||
// Released under MIT license
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic>
|
||||
#include <jansson.h>
|
||||
#include <signal.h>
|
||||
|
@ -70,20 +71,40 @@ int run_cpu_validation(const std::string & filename)
|
|||
|
||||
// {"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));
|
||||
{
|
||||
// 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);
|
||||
json_t *const registers_before = json_object_get(test, "registers-before");
|
||||
|
||||
{
|
||||
const char *key = nullptr;
|
||||
json_t *value = nullptr;
|
||||
json_t *set0 = json_object_get(registers_before, "0");
|
||||
json_object_foreach(set0, key, value) {
|
||||
c->lowlevel_register_set(0, atoi(key), json_integer_value(value));
|
||||
}
|
||||
json_t *set1 = json_object_get(registers_before, "1");
|
||||
json_object_foreach(set1, key, value) {
|
||||
c->lowlevel_register_set(1, atoi(key), json_integer_value(value));
|
||||
}
|
||||
}
|
||||
{
|
||||
json_t *psw_reg = json_object_get(registers_before, "psw");
|
||||
assert(psw_reg);
|
||||
c->lowlevel_psw_set(json_integer_value(psw_reg));
|
||||
}
|
||||
{
|
||||
json_t *b_pc = json_object_get(registers_before, "pc");
|
||||
assert(b_pc);
|
||||
c->setPC(json_integer_value(b_pc));
|
||||
// TODO PS
|
||||
}
|
||||
|
||||
c->step_a();
|
||||
|
@ -91,39 +112,74 @@ int run_cpu_validation(const std::string & filename)
|
|||
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);
|
||||
{
|
||||
bool err = false;
|
||||
{
|
||||
json_t *memory_after = json_object_get(test, "memory-after");
|
||||
const char *key = nullptr;
|
||||
json_t *value = nullptr;
|
||||
json_object_foreach(memory_after, key, value) {
|
||||
int key_v = atoi(key);
|
||||
uint16_t mem_contains = b->readPhysical(key_v);
|
||||
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;
|
||||
if (mem_contains != should_be) {
|
||||
DOLOG(warning, true, "memory address %06o (%d) mismatch (is: %06o (%d), should be: %06o (%d))", key_v, key_v, mem_contains, mem_contains, should_be, 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;
|
||||
uint16_t psw = c->getPSW();
|
||||
|
||||
if (strcmp(key, "psw") == 0)
|
||||
register_is = c->getPSW();
|
||||
json_t *const registers_after = json_object_get(test, "registers-after");
|
||||
|
||||
{
|
||||
int set_nr = (psw >> 11) & 1;
|
||||
char set[] = { char('0' + set_nr), 0x00 };
|
||||
|
||||
json_t *a_set = json_object_get(registers_after, set);
|
||||
const char *key = nullptr;
|
||||
json_t *value = nullptr;
|
||||
json_object_foreach(a_set, key, value) {
|
||||
uint16_t register_is = c->lowlevel_register_get(set_nr, atoi(key));
|
||||
uint16_t should_be = json_integer_value(value);
|
||||
|
||||
if (register_is != should_be) {
|
||||
DOLOG(warning, true, "set %d register %s mismatch (is: %06o, should be: %06o)", set_nr, key, register_is, should_be);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
json_t *a_pc = json_object_get(registers_after, "pc");
|
||||
assert(a_pc);
|
||||
uint16_t should_be_pc = json_integer_value(a_pc);
|
||||
if (c->getPC() != should_be_pc) {
|
||||
DOLOG(warning, true, "PC register mismatch (is: %06o, should be: %06o)", c->getPC(), should_be_pc);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO check PS
|
||||
|
||||
{
|
||||
json_t *a_psw = json_object_get(registers_after, "psw");
|
||||
assert(a_psw);
|
||||
uint16_t should_be_psw = json_integer_value(a_psw);
|
||||
if (should_be_psw != psw) {
|
||||
DOLOG(warning, true, "PSW register mismatch (is: %06o, should be: %06o)", psw, should_be_psw);
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
DOLOG(warning, true, "%s\n", json_dumps(test, 0)); // also emit empty line(!)
|
||||
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;
|
||||
}
|
||||
n_ok++;
|
||||
}
|
||||
|
||||
if (err)
|
||||
DOLOG(warning, true, "%s", json_dumps(test, 0));
|
||||
else
|
||||
n_ok++;
|
||||
|
||||
// clean-up
|
||||
delete b;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue