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.
|
||||
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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue