add integrated example, fix bracket searching

This commit is contained in:
wgroeneveld 2018-12-04 10:24:58 +01:00
parent 7340f81c3f
commit 7c0eb5ca22
5 changed files with 238 additions and 5 deletions

View File

@ -91,6 +91,15 @@ Everything can be chained together, or be asserted in one line:
Notice the difference: `scratchpads()` will accept an array, and `contains()` will accept the same length in values.
You can set the scratchpad/output port/... index as an `int` (0, 1, ...) or as a `str` in hex values ("0", "1F", "FF", ...)
**Assertion output**: if for instance the output ports do not match, the following message will appear in your test output window:
> AssertionError: Output dos not contain expected values:
output ports_out 3 should contain 0 (hex: 00) but instead contains 12 (hex: 0C)
Since it's possible to assert hex values (as a `str`) or number values (as an `int`), the test output message always shows both.
It is possible to write `assert_that.ports([1]).contains(["0A"])` and `assert_that.ports([1]).contains([10])`. Both assert the same thing and contain the same expectation values.
#### Testing only one procedure
If you don't want the whole thing to be executed, you can still use opbtest, and call `testproc(name)`:
@ -143,3 +152,4 @@ For instance, `.setregs({"s5": 2, "s6": 3})` will preload register s5 with value
Before calling `execute()`, you can preload input port values using `mockinput()`.
For instance, `.mockinput(0, 4)` will preload input port 0 with value 4. Psm statements like `input s0, 0` will load 4 into register s4.
opbtest acutally replaces the statement with `load s0, 4`, so no actual input statements will be processed.

View File

@ -0,0 +1,154 @@
constant QuitPort, FF
constant ConfigA, 01
constant ConfigB, 02
constant ConfigC, 03
constant ConfigD, 04
namereg sF, SP ; sF is stack pointer
namereg sA, seed
init:
load SP, 00 ; 3F = einde.
jump main
use_random8(random, seed)
proc random_range(s0 is max, s2 is shifter, s3 is counter) {
if(s0 == 0) {
load seed, 0
jump done
}
randomizing:
load counter, 0
load shifter, max
call random
shifting:
; shift totdat we een 1 tegenkomen (wordt ook nog geshift)
add counter, 1
sl0 shifter
jump NC, shifting
sub counter, 1
; shift gegenereerd getal zelfde aantal keren, indien te groot: herbegin
for(shifter := 0, shifter < counter, shifter := shifter + 1) {
sl0 seed
}
for(shifter := 0, shifter < counter, shifter := shifter + 1) {
sr0 seed
}
if(seed > max) {
jump randomizing
}
done:
; resultaat - links geshift met 0en (en terug rechts) - zit in seed
}
proc permutation_to_configuration(s4 is index, s5 is scratchindex, s6 is counter, s7 is configa, s8 is configb) {
load configa, 0
load configb, 0
for(counter := 3, signed(counter >= 0), counter := counter - 1) {
load SP, counter
expr(SP := SP + scratchindex)
fetch index, (SP)
; 0000 00 weg; laatse 2 bits relevant tot nu toe
sl0 index
sl0 index
sl0 index
sl0 index
sl0 index
sl0 index
sl0 index
sla configa
sl0 index
sla configb
add SP, 01
}
}
proc pg_to_permutation(s6 is counter, s7 is pgcounter, s8 is destcounter, s4 is value, s5 is pgvalue) {
load pgcounter, 10
for(counter := 0, counter < 4, counter := counter + 1) {
load SP, counter
fetch value, (SP)
load SP, pgcounter
fetch pgvalue, (SP)
expr(destcounter := value + 32)
load SP, destcounter
store pgvalue, (SP)
add pgcounter, 01
}
}
main:
load seed, 5A ; replace with LFSA hw lookup
vars(s0 is random_range_max, s6 is counter, s4 is index, s5 is random_index)
; initiele array: [0, 1, 2] in scratchpad 00 -> 03
for(counter := 0, counter < 4, counter := counter + 1) {
store counter, (SP)
add SP, 01
}
load SP, 10
; initiele p/g: [0, 2, 2, 1] in scratchpad 10 -> 13 (hex)
load counter, 0
store counter, (SP)
add SP, 01
load counter, 2
store counter, (SP)
add SP, 01
load counter, 2
store counter, (SP)
add SP, 01
load counter, 1
store counter, (SP)
add SP, 01
; backwards Knuth shuffle
for(counter := 3, signed(counter >= 0), counter := counter - 1) {
; 0) random index in seed
load random_range_max, counter
call random_range
; 1) fetch arr[counter] (starting at end)
load SP, counter
fetch index, (SP)
; 2) fetch arr[random(0, counter + 1)]
load SP, seed
fetch random_index, (SP)
; 3) swap values
store index, (SP)
load SP, counter
store random_index, (SP)
add SP, 01
}
vars(s7 is configa, s8 is configb)
load s5, 0; originele permutation resultaat leeft op scratchpad index 0
call permutation_to_configuration
output configa, ConfigA
output configb, ConfigB
call pg_to_permutation
load s5, 20 ; p/g permutation resultaat leeft op scratchpad index 32
call permutation_to_configuration
output configa, ConfigC
output configb, ConfigD
; Terminate the simulator
;load s0, 00
output s0, QuitPort

View File

@ -0,0 +1,40 @@
from opbtest import OpbTestCase
#
# The randompermutations.psm4 Assembly file creates a random permutation of 4 numbers (0, 1, 2, 3)
# Scratchpad:
# 00 : 00 03 02 01 00 [...] -> original numbers, scrambled in unique permutation
# 10 : 00 02 02 01 00 [...] -> bitstream masks for these numbers: 0, 2, 2, 1
# 20 : 00 01 02 02 00 [...] -> scrambled in unique permutation
# 30 : [...]
# Out ports:
# 00: 00 06 0A 0C 02 [...]
class TestRandomPermutations(OpbTestCase):
def setUp(self):
pass
#self.do_not_cleanup_files()
def load_psm4_assertion(self):
# mock out the PRNG call
return self.load_file("randompermutations.psm4").replace("call random", "load seed, 3F").execute()
def test_random_range_between_three_and_zero(self):
# proc random_range(s0 is max, s2 is shifter, s3 is counter) {
# we need to initialize these registers as "parameters". "return value" is in sA (seed)
assert_that = self.load_file("randompermutations.psm4")\
.replace("call random", "load seed, AF")\
.setregs({"s0": 3})\
.testproc("random_range")\
.execute()
assert_that.reg("sA").contains(2)
def test_output_configuration_correct_in_output_ports(self):
assert_that = self.load_psm4_assertion()
assert_that.ports([1, 2, 3, 4, 5]).contains(["06", "0A", "0C", "02", "00"])
def test_permutation_in_scratchpad(self):
assert_that = self.load_psm4_assertion()
assert_that.scratchpads(["0", "1", "2", "3"]).contains([0, 3, 2, 1])
assert_that.scratchpads(["10", "11", "12", "13"]).contains([0, 2, 2, 1])

View File

@ -85,11 +85,18 @@ class OpbTestCase(TestCase):
def assertPsm(self, jsondata):
return OpbTestAssertions(jsondata, self)
def _print_expectation(self, expected):
return str(expected) + " (hex: " + hex(expected).replace("0x", "").upper().zfill(2) + ")"
def _check(self, jsonindex, jsondata, index, expected):
actual = jsondata[jsonindex][index]
# try to convert both to the same type. acutal will always be an int (hex valued)
if type(expected) is str:
expected = int(expected, 16)
if expected == actual:
return ""
return "output " + jsonindex + " " + str(index) + " should contain " + str(expected) + " but instead contains " + str(actual)
return "output " + jsonindex + " " + str(index) + " should contain " + self._print_expectation(expected) + " but instead contains " + self._print_expectation(actual)
def checkPort(self, jsondata, port, expected):
self._check("ports_out", jsondata, port, expected)
@ -100,4 +107,4 @@ class OpbTestCase(TestCase):
expected = int(str(expected), 16)
if expected == actual:
return ""
return "reg " + bank + "," + str(nr) + " should contain " + str(expected) + " but instead contains " + str(actual)
return "reg " + bank + "," + self._print_expectation(nr) + " should contain " + str(expected) + " but instead contains " + str(actual)

View File

@ -34,7 +34,7 @@ class OpbTestMockable():
with open(self.filename, 'r') as original:
data = original.readlines()
def findlinebetween(data, statement1, statement2):
def find_line_between(data, statement1, statement2):
linenr = 0
startcounting = False
for line in data:
@ -47,11 +47,33 @@ class OpbTestMockable():
if linenr + 1 == len(data):
self.case.fail("No statements between " + statement1 + " and " + statement2 + " found")
return linenr
def find_last_closing_bracket(data, procname):
procname += "(" # add (, could also have been a call
linenr = 0
startcounting = False
amount_of_brackets_open = 0
for line in data:
if procname in line:
startcounting = True
if startcounting:
if '}' in line:
amount_of_brackets_open -= 1
elif '{' in line:
amount_of_brackets_open += 1
if amount_of_brackets_open == 0:
break
linenr += 1
if linenr + 1 == len(data):
self.case.fail("Proc " + procname + ": no ending bracket } found")
return linenr
def setupproc(data):
self.prepender.append("jump " + self.proctotest + "\n")
linenr = findlinebetween(data, self.proctotest + "(", "}") # add (, could also have been a call
linenr = find_last_closing_bracket(data, self.proctotest)
data = data[0:linenr] + ["jump opbtestquitfn\n"] + data[linenr:]
return data
@ -89,7 +111,7 @@ class OpbTestMockable():
if len(self.replacers) > 0:
data = setupreplaces(data)
firstjump = findlinebetween(data, "jump", "jump")
firstjump = find_line_between(data, "jump", "jump")
data = data[0:firstjump] + self.prepender + data[firstjump:] + self.appender
with open(self.filename, 'w') as modified: