add integrated example, fix bracket searching
This commit is contained in:
parent
7340f81c3f
commit
7c0eb5ca22
10
README.md
10
README.md
|
@ -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.
|
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", ...)
|
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
|
#### Testing only one procedure
|
||||||
|
|
||||||
If you don't want the whole thing to be executed, you can still use opbtest, and call `testproc(name)`:
|
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()`.
|
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.
|
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.
|
opbtest acutally replaces the statement with `load s0, 4`, so no actual input statements will be processed.
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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])
|
|
@ -85,11 +85,18 @@ class OpbTestCase(TestCase):
|
||||||
def assertPsm(self, jsondata):
|
def assertPsm(self, jsondata):
|
||||||
return OpbTestAssertions(jsondata, self)
|
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):
|
def _check(self, jsonindex, jsondata, index, expected):
|
||||||
actual = jsondata[jsonindex][index]
|
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:
|
if expected == actual:
|
||||||
return ""
|
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):
|
def checkPort(self, jsondata, port, expected):
|
||||||
self._check("ports_out", jsondata, port, expected)
|
self._check("ports_out", jsondata, port, expected)
|
||||||
|
@ -100,4 +107,4 @@ class OpbTestCase(TestCase):
|
||||||
expected = int(str(expected), 16)
|
expected = int(str(expected), 16)
|
||||||
if expected == actual:
|
if expected == actual:
|
||||||
return ""
|
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)
|
||||||
|
|
|
@ -34,7 +34,7 @@ class OpbTestMockable():
|
||||||
with open(self.filename, 'r') as original:
|
with open(self.filename, 'r') as original:
|
||||||
data = original.readlines()
|
data = original.readlines()
|
||||||
|
|
||||||
def findlinebetween(data, statement1, statement2):
|
def find_line_between(data, statement1, statement2):
|
||||||
linenr = 0
|
linenr = 0
|
||||||
startcounting = False
|
startcounting = False
|
||||||
for line in data:
|
for line in data:
|
||||||
|
@ -47,11 +47,33 @@ class OpbTestMockable():
|
||||||
if linenr + 1 == len(data):
|
if linenr + 1 == len(data):
|
||||||
self.case.fail("No statements between " + statement1 + " and " + statement2 + " found")
|
self.case.fail("No statements between " + statement1 + " and " + statement2 + " found")
|
||||||
return linenr
|
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):
|
def setupproc(data):
|
||||||
self.prepender.append("jump " + self.proctotest + "\n")
|
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:]
|
data = data[0:linenr] + ["jump opbtestquitfn\n"] + data[linenr:]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -89,7 +111,7 @@ class OpbTestMockable():
|
||||||
if len(self.replacers) > 0:
|
if len(self.replacers) > 0:
|
||||||
data = setupreplaces(data)
|
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
|
data = data[0:firstjump] + self.prepender + data[firstjump:] + self.appender
|
||||||
with open(self.filename, 'w') as modified:
|
with open(self.filename, 'w') as modified:
|
||||||
|
|
Loading…
Reference in New Issue