val path = System.getProperty("user.dir") + "/source/load-ivy.sc" interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path))) import chisel3._ import chisel3.util._ import chisel3.tester._ import chisel3.tester.RawTester.test import dotvisualizer._ class RegisterFile(register_number: Int, register_width: Int) extends Module { // αντιγράψτε από προηγούμενα } class Alu(n: Int) extends Module { // αντιγράψτε από προηγούμενα } class DataPath(register_number: Int, register_width: Int) extends Module { // αντιγράψτε από προηγούμενα και τροποποιήστε σύμφωνα με τις οδηγίες } test(new DataPath(8,16)) { c => // σήματα εισόδου για τις δοκιμαστικές "λειτουργίες" (micro-instructions) και την αναμενόμενη έξοδο "zero" val cmdbits = List(Map("READ_SEL_A" -> 0.U, // λειτουργία: r1 <- 256 "READ_SEL_B" -> 0.U, "ALU_A_SEL" -> 0.U, "IM" -> 256.U, "SEL" -> "b01".U, "SUB" -> 0.U, "WRITE_SEL" -> 1.U, "zero" -> 0.U), // η έξοδος zero πρέπει να είναι 0 (ψευδής) Map("READ_SEL_A" -> 1.U, // λειτουργία: r0 <- r1 - r1 "READ_SEL_B" -> 1.U, "ALU_A_SEL" -> 1.U, "IM" -> 0.U, "SEL" -> "b11".U, "SUB" -> 1.U, "WRITE_SEL" -> 0.U, "zero" -> 1.U) // η έξοδος zero πρέπει να είναι 1 (αληθής) ) for (bits <- cmdbits) { // για κάθε μία από τις δοκιμαστικές λειτουργίες // ανάθεση τιμών εισόδου c.io.read_sel_a.poke(bits("READ_SEL_A")) c.io.read_sel_b.poke(bits("READ_SEL_B")) c.io.alu_a_sel.poke(bits("ALU_A_SEL")) c.io.im.poke(bits("IM")) c.io.sel.poke(bits("SEL")) c.io.sub.poke(bits("SUB")) c.io.write_sel.poke(bits("WRITE_SEL")) // έλεγχος αναμενόμενης τιμής εξόδου zero c.io.zero.expect(bits("zero")) // μετάβαση στην επόμενη λειτουργία c.clock.step() } } println("SUCCESS!!") class BranchLogic extends Module { val io = IO(new Bundle { // συμπληρώστε εισόδους/εξόδους σύμφωνα με την περιγραφή }) // συμπληρώστε τη ζητούμενη λειτουργικότητα } test(new BranchLogic) { c => // δοκιμή των 4 δυνατών συνδυασμών των εισόδων branch και zero c.io.branch.poke(0.U) // branch = 0 και zero = 0 -> pc_sel πρέπει να είναι 0 c.io.zero.poke(0.U) c.io.pc_sel.expect(0.U) c.io.branch.poke(0.U) // branch = 0 και zero = 1 -> pc_sel πρέπει να είναι 0 c.io.zero.poke(1.U) c.io.pc_sel.expect(0.U) c.io.branch.poke(1.U) // branch = 1 και zero = 0 -> pc_sel πρέπει να είναι 0 c.io.zero.poke(0.U) c.io.pc_sel.expect(0.U) c.io.branch.poke(1.U) // branch = 1 και zero = 1 -> pc_sel πρέπει να είναι 1 c.io.zero.poke(1.U) c.io.pc_sel.expect(1.U) // δοκιμή εάν η έξοδος branch_pc ισούται με branch_offset + next_pc c.io.next_pc.poke(1.U) c.io.branch_offset.poke(2.U) c.io.branch_pc.expect(3.U) // 1+2 c.io.next_pc.poke("b1111111111111111".U) c.io.branch_offset.poke(1.U) c.io.branch_pc.expect(0.U) // 65535+1 (ισούται με 0 στα 16 bits) } println("SUCCESS!!") class DecodeUnit extends Module { // αντιγράψτε από προηγούμενα και τροποποιήστε σύμφωνα με τις οδηγίες } test(new DecodeUnit) { c => // δοκιμή εντολής αριθμητικής-λογικής πράξης, η έξοδος branch πρέπει να είναι 0 (ψευδής) c.io.instruction.poke("b0000011001010011".U) // r3 = r1 + r2 c.io.branch.expect(0.U) // δοκιμή εντολής ανάθεσης σταθεράς σε καταχωρητή, η έξοδος branch πρέπει να είναι 0 (ψευδής) c.io.instruction.poke("b0010000100001001".U) // r1 = 33 c.io.branch.expect(0.U) // δοκιμή εντολής beq c.io.instruction.poke("b0100000001010100".U) // if r1 == r2 then pc += 4 c.io.branch.expect(1.U) // η έξοδος branch πρέπει να είναι 1 (αληθής) c.io.branch_offset.expect("b0000000000000100".U) // το branch_offset πρέπει να είναι +4 c.io.alu_a_sel.expect(1.U) // το alu_a_sel πρέπει να είναι 1 (πράξη μεταξύ καταχωρητών) c.io.read_sel_a.expect(1.U) // το read_sel_a πρεπει να είναι 1 (Rscr1 = r1) c.io.read_sel_b.expect(2.U) // το read_sel_b πρεπει να είναι 2 (Rscr2 = r2) c.io.sel.expect("b11".U) // το sel πρέπει να είναι b11 (+/-) c.io.sub.expect(1.U) // το sub πρέπει να είναι 1 (αφαίρεση) c.io.write_sel.expect(0.U) // το write_sel πρέπει να είναι 0 (προορισμός = r0) // δοκιμή επέκτασης προσήμου για το branch_offset c.io.instruction.poke("b0101111001010111".U) // if r1 == r2 then pc += -1 c.io.branch_offset.expect("b1111111111111111".U) // ο αριθμός -1 επεκταμένος στα 16 bits } println("SUCCESS!!") class InstructionMemory(addr_width: Int, instr_width: Int, content: Seq[UInt]) extends Module { // αντιγράψτε από προηγούμενα } class FetchUnit(addr_width: Int, instr_width: Int, content: Seq[UInt]) extends Module { // αντιγράψτε από προηγούμενα } class Cpu(instructions: Seq[UInt]) extends Module { // αντιγράψτε από προηγούμενα και τροποποιήστε σύμφωνα με τις οδηγίες } val instructions = List("b0010000001010001".U, // r1 = 10 (limit = 10) "b0010000000000010".U, // r2 = 0 (sum = 0) "b0010000000001011".U, // r3 = 1 (counter = 1) "b0010000000001100".U, // r4 = 1 (constant 1) "b0000011010011010".U, // r2 = r2 + r1 (sum = sum + counter) "b0000011011100011".U, // r3 = r3 + r4 (counter++) "b0000111001100001".U, // r1 = r1 - r4 (limit--) "b0100000001000001".U, // beq r1,r0,+1 (if limit==0 then pc <- (pc+1)+1) "b0101111000000011".U, // beq r0,r0,-5 (pc <- (pc+1)-5) "b0000001010000000".U, // r0 = r2 or r0 (to show r2 contents) "b0011111111111000".U, // r0 = 0xFFFF (to mark end of program) ) test(new Cpu(instructions)) { c => for (i <- 0 until 54) { println(c.io.results.peek()) c.clock.step() } c.io.results.expect("b1111111111111111".U) // must be the program's end marker } println("SUCCESS!!")