Seite 1 von 1

Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 16:42
von Linux-Fan
Hallo,

ich habe schon damals in der Übung 2.2.2 damit gekämpft und nachdem das jetzt auch in den Beispielaufgaben als 3d auftaucht, bin ich endgültig daran verzweifelt.

Das Problem ist folgendes:
Man will ein Bluespec-Modul haben, welches einen Zähler realisiert, dessen Zählerstand man im selben Takt schreiben und lesen kann. An sich lässt sich das mit RWires oder CRegs realisieren, allerdings habe ich eine solche Variante noch nie erfolgreich kompiliert bekommen bzw. es gab Warnungen wegen Konflikten und die gewünschte Semantik lag nicht vor.

Als ``minimum failing example'' habe ich folgendes geschrieben: http://pastebin.com/GhdTynCn.
Darin ist kein Reset/Load implementiert und der Test ist sehr einfach aufgebaut. Des weiteren habe ich Zähler auslesen und Register aktualisieren in eine Method geschrieben, um Konflikte zwischen dem Auslesen und Aktualisieren zu vermeiden.

Jetzt sagt der Compiler folgendes

Code: Alles auswählen

TU clientssh3:~/wd/cms/beispeilaufgaben$ make
bsc -sim -g mkTrivialTest -u TestTrivial.bsv
checking package dependencies
compiling TestTrivial.bsv
code generation for mkTrivialTest starts
Error: "TestTrivial.bsv", line 53, column 33: (G0004)
  Rule `RL_action_l53c33' uses methods that conflict in parallel:
    tc_ival.port0__write(...)
  and
    tc_ival.port1__read()
  For the complete expressions use the flag `-show-range-conflict'.
Error: "TestTrivial.bsv", line 58, column 33: (G0004)
  Rule `RL_action_l58c33' uses methods that conflict in parallel:
    tc_ival.port0__write(...)
  and
    tc_ival.port1__read()
  For the complete expressions use the flag `-show-range-conflict'.
Error: "TestTrivial.bsv", line 58, column 33: (G0004)
  Rule `RL_action_l58c33' uses methods that conflict in parallel:
    tc_dval.port0__write(...)
  and
    tc_dval.port1__read()
  For the complete expressions use the flag `-show-range-conflict'.
Elaborated error module file created: mkTrivialTest.ba
make: *** [trivial] Error 1
IOW: die eigentlich gewollte Möglichkeit, parallel über mehrere Ports auf das CReg zuzugreifen funktioniert nicht.

Ich vermute, dass man den Konflikt auflösen könnte, wenn man explizit ``write before read'' formalisieren können. Allerdings unterstüzt der `bsc` auf dem Poolrechner keine Scheduling Attributes für Methoden und ich konnte online nichtmal eine Testversion von einem neueren BSC finden, also nicht überprüfen, ob man damit das Problem angehen könnte.

Hat jemand es geschafft einen Zähler mit Concurrent Add + Read (wobei Lesen das NEUE Ergebnis zurückgibt) zu implementieren und ist bereit, sein Wissen zu teilen?

Edit: Erst schreiben, dann Lesen :)

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 16:53
von JHofmann
Moin,

teilen Sie mal folgende Rule in auf:

Code: Alles auswählen

 action
  tc.inc(40);
  tc.dec(20);
  let rp <- tc.get();
  if(rp != 22)
    $display("[FAIL] GOT %d", rp);
  else
    $display("[ OK ]");
  endaction
Sie können nicht auf verschiedene CReg Stufen in der selben Rule zugreifen.

Viele Grüße,

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 16:54
von Fabian Czappa
Hay,

das sieht ziemlich schrecklich aus :D
Versuchs doch nochmal so (Es gibt keinen Grund, sich so viel Stress zu machen, das sind 5 Zeilen Code alles in allem):
Du hast ein Register mit mehreren Ports, von dem aktualisierst du dann immer den Wert Schritt für Schritt und gibst den letzten aus.

Viele Grüße
Fabian

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 17:15
von Linux-Fan
JHofmann hat geschrieben:teilen Sie mal folgende Rule in auf:
[...]
Sie können nicht auf verschiedene CReg Stufen in der selben Rule zugreifen.
Das war der entscheidende Hinweis! Vielen Dank, jetzt funktioniert es: http://pastebin.com/zSkSpGBx :) :)
Fabian Czappa hat geschrieben:das sieht ziemlich schrecklich aus :D
Versuchs doch nochmal so (Es gibt keinen Grund, sich so viel Stress zu machen, das sind 5 Zeilen Code alles in allem):
Du hast ein Register mit mehreren Ports, von dem aktualisierst du dann immer den Wert Schritt für Schritt und gibst den letzten aus.
Jetzt da ich es geschafft habe, dass es funktioniert (die neue Lösung ist noch hässlicher als vorher...) mache ich mich daran, das mit dem `reset` aus der Aufgabe zu versehen und stilmäßig zu verbessern :)

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 17:48
von Soulztorm
Hi Leute,

hierzu hab ich auchmal die "5 Zeilen" (Tatsächlich exakt 5) Lösung versucht, in dem ich in einem takt über ein 4 Port CReg jeweils up, down, reset, und am letzten port getCounter ausgebe:

http://pastebin.com/4ybxD2Jp

Fehler seht ihr unten im Console dump (sowas: )

Error: "CRegCounter.bsv", line 40, column 25: (G0004)
Rule `RL_action_l40c25' uses methods that conflict in parallel:
uut_ctr.port0__write(...)
and
uut_ctr.port1__read()


Wo ist jetzt mein Denkfehler?
Ich dachte ich kann in einem takt alle aktionen auf den 4 CReg ports ausführen, und nach jedem takt steht der aktuelle wert in allen 4 ports?

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 17:52
von Fabian Czappa
Wie schon so oft im Forum erwähnt:
Die Port können nicht gleichzeitig angesprochen werden (Logisch, siehe die Hardware), also auch nicht innerhalb einer Regel bzw einer Action in einer FSM.

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:06
von Soulztorm
OK also wenn ich die Testbench nicht als Aktion sondern als parallele Umgebung setze funktioniert alles in einem Takt. Ist das dann auch korrekt? Oder ist bei meiner Implementation noch irgendwas falsch?

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:13
von Linux-Fan
Wenn ich meine Testbench darauf ausführe, erhalte ich einen Fehler, der daher resultiert, dass `reset()` bei der Implementierung aus http://pastebin.com/4ybxD2Jp dafür sorgt, dass gleichzeitge up and down nicht berücksichtigt werden (also wird reset logisch gesehen ``nach'' up und down ausgeführt). Solange man sich dessen bewusst ist, würde ich sagen, dass die Lösung richtig ist :)

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:21
von Soulztorm
Ja gut, da ich das irgendwie umgedreht hatte (Was nicht so viel Sinn gemacht hat tbh. :D) kam bei jedem reset auch 0 raus, jetzt nochmal ports getauscht, und in jeder par umgebung kann ich resetten, erhöhen und erniedrigen und der Wert stimmt.

Edit: der "Fehler" ist ne Warnung?!

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:31
von Fabian Czappa
Ihr redet gerade an mir vorbei, falls ich eine Frage (ist da überhaupt eine) überlesen habe, dann sagt das nochmal.

Code: Alles auswählen

Error: "CRegCounter.bsv", line 40, column 25: (G0004)
  Rule `RL_action_l40c25' uses methods that conflict in parallel:
    uut_ctr.port0__write(...)
  and
    uut_ctr.port1__write(...)
Ist ein richtiger Fehler, weil es falsch ist. Um es nochmal zu sagen: Verschiedenrangige Ports können nicht gleichzeitig angesteuert werden.
Des weiteren ist es nicht spezifiziert, in welcher Reihenfolge die Methoden abgearbeitet werden müssen. Von mir auch aus up < reset < down. Nur getcounter muss am Ende sein.

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:33
von Linux-Fan
Soulztorm hat geschrieben:Edit: der "Fehler" ist ne Warnung?!
Nein, der Fehler wird von meiner Testbench ausgegeben. Ich schreibe wenn möglich immer Tests, die direkt ein dickes FAIL ausgeben, wenn der Test nicht erfolgreich ausgeführt wurde :), konkret sieht meine Testbench folgendermaßen aus (natürlich fehlen noch die Module mit den Implementierungen, die oben importiert werden, um das direkt auszuführen, aber man kann mit meiner jetzt-funktionsfähigen Lösung von Aufgabe 2.2.2. testen): http://pastebin.com/RRbZy3eL

@Fabian Czappa: Ich glaube/hoffe, dass alle an diesem Thread beteiligten das Problem jetzt gelöst haben, sofern sie es einmal hatten :)

Re: Zähleraktualisierung & Lesen in einem Takt / Übung 2.2.2 / Beispielaufgabe 3d

Verfasst: 19. Feb 2017 18:40
von Soulztorm
Ok, dass ich in einer Rule oder Action nicht auf mehrere Ports zugreifen kann weiss ich jetzt.
Wenn ich jetzt also die Aktionen in einer par Umgebung habe, erstellt mir die FSM daraus Regeln, die getrennt alle zum selben Takt ausgeführt werden, in der Impliziten Ordnung durch die Ports?

Dieses Modul:

Code: Alles auswählen

module mkCounter(CRegCounter);
	Reg#(Int#(32)) ctr[4] <- mkCReg(4, 0);

	method Action up(Int#(32) v); 
		ctr[1] <= ctr[1] + v;
	endmethod
	
	method Action down(Int#(32) v);
		ctr[2] <= ctr[2] - v;
	endmethod
	
	method Action reset();
		ctr[0] <= 0;
	endmethod
	
	method Int#(32) getCounter();
		return ctr[3];	
	endmethod	
endmodule
und diese Testbench:

Code: Alles auswählen

	Stmt teststmt = {
		seq
			par
				uut.up(32);
				uut.down(11);
				$display("Counter is: %d", uut.getCounter());
				uut.reset();
			endpar	
			
			par
				uut.up(42);
				$display("Counter is: %d", uut.getCounter());
				uut.reset();
			endpar	
		endseq		
	};
führen zwar zu einer Warnung, aber zu der erwarteten Ausgabe von 21 und 42.