├── .ocamlformat ├── arty ├── outputs │ └── .gitignore ├── .gitignore ├── dune ├── ips │ └── design_1_clk_wiz_0_0 │ │ ├── design_1_clk_wiz_0_0_board.xdc │ │ ├── design_1_clk_wiz_0_0_ooc.xdc │ │ ├── design_1_clk_wiz_0_0.xdc │ │ ├── design_1_clk_wiz_0_0.veo │ │ ├── design_1_clk_wiz_0_0.v │ │ ├── design_1_clk_wiz_0_0_clk_wiz.v │ │ └── doc │ │ └── clk_wiz_v6_0_changelog.txt ├── route.tcl ├── dune-project ├── .Xil │ └── hardcaml_arty_top_propImpl.xdc ├── hardcaml_mips_arty.opam ├── Makefile ├── synth.tcl ├── place.tcl ├── arty.ml └── boards │ └── arty-a7-35 │ └── E.0 │ ├── part0_pins.xml │ ├── mig.prj │ └── preset.xml ├── lib ├── io │ ├── memory.mli │ ├── delay_test_io.mli │ ├── io_intf.ml │ ├── memory.ml │ ├── uart.mli │ ├── delay_test_io.ml │ └── uart.ml ├── dune ├── width_check.ml ├── program.mli ├── cpu.mli ├── writeback │ └── writeback.ml ├── instruction_decode │ ├── stall_unit.ml │ ├── forwarding_unit.ml │ ├── instruction_decode.ml │ └── control_unit.ml ├── instruction_execute │ ├── instruction_execute.ml │ └── alu.ml ├── instruction_fetch │ ├── gen_next_pc.ml │ └── instruction_fetch.ml ├── program.ml ├── cpu.ml └── datapath.ml ├── .gitignore ├── test ├── dune ├── instruction_fetch │ └── test_instruction_fetch.ml ├── test_writeback │ └── test_writeback.ml ├── instruction_decode │ ├── test_stall_unit.ml │ ├── test_forwarding_unit.ml │ └── test_instruction_decode.ml ├── instruction_execute │ ├── test_alu.ml │ └── test_instruction_execute.ml └── io │ ├── test_memory.ml │ ├── uart │ └── test_uart_tx.ml │ └── test_delay_test_io.ml ├── dune ├── main.ml ├── dune-project ├── README.md ├── hardcaml_mips.opam ├── LICENSE ├── interactive.ml ├── .github └── workflows │ └── test.yml └── CHANGELOG.md /.ocamlformat: -------------------------------------------------------------------------------- 1 | version=0.21.0 -------------------------------------------------------------------------------- /arty/outputs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /lib/io/memory.mli: -------------------------------------------------------------------------------- 1 | include Io_intf.Io_intf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | _build 3 | verilog 4 | mips_datapath.v -------------------------------------------------------------------------------- /arty/.gitignore: -------------------------------------------------------------------------------- 1 | hardcaml_arty_top.v 2 | tight_setup_hold_pins.txt 3 | .Xil -------------------------------------------------------------------------------- /arty/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name arty) 3 | (modules arty) 4 | (libraries hardcaml hardcaml_arty hardcaml_mips)) 5 | -------------------------------------------------------------------------------- /lib/io/delay_test_io.mli: -------------------------------------------------------------------------------- 1 | include Io_intf.Io_intf 2 | 3 | (* For testing purposes, delay writes by 2 clock cycles, 4 | * and reads by 3 clock cycles. 5 | * Used to test datapath pausing. 6 | *) -------------------------------------------------------------------------------- /lib/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name Mips) 3 | (public_name hardcaml_mips) 4 | (libraries hardcaml hardcaml_arty) 5 | (preprocess 6 | (pps ppx_jane ppx_deriving_hardcaml))) 7 | 8 | (include_subdirs unqualified) 9 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_board.xdc: -------------------------------------------------------------------------------- 1 | #--------------------Physical Constraints----------------- 2 | 3 | set_property BOARD_PIN {clk} [get_ports clk_in1] 4 | set_property BOARD_PIN {reset} [get_ports resetn] 5 | -------------------------------------------------------------------------------- /test/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name test_mips) 3 | (inline_tests 4 | (flags (-verbose))) 5 | (libraries hardcaml hardcaml_waveterm hardcaml_mips) 6 | (preprocess 7 | (pps ppx_jane ppx_expect))) 8 | 9 | (include_subdirs unqualified) 10 | -------------------------------------------------------------------------------- /dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name main) 3 | (modules main) 4 | (libraries hardcaml hardcaml_mips)) 5 | 6 | (executable 7 | (name interactive) 8 | (modules interactive) 9 | (libraries hardcaml hardcaml_waveterm hardcaml_waveterm.interactive hardcaml_mips)) 10 | -------------------------------------------------------------------------------- /lib/width_check.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | 3 | module With_interface (I : Interface.S) (O : Interface.S) = 4 | struct 5 | let check_widths circuit_impl i = 6 | I.Of_signal.assert_widths i; 7 | let out = circuit_impl i in 8 | O.Of_signal.assert_widths out; 9 | out 10 | end 11 | -------------------------------------------------------------------------------- /lib/program.mli: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | 3 | type t 4 | 5 | (* The input should be a list of MIPS instructions in hexadecimal format *) 6 | val create : string list -> t 7 | 8 | val to_signals : t -> Signal.t list 9 | 10 | (* An example program instance used for testing *) 11 | val sample : t 12 | -------------------------------------------------------------------------------- /lib/cpu.mli: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | 3 | module I = Hardcaml_arty.User_application.I 4 | 5 | module O : sig 6 | type 'a t = { 7 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; 8 | ethernet : 'a Hardcaml_arty.User_application.Ethernet.O.t; 9 | writeback_data : 'a; 10 | writeback_pc : 'a; 11 | } 12 | [@@deriving sexp_of, hardcaml] 13 | end 14 | 15 | val circuit_impl : Program.t -> Scope.t -> Signal.t I.t -> Signal.t O.t 16 | -------------------------------------------------------------------------------- /main.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Mips 3 | module MipsCircuit = Circuit.With_interface (Cpu.I) (Cpu.O) 4 | 5 | let scope = Scope.create () 6 | 7 | let circuit = 8 | let bound_circuit_impl = Cpu.circuit_impl Program.sample scope in 9 | MipsCircuit.create_exn ~name:"cpu" bound_circuit_impl 10 | 11 | let output_mode = Rtl.Output_mode.To_file("mips_cpu.v") 12 | 13 | let () = Rtl.output ~output_mode ~database:(Scope.circuit_database scope) Verilog circuit 14 | -------------------------------------------------------------------------------- /arty/route.tcl: -------------------------------------------------------------------------------- 1 | set_param board.repoPaths "boards/" 2 | set output_dir "outputs/" 3 | 4 | open_checkpoint $output_dir/post_place.dcp 5 | 6 | route_design 7 | 8 | write_checkpoint -force $output_dir/post_route 9 | report_timing_summary -file $output_dir/post_route_timing_summary.rpt 10 | report_bus_skew -file $output_dir/post_route_bus_skew.rpt 11 | report_utilization -file $output_dir/post_route_utilization.rpt 12 | write_bitstream -force $output_dir/hardcaml_arty_top.bit 13 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.8) 2 | 3 | (cram enable) 4 | 5 | (package 6 | (name hardcaml_mips) 7 | (synopsis "A simple MIPS CPU learning project in Hardcaml.")) 8 | 9 | (version 1.0.0) 10 | 11 | (generate_opam_files true) 12 | 13 | (source 14 | (github askvortsov1/hardcaml-mips)) 15 | 16 | (license MIT) 17 | 18 | (authors "Alexander Skvortsov" "Mayur Deshpande") 19 | 20 | (maintainers "sasha.skvortsov109@gmail.com") 21 | 22 | (homepage "https://ceramichacker.com/blog/category/hardcaml-mips") 23 | -------------------------------------------------------------------------------- /arty/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.8) 2 | 3 | (cram enable) 4 | 5 | (package 6 | (name hardcaml_mips_arty) 7 | (synopsis "A wrapper for hardcaml_mips on the Arty A7 FPGA.")) 8 | 9 | (version 1.0.0) 10 | 11 | (generate_opam_files true) 12 | 13 | (source 14 | (github askvortsov1/hardcaml-mips)) 15 | 16 | (license MIT) 17 | 18 | (authors "Alexander Skvortsov" "Mayur Deshpande") 19 | 20 | (maintainers "sasha.skvortsov109@gmail.com") 21 | 22 | (homepage "https://ceramichacker.com/blog/category/hardcaml-mips") 23 | -------------------------------------------------------------------------------- /arty/.Xil/hardcaml_arty_top_propImpl.xdc: -------------------------------------------------------------------------------- 1 | set_property SRC_FILE_INFO {cfile:/home/Programming/Projects/hardcaml-mips/arty/outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc rfile:../outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc id:1 order:EARLY scoped_inst:the_design_1_clk_wiz_0_0/inst} [current_design] 2 | current_instance the_design_1_clk_wiz_0_0/inst 3 | set_property src_info {type:SCOPED_XDC file:1 line:57 export:INPUT save:INPUT read:READ} [current_design] 4 | set_input_jitter [get_clocks -of_objects [get_ports clk_in1]] 0.100 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hardcaml MIPS CPU 2 | 3 | Hi! We are Sasha Skvortsov and Mayur Deshpande. As a followup to a class project, we are designing a simple 5-stage MIPS CPU in OCaml via the [HardCaml](https://github.com/janestreet/hardcaml) library. You can read more about this project at the [CeramicHacker](https://ceramichacker.com/t/hardcaml-mips) blog. 4 | 5 | ## Code Structure 6 | 7 | There are 3 main components to this codebase: 8 | 9 | - In `lib`: source code for the MIPS CPU 10 | - In `test`: Unit and integration tests for the MIPS CPU 11 | - In the project root: a `main.ml` file that prints the design from `lib` into Verilog 12 | 13 | ## How to Use 14 | 15 | Coming Soon 16 | -------------------------------------------------------------------------------- /lib/io/io_intf.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module type Io_intf = sig 5 | module I : sig 6 | type 'a t = { 7 | clock : 'a; [@bits 1] 8 | write_enable : 'a; [@bits 1] 9 | write_addr : 'a; [@bits 32] 10 | write_data : 'a; [@bits 32] 11 | read_enable : 'a; [@bits 1] 12 | read_addr : 'a; [@bits 32] 13 | } 14 | [@@deriving sexp_of, hardcaml] 15 | end 16 | 17 | module O : sig 18 | type 'a t = { 19 | io_busy : 'a; [@bits 1] 20 | read_data : 'a; [@bits 32] 21 | } 22 | [@@deriving sexp_of, hardcaml] 23 | end 24 | 25 | val circuit_impl : Scope.t -> t I.t -> t O.t 26 | 27 | val hierarchical : Scope.t -> t I.t -> t O.t 28 | end 29 | -------------------------------------------------------------------------------- /hardcaml_mips.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | version: "1.0.0" 4 | synopsis: "A simple MIPS CPU learning project in Hardcaml." 5 | maintainer: ["sasha.skvortsov109@gmail.com"] 6 | authors: ["Alexander Skvortsov" "Mayur Deshpande"] 7 | license: "MIT" 8 | homepage: "https://ceramichacker.com/blog/category/hardcaml-mips" 9 | bug-reports: "https://github.com/askvortsov1/hardcaml-mips/issues" 10 | depends: [ 11 | "dune" {>= "2.8"} 12 | "odoc" {with-doc} 13 | ] 14 | build: [ 15 | ["dune" "subst"] {dev} 16 | [ 17 | "dune" 18 | "build" 19 | "-p" 20 | name 21 | "-j" 22 | jobs 23 | "@install" 24 | "@runtest" {with-test} 25 | "@doc" {with-doc} 26 | ] 27 | ] 28 | dev-repo: "git+https://github.com/askvortsov1/hardcaml-mips.git" 29 | -------------------------------------------------------------------------------- /arty/hardcaml_mips_arty.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | version: "1.0.0" 4 | synopsis: "A wrapper for hardcaml_mips on the Arty A7 FPGA." 5 | maintainer: ["sasha.skvortsov109@gmail.com"] 6 | authors: ["Alexander Skvortsov" "Mayur Deshpande"] 7 | license: "MIT" 8 | homepage: "https://ceramichacker.com/blog/category/hardcaml-mips" 9 | bug-reports: "https://github.com/askvortsov1/hardcaml-mips/issues" 10 | depends: [ 11 | "dune" {>= "2.8"} 12 | "odoc" {with-doc} 13 | ] 14 | build: [ 15 | ["dune" "subst"] {dev} 16 | [ 17 | "dune" 18 | "build" 19 | "-p" 20 | name 21 | "-j" 22 | jobs 23 | "@install" 24 | "@runtest" {with-test} 25 | "@doc" {with-doc} 26 | ] 27 | ] 28 | dev-repo: "git+https://github.com/askvortsov1/hardcaml-mips.git" 29 | -------------------------------------------------------------------------------- /arty/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: ../_build/default/arty/arty.exe 2 | 3 | ../_build/default/arty/arty.exe: 4 | dune build arty.exe 5 | 6 | hardcaml_arty_top.v: ../_build/default/arty/arty.exe 7 | $< >$@ 8 | 9 | outputs/post_synth.dcp: synth.tcl hardcaml_arty_top.v 10 | vivado -nojournal -mode batch -source synth.tcl -log outputs/synth.log 11 | 12 | outputs/post_place.dcp: place.tcl outputs/post_synth.dcp 13 | vivado -nojournal -mode batch -source place.tcl -log outputs/place.log 14 | 15 | outputs/hardcaml_arty_top.bit outputs/post_route.dcp: route.tcl outputs/post_place.dcp 16 | vivado -nojournal -mode batch -source route.tcl -log outputs/route.log 17 | rm -f usage_statistics_webtalk.html usage_statistics_webtalk.xml 18 | 19 | make build: 20 | make outputs/hardcaml_arty_top.bit 21 | 22 | make prog: 23 | djtgcfg prog --file outputs/hardcaml_arty_top.bit -d Arty -i 0 24 | 25 | clean: 26 | rm -f outputs/* 27 | -------------------------------------------------------------------------------- /lib/writeback/writeback.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | sel_mem_for_reg_data : 'a; 7 | alu_result : 'a; [@bits 32] 8 | data_output : 'a; [@bits 32] 9 | } 10 | [@@deriving sexp_of, hardcaml] 11 | end 12 | 13 | module O = struct 14 | type 'a t = { writeback_data : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 15 | end 16 | 17 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 18 | let writeback_data = 19 | mux2 input.sel_mem_for_reg_data input.data_output input.alu_result 20 | in 21 | { O.writeback_data } 22 | 23 | let circuit_impl_exn scope input = 24 | let module W = Width_check.With_interface (I) (O) in 25 | W.check_widths (circuit_impl scope) input 26 | 27 | let hierarchical scope input = 28 | let module H = Hierarchy.In_scope (I) (O) in 29 | H.hierarchical ~scope ~name:"writeback" circuit_impl_exn input 30 | -------------------------------------------------------------------------------- /lib/instruction_decode/stall_unit.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | e_sel_mem_for_reg_data : 'a; 7 | rs : 'a; [@bits 5] 8 | rt : 'a; [@bits 5] 9 | e_dest: 'a; [@bits 5] 10 | } 11 | [@@deriving sexp_of, hardcaml] 12 | end 13 | 14 | module O = struct 15 | type 'a t = { stall_pc: 'a } [@@deriving sexp_of, hardcaml] 16 | end 17 | 18 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 19 | let lw_in_execute = input.e_sel_mem_for_reg_data in 20 | let uses_execute_output = ((input.rs ==: input.e_dest) |: (input.rt ==: input.e_dest)) in 21 | let stall_pc = lw_in_execute &: uses_execute_output in 22 | 23 | { O.stall_pc } 24 | 25 | let circuit_impl_exn scope input = 26 | let module W = Width_check.With_interface (I) (O) in 27 | W.check_widths (circuit_impl scope) input 28 | 29 | let hierarchical scope input = 30 | let module H = Hierarchy.In_scope (I) (O) in 31 | H.hierarchical ~scope ~name:"stall_unit" circuit_impl_exn input 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021-Present Alexander Skvortsov, Mayur Deshpande 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /arty/synth.tcl: -------------------------------------------------------------------------------- 1 | set_param board.repoPaths "boards/" 2 | 3 | create_project -in_memory -part xc7a35ticsg324-1L 4 | set_property board_part digilentinc.com:arty-a7-35:part0:1.0 [current_project] 5 | set output_dir "./outputs" 6 | 7 | exec rm -rf outputs/ips 8 | exec cp -r ips/ outputs/ips 9 | read_ip -verbose outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xci 10 | 11 | # TODO(fyquah): It is unfortunate that we need to comment this out by hand. Our 12 | # RTL generator should know that the thernet mac isn't used, and hence 13 | # shouldn't be read here. This can be fixed by generating tcl files. 14 | # read_ip -verbose ips/hardcaml_arty_tri_mode_ethernet_mac_0/hardcaml_arty_tri_mode_ethernet_mac_0.xci 15 | read_verilog hardcaml_arty_top.v 16 | 17 | upgrade_ip [get_ips] 18 | set_property generate_synth_checkpoint false [get_files outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xci] 19 | # set_property generate_synth_checkpoint false [get_files ips/hardcaml_arty_tri_mode_ethernet_mac_0/hardcaml_arty_tri_mode_ethernet_mac_0.xci] 20 | generate_target all [get_ips] 21 | validate_ip [get_ips] 22 | 23 | synth_design -top hardcaml_arty_top 24 | write_checkpoint -force "${::output_dir}/post_synth.dcp" 25 | -------------------------------------------------------------------------------- /lib/io/memory.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | clock : 'a; [@bits 1] 7 | write_enable : 'a; [@bits 1] 8 | write_addr : 'a; [@bits 32] 9 | write_data : 'a; [@bits 32] 10 | read_enable : 'a; [@bits 1] 11 | read_addr : 'a; [@bits 32] 12 | } 13 | [@@deriving sexp_of, hardcaml] 14 | end 15 | 16 | module O = struct 17 | type 'a t = { io_busy : 'a; [@bits 1] read_data : 'a [@bits 32] } 18 | [@@deriving sexp_of, hardcaml] 19 | end 20 | 21 | let data_memory write_clock write_enable write_data write_addr read_addr = 22 | let write_port = 23 | { write_clock; write_address = write_addr; write_enable; write_data } 24 | in 25 | let mem = 26 | multiport_memory 512 ~write_ports:[| write_port |] 27 | ~read_addresses:[| read_addr |] 28 | in 29 | Array.get mem 0 30 | 31 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 32 | let read_data = 33 | data_memory input.clock input.write_enable input.write_data input.write_addr 34 | input.read_addr 35 | in 36 | { O.read_data; io_busy = of_bool false } 37 | 38 | let hierarchical scope input = 39 | let module H = Hierarchy.In_scope (I) (O) in 40 | H.hierarchical ~scope ~name:"memory" circuit_impl input 41 | -------------------------------------------------------------------------------- /interactive.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Cpu 4 | 5 | module Simulator = Cyclesim.With_interface (I) (O) 6 | 7 | let testbench n = 8 | let scope = Scope.create ~auto_label_hierarchical_ports:true ~flatten_design:true () in 9 | let program = 10 | Mips.Program.create 11 | [ 12 | "3C08FFFF" (* lui t0 0xFFFF *); 13 | "3508FFFF" (* ori t0 t0 0xFFFF *); 14 | "214A0008" (* addi $t2 $t2 0x0008 *); 15 | "216B0004" (* addi $t3 $t3 0x0004 *); 16 | "8D0C0000" (* lw $t4 0($t0) *); 17 | "000C6820" (* add $t5 $zero $t4 *); 18 | "000C6820" (* add $t5 $zero $t4 *); 19 | "000C6820" (* add $t5 $zero $t4 *); 20 | "000C6820" (* add $t5 $zero $t4 *); 21 | "000C6820" (* add $t5 $zero $t4 *); 22 | "214A0008" (* addi $t2 $t3 0x0008 *); 23 | "216B0006" (* addi $t3 $t2 0x0006 *); 24 | ] 25 | in 26 | let sim = Simulator.create ~config:Cyclesim.Config.trace_all (circuit_impl program scope) in 27 | let waves, sim = Waveform.create sim in 28 | 29 | for _i = 0 to n do 30 | Cyclesim.cycle sim 31 | done; 32 | 33 | waves 34 | 35 | let () = 36 | let waves = testbench 15 in 37 | Hardcaml_waveterm_interactive.run ~wave_width:5 ~signals_width:30 waves -------------------------------------------------------------------------------- /lib/instruction_execute/instruction_execute.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | alu_a : 'a; [@bits 32] 7 | alu_b : 'a; [@bits 32] 8 | imm : 'a; [@bits 32] 9 | sel_shift_for_alu: 'a; 10 | sel_imm_for_alu: 'a; 11 | alu_control : 'a; [@bits (width Control_unit.Alu_ops.default)] 12 | jal : 'a; 13 | prev2_pc : 'a; [@bits 32] 14 | } 15 | [@@deriving sexp_of, hardcaml] 16 | end 17 | 18 | module O = struct 19 | type 'a t = { alu_result : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 20 | end 21 | 22 | let circuit_impl (scope : Scope.t) (input : _ I.t) = 23 | let shift_amount = uresize input.imm.:[10, 6] 32 in 24 | let arg_a = mux2 input.sel_shift_for_alu shift_amount input.alu_a in 25 | let arg_b = mux2 input.sel_imm_for_alu input.imm input.alu_b in 26 | let alu = Alu.hierarchical scope { Alu.I.arg_a; arg_b; alu_control = input.alu_control} in 27 | let alu_result = mux2 input.jal (input.prev2_pc +:. 8) alu.result in 28 | { O.alu_result } 29 | 30 | let circuit_impl_exn scope input = 31 | let module W = Width_check.With_interface (I) (O) in 32 | W.check_widths (circuit_impl scope) input 33 | 34 | let hierarchical scope input = 35 | let module H = Hierarchy.In_scope (I) (O) in 36 | H.hierarchical ~scope ~name:"instruction_execute" circuit_impl_exn input 37 | -------------------------------------------------------------------------------- /lib/io/uart.mli: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module Word_with_valid : sig 5 | include Hardcaml.Interface.S with type 'a t = 'a With_valid.t 6 | end 7 | 8 | val cycles_per_packet : int 9 | 10 | module Rx_buffer : sig 11 | val create : 12 | clock:Signal.t -> 13 | read_enable:Signal.t -> 14 | Signal.t Hardcaml_arty.Uart.Byte_with_valid.t -> 15 | (Signal.t Word_with_valid.t * Signal.t) 16 | end 17 | 18 | module Tx_buffer : sig 19 | val create : 20 | clock:Signal.t -> 21 | Signal.t Word_with_valid.t -> 22 | (Signal.t Hardcaml_arty.Uart.Byte_with_valid.t * Signal.t) 23 | end 24 | 25 | module I : sig 26 | type 'a t = { 27 | clock : 'a; [@bits 1] 28 | write_enable : 'a; [@bits 1] 29 | write_addr : 'a; [@bits 32] 30 | write_data : 'a; [@bits 32] 31 | read_enable : 'a; [@bits 1] 32 | read_addr : 'a; [@bits 32] 33 | uart_rx : 'a Hardcaml_arty.Uart.Byte_with_valid.t;[@rtlprefix "rx_"] 34 | } 35 | [@@deriving sexp_of, hardcaml] 36 | end 37 | 38 | module O : sig 39 | type 'a t = { 40 | io_busy : 'a; [@bits 1] 41 | read_data : 'a; [@bits 32] 42 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t;[@rtlprefix "tx_"] 43 | } 44 | [@@deriving sexp_of, hardcaml] 45 | end 46 | 47 | val circuit_impl : Scope.t -> t I.t -> t O.t 48 | 49 | val hierarchical : Scope.t -> t I.t -> t O.t -------------------------------------------------------------------------------- /lib/instruction_fetch/gen_next_pc.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | pc : 'a; [@bits 32] 7 | prev_pc : 'a; [@bits 32] 8 | alu_a : 'a; [@bits 32] 9 | alu_b : 'a; [@bits 32] 10 | addr: 'a; [@bits 26] 11 | se_imm: 'a; [@bits 32] 12 | pc_sel: 'a Control_unit.Pc_sel.Binary.t; 13 | } 14 | 15 | [@@deriving sexp_of, hardcaml] 16 | end 17 | 18 | module O = struct 19 | type 'a t = { next_pc : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 20 | end 21 | 22 | 23 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 24 | let open Control_unit.Pc_sel.Enum in 25 | let pc_incr = input.pc +:. 4 in 26 | let branch_addr = input.prev_pc +:. 4 +: (sll input.se_imm 2) in 27 | let next_pc = Control_unit.Pc_sel.Binary.match_ (module Signal) input.pc_sel 28 | [ 29 | Pc_incr, pc_incr; 30 | Jump_addr, input.pc.:[31, 28] @: (sll (uresize input.addr 28) 2); 31 | Jump_reg, input.alu_a; 32 | Branch_eq, mux2 (input.alu_a ==: input.alu_b) branch_addr pc_incr; 33 | Branch_neq, mux2 (input.alu_a <>: input.alu_b) branch_addr pc_incr; 34 | ] in 35 | 36 | { O.next_pc } 37 | 38 | let circuit_impl_exn scope input = 39 | let module W = Width_check.With_interface (I) (O) in 40 | W.check_widths (circuit_impl scope) input 41 | 42 | let hierarchical scope input = 43 | let module H = Hierarchy.In_scope (I) (O) in 44 | H.hierarchical ~scope ~name:"gen_next_pc" circuit_impl_exn input 45 | 46 | 47 | -------------------------------------------------------------------------------- /lib/instruction_execute/alu.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | arg_a : 'a; [@bits 32] 7 | arg_b : 'a; [@bits 32] 8 | alu_control : 'a; [@bits (width Control_unit.Alu_ops.default)] 9 | } 10 | [@@deriving sexp_of, hardcaml] 11 | end 12 | 13 | module O = struct 14 | type 'a t = { result : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 15 | end 16 | 17 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 18 | let result = Always.Variable.wire ~default:(of_string "32'b0") in 19 | let module Op = Control_unit.Alu_ops in 20 | let a = input.arg_a in 21 | let b = input.arg_b in 22 | Always.( 23 | compile 24 | [ 25 | switch input.alu_control 26 | [ 27 | (Op.add, [ result <-- a +: b ]); 28 | (Op.addu, [ result <-- a +: b ]); 29 | (Op.and_, [ result <-- (a &: b) ]); 30 | (Op.lui, [ result <-- b.:[(15, 0)] @: of_string "16'h0" ]); 31 | (Op.or_, [ result <-- (a |: b) ]); 32 | (Op.slt, [ result <-- uresize (a <: b) 32 ]); 33 | (Op.sltu, [ result <-- uresize (a <+ b) 32 ]); 34 | (Op.sll, [ result <-- log_shift sll b a ]); 35 | (Op.sra, [ result <-- log_shift sra b a ]); 36 | (Op.srl, [ result <-- log_shift srl b a ]); 37 | (Op.sub, [ result <-- a -: b ]); 38 | (Op.subu, [ result <-- a -: b ]); 39 | (Op.xor, [ result <-- a ^: b ]); 40 | ]; 41 | ]); 42 | 43 | { O.result = Always.Variable.value result } 44 | 45 | let circuit_impl_exn scope input = 46 | let module W = Width_check.With_interface (I) (O) in 47 | W.check_widths (circuit_impl scope) input 48 | 49 | let hierarchical scope input = 50 | let module H = Hierarchy.In_scope (I) (O) in 51 | H.hierarchical ~scope ~name:"alu" circuit_impl_exn input 52 | -------------------------------------------------------------------------------- /lib/instruction_fetch/instruction_fetch.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { pc : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 6 | end 7 | 8 | module O = struct 9 | type 'a t = { instruction : 'a; [@bits 32] } 10 | [@@deriving sexp_of, hardcaml] 11 | end 12 | 13 | (* In an actual computer, instruction memory would be actual memory, 14 | * and we would use Hardcaml's `multiport_memory` primitive to implement it. 15 | * 16 | * Unfortunately, that primitive doesn't support initial values, so testing would 17 | * require either a complex sequence of `reset` logic or a physical RAM device. 18 | * 19 | * The former would be messy and the latter beyond the scope of this project, 20 | * but we still don't want to hardcode a particular program as part of the design. 21 | * Instead, to keep things simple, we consider the program to be an input to our Hardcaml CPU. 22 | *) 23 | let instruction_memory program address = 24 | (* When the selector > length inputs, Hardcaml's mux will just repeat the last element. 25 | * To avoid unexpected effects if `pc` goes beyond the length of our program, 26 | * we append a noop to our program. *) 27 | let program_signals = Program.to_signals program @ [ of_string "32'h0" ] in 28 | mux address program_signals 29 | 30 | let circuit_impl (program : Program.t) (_scope : Scope.t) (input : _ I.t) = 31 | let address = srl input.pc 2 in 32 | let instruction = instruction_memory program address in 33 | { O.instruction } 34 | 35 | let circuit_impl_exn program scope input = 36 | let module W = Width_check.With_interface (I) (O) in 37 | W.check_widths (circuit_impl program scope) input 38 | 39 | let hierarchical program scope input = 40 | let module H = Hierarchy.In_scope (I) (O) in 41 | H.hierarchical ~scope ~name:"instruction_fetch" (circuit_impl_exn program) 42 | input 43 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the main branch 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | branches: [ main ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | 17 | 18 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 19 | jobs: 20 | # This workflow contains a single job called "build" 21 | build: 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: 26 | - ubuntu-latest 27 | ocaml-compiler: 28 | - 4.13.x 29 | 30 | runs-on: ${{ matrix.os }} 31 | 32 | # Steps represent a sequence of tasks that will be executed as part of the job 33 | steps: 34 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 35 | - uses: actions/checkout@v2 36 | 37 | - name: Set up OCaml 38 | uses: ocaml/setup-ocaml@v2 39 | with: 40 | ocaml-compiler: ${{ matrix.ocaml-compiler }} 41 | 42 | - name: Set up source repos 43 | run: | 44 | opam repo add janestreet-bleeding https://ocaml.janestreet.com/opam-repository 45 | opam repo add janestreet-bleeding-external https://github.com/janestreet/opam-repository.git#external-packages 46 | eval $(opam env) 47 | 48 | - name: Install Deps 49 | run: | 50 | opam install dune core hardcaml hardcaml_waveterm ppx_deriving_hardcaml ppx_expect ppx_jane 51 | opam pin add https://github.com/askvortsov1/hardcaml_arty.git#as/make-installable --yes 52 | eval $(opam env) 53 | 54 | - name: Build 55 | run: opam exec -- dune build 56 | 57 | - name: Testing 58 | run: opam exec -- dune test 59 | -------------------------------------------------------------------------------- /arty/place.tcl: -------------------------------------------------------------------------------- 1 | set_param board.repoPaths "boards/" 2 | set output_dir "outputs/" 3 | 4 | open_checkpoint $output_dir/post_synth.dcp 5 | 6 | ######################## 7 | # Various pin placements 8 | ######################## 9 | 10 | proc bind_port_to_pin { port_name pin_name } { 11 | set port [get_ports "$port_name"] 12 | set pin [get_board_part_pins "$pin_name"] 13 | set loc [get_property LOC $pin] 14 | set iostandard [get_property IOSTANDARD $pin] 15 | 16 | set_property PACKAGE_PIN $loc $port 17 | set_property IOSTANDARD $iostandard $port 18 | } 19 | 20 | proc bind_ports_vector_to_pins {port_format pin_format n} { 21 | for { set i 0 } { $i < $n } { incr i } { 22 | set port_name [format $port_format $i] 23 | set pin_name [format $pin_format $i] 24 | bind_port_to_pin $port_name $pin_name 25 | } 26 | } 27 | 28 | bind_ports_vector_to_pins "led_4bits\[%d\]" "led_4bits_tri_o_%d" 4 29 | bind_ports_vector_to_pins "led_rgb\[%d\]" "rgb_led_tri_o_%d" 12 30 | bind_ports_vector_to_pins "push_buttons_4bits\[%d\]" "push_buttons_4bits_tri_i_%d" 4 31 | bind_port_to_pin "usb_uart_rx" "usb_uart_rxd" 32 | bind_port_to_pin "usb_uart_tx" "usb_uart_txd" 33 | bind_port_to_pin "sys_clock" "clk" 34 | bind_port_to_pin "reset" "reset" 35 | 36 | bind_ports_vector_to_pins "eth_mii_rxd\[%d\]" "eth_rxd_%d" 4 37 | bind_port_to_pin "eth_mii_rx_er" "eth_rx_er" 38 | bind_port_to_pin "eth_mii_rx_dv" "eth_rx_dv" 39 | bind_port_to_pin "eth_mii_rx_clk" "eth_rx_clk" 40 | bind_port_to_pin "eth_mii_tx_clk" "eth_tx_clk" 41 | 42 | bind_port_to_pin "eth_mii_tx_en" "eth_tx_en" 43 | bind_ports_vector_to_pins "eth_mii_txd\[%d\]" "eth_txd_%d" 4 44 | 45 | bind_port_to_pin "mdc" "eth_mdc" 46 | 47 | opt_design 48 | place_design 49 | phys_opt_design 50 | 51 | write_checkpoint -force $output_dir/post_place 52 | report_timing_summary -file $output_dir/post_place_timing_summary.rpt 53 | -------------------------------------------------------------------------------- /lib/program.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | type t = Signal.t list 5 | 6 | let create program = 7 | program 8 | |> List.map (fun str -> "32'h" ^ str) 9 | |> List.map of_string 10 | 11 | let to_signals program = program 12 | 13 | let sample_strings = 14 | [ 15 | "3c010000"; (* (00) main: lui $1, 0 *) 16 | "34240050"; (* (04) ori $4, $1, 50 *) 17 | "0c00001b"; (* (08) call: jal sum *) 18 | "20050004"; (* (0c) dslot1: addi $5, $0, 4 *) 19 | "ac820000"; (* (10) return: sw $2, 0($4) *) 20 | "8c890000"; (* (14) lw $9, 0($4) *) 21 | "01244022"; (* (18) sub $8, $9, $4 *) 22 | "20050003"; (* (1c) addi $5, $0, 3 *) 23 | "20a5ffff"; (* (20) loop2: addi $5, $5, -1 *) 24 | "34a8ffff"; (* (24) ori $8, $5, 0xffff *) 25 | "39085555"; (* (28) xori $8, $8, 0x5555 *) 26 | "2009ffff"; (* (2c) addi $9, $0, -1 *) 27 | "312affff"; (* (30) andi $10,$9,0xffff *) 28 | "01493025"; (* (34) or $6, $10, $9 *) 29 | "01494026"; (* (38) xor $8, $10, $9 *) 30 | "01463824"; (* (3c) and $7, $10, $6 *) 31 | "10a00003"; (* (40) beq $5, $0, shift *) 32 | "00000000"; (* (44) dslot2: nop *) 33 | "08000008"; (* (48) j loop2 *) 34 | "00000000"; (* (4c) dslot3: nop *) 35 | "2005ffff"; (* (50) shift: addi $5, $0, -1 *) 36 | "000543c0"; (* (54) sll $8, $5, 15 *) 37 | "00084400"; (* (58) sll $8, $8, 16 *) 38 | "00084403"; (* (5c) sra $8, $8, 16 *) 39 | "000843c2"; (* (60) srl $8, $8, 15 *) 40 | "08000019"; (* (64) finish: j finish *) 41 | "00000000"; (* (68) dslot4: nop *) 42 | "00004020"; (* (6c) sum: add $8, $0, $0 *) 43 | "8c890000"; (* (70) loop: lw $9, 0($4) *) 44 | "01094020"; (* (74) stall: add $8, $8, $9 *) 45 | "20a5ffff"; (* (78) addi $5, $5, -1 *) 46 | "14a0fffc"; (* (7c) bne $5, $0, loop *) 47 | "20840004"; (* (80) dslot5: addi $4, $4, 4 *) 48 | "03e00008"; (* (84) jr $31 *) 49 | "00081000"; (* (88) dslot6: sll $2, $8, 0 *) 50 | ] 51 | 52 | let sample = create sample_strings 53 | -------------------------------------------------------------------------------- /arty/arty.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml.Signal 2 | module UA = Hardcaml_arty.User_application 3 | 4 | let rgb_off = 5 | { 6 | Hardcaml_arty.User_application.Led_rgb.r = of_bool false; 7 | g = of_bool false; 8 | b = of_bool false; 9 | } 10 | 11 | let sample = 12 | Mips.Program.create 13 | [ 14 | "3C10FFFF" (* (0) lui $s0 0xFFFF *); 15 | "3610FFFE" (* (4) ori $s0 $s0 0xFFFE *); 16 | "20110030" (* (8) addi $s1 $zero 0x0030 *); 17 | "356B3A20" (* (C) ori $t3 $t3 0x3A20 *); 18 | "AE0B0000" (* (10) sw $t3 0x0000 $s0 *); 19 | "8E080000" (* (14) lw $t0 0x0000 $s0 *); 20 | "AE080000" (* (18) sw $t0 0x0000 $s0 *); 21 | "3C0B0A00" (* (1C) lui $t3 0x0A00 *); 22 | "356B0000" (* (20) ori $t3 $t3 0x0000 *); 23 | "AE0B0000" (* (24) sw $t3 0x0000 $s0 *); 24 | "3C0B2332" (* (28) lui $t3 0x2332 *); 25 | "356B3A20" (* (2C) ori $t3 $t3 0x3A20 *); 26 | "AE0B0000" (* (30) sw $t3 0x0000 $s0 *); 27 | "8E090000" (* (34) lw $t1 0x0000 $s0 *); 28 | "AE090000" (* (38) sw $t1 0x0000 $s0 *); 29 | "00084602" (* (3C) srl $t0 $t0 0x0018 *); 30 | "00094E02" (* (40) srl $t1 $t1 0x0018 *); 31 | "01114022" (* (44) sub $t0 $t0 $s1 *); 32 | "01314822" (* (48) sub $t1 $t1 $s1 *); 33 | "01095020" (* (4C) add $t2 $t0 $t1 *); 34 | "01515020" (* (50) add $t2 $t2 $s1 *); 35 | "3C0B0A00" (* (54) lui $t3 0x0A00 *); 36 | "356B0000" (* (58) ori $t3 $t3 0x0000 *); 37 | "AE0B0000" (* (5C) sw $t3 0x0000 $s0 *); 38 | "3C0B414E" (* (60) lui $t3 0x414E *); 39 | "356B533A" (* (64) ori $t3 $t3 0x533A *); 40 | "AE0B0000" (* (68) sw $t3 0x0000 $s0 *); 41 | "AE0A0000" (* (6C) sw $t2 0x0000 $s0 *); 42 | "3C0B0A00" (* (70) lui $t3 0x0A00 *); 43 | "356B0000" (* (74) ori $t3 $t3 0x0000 *); 44 | "AE0B0000" (* (78) sw $t3 0x0000 $s0 *); 45 | ] 46 | 47 | let circuit program scope input = 48 | let cpu = Mips.Cpu.circuit_impl program scope input in 49 | { 50 | UA.O.uart_tx = cpu.uart_tx; 51 | ethernet = cpu.ethernet; 52 | led_4bits = cpu.writeback_pc.:[(31, 28)]; 53 | led_rgb = [ rgb_off; rgb_off; rgb_off; rgb_off ]; 54 | } 55 | 56 | let () = 57 | Hardcaml_arty.Rtl_generator.generate ~instantiate_ethernet_mac:false 58 | (circuit sample) (To_channel Stdio.stdout) 59 | -------------------------------------------------------------------------------- /lib/instruction_decode/forwarding_unit.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module Data_options = struct 5 | type 'a t = { 6 | reg_value : 'a; [@bits 32] 7 | e_alu_output : 'a; [@bits 32] 8 | m_alu_output : 'a; [@bits 32] 9 | m_data_output : 'a; [@bits 32] 10 | } 11 | [@@deriving sexp_of, hardcaml] 12 | end 13 | 14 | module Controls = struct 15 | type 'a t = { 16 | e_stalled : 'a; 17 | e_sel_mem_for_reg_data : 'a; 18 | m_sel_mem_for_reg_data : 'a; 19 | e_reg_write_enable : 'a; 20 | m_reg_write_enable : 'a; 21 | } 22 | [@@deriving sexp_of, hardcaml] 23 | end 24 | 25 | module I = struct 26 | type 'a t = { 27 | options : 'a Data_options.t; 28 | controls : 'a Controls.t; 29 | source : 'a; [@bits 5] 30 | e_dest : 'a; [@bits 5] 31 | m_dest : 'a; [@bits 5] 32 | } 33 | [@@deriving sexp_of, hardcaml] 34 | end 35 | 36 | module O = struct 37 | type 'a t = { forward_data : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 38 | end 39 | 40 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 41 | let opt = input.options in 42 | let ctrl = input.controls in 43 | let forward_data = 44 | priority_select_with_default ~default:opt.reg_value 45 | [ 46 | { 47 | With_valid.valid = 48 | (* The last instruction wrote to this register, and was NOT a lw, and WAS NOT stalled. *) 49 | ctrl.e_reg_write_enable 50 | &: (input.source ==: input.e_dest) 51 | &: ~:(ctrl.e_sel_mem_for_reg_data) 52 | &: ~:(ctrl.e_stalled); 53 | value = opt.e_alu_output; 54 | }; 55 | { 56 | With_valid.valid = 57 | (* The 2nd to last instruction wrote to this register, and was an lw. *) 58 | ctrl.m_reg_write_enable 59 | &: (input.source ==: input.m_dest) 60 | &: ctrl.m_sel_mem_for_reg_data; 61 | value = opt.m_data_output; 62 | }; 63 | { 64 | (* The 2nd to last instruction wrote to this register *) 65 | With_valid.valid = 66 | ctrl.m_reg_write_enable &: (input.source ==: input.m_dest); 67 | value = opt.m_alu_output; 68 | }; 69 | ] 70 | in 71 | { O.forward_data } 72 | 73 | let circuit_impl_exn scope input = 74 | let module W = Width_check.With_interface (I) (O) in 75 | W.check_widths (circuit_impl scope) input 76 | 77 | let hierarchical scope input = 78 | let module H = Hierarchy.In_scope (I) (O) in 79 | H.hierarchical ~scope ~name:"forwarding_unit" circuit_impl_exn input 80 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_ooc.xdc: -------------------------------------------------------------------------------- 1 | 2 | # file: design_1_clk_wiz_0_0_ooc.xdc 3 | # 4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | # 6 | # This file contains confidential and proprietary information 7 | # of Xilinx, Inc. and is protected under U.S. and 8 | # international copyright and other intellectual property 9 | # laws. 10 | # 11 | # DISCLAIMER 12 | # This disclaimer is not a license and does not grant any 13 | # rights to the materials distributed herewith. Except as 14 | # otherwise provided in a valid license issued to you by 15 | # Xilinx, and to the maximum extent permitted by applicable 16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | # (2) Xilinx shall not be liable (whether in contract or tort, 22 | # including negligence, or under any other theory of 23 | # liability) for any loss or damage of any kind or nature 24 | # related to, arising under or in connection with these 25 | # materials, including for any direct, or any indirect, 26 | # special, incidental, or consequential loss or damage 27 | # (including loss of data, profits, goodwill, or any type of 28 | # loss or damage suffered as a result of any action brought 29 | # by a third party) even if such damage or loss was 30 | # reasonably foreseeable or Xilinx had been advised of the 31 | # possibility of the same. 32 | # 33 | # CRITICAL APPLICATIONS 34 | # Xilinx products are not designed or intended to be fail- 35 | # safe, or for use in any application requiring fail-safe 36 | # performance, such as life-support or safety devices or 37 | # systems, Class III medical devices, nuclear facilities, 38 | # applications related to the deployment of airbags, or any 39 | # other applications that could lead to death, personal 40 | # injury, or severe property or environmental damage 41 | # (individually and collectively, "Critical 42 | # Applications"). Customer assumes the sole risk and 43 | # liability of any use of Xilinx products in Critical 44 | # Applications, subject only to applicable laws and 45 | # regulations governing limitations on product liability. 46 | # 47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | # PART OF THIS FILE AT ALL TIMES. 49 | # 50 | 51 | ################# 52 | #DEFAULT CLOCK CONSTRAINTS 53 | 54 | ############################################################ 55 | # Clock Period Constraints # 56 | ############################################################ 57 | #create_clock -period 10.000 [get_ports clk_in1] 58 | 59 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc: -------------------------------------------------------------------------------- 1 | 2 | # file: design_1_clk_wiz_0_0.xdc 3 | # 4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | # 6 | # This file contains confidential and proprietary information 7 | # of Xilinx, Inc. and is protected under U.S. and 8 | # international copyright and other intellectual property 9 | # laws. 10 | # 11 | # DISCLAIMER 12 | # This disclaimer is not a license and does not grant any 13 | # rights to the materials distributed herewith. Except as 14 | # otherwise provided in a valid license issued to you by 15 | # Xilinx, and to the maximum extent permitted by applicable 16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | # (2) Xilinx shall not be liable (whether in contract or tort, 22 | # including negligence, or under any other theory of 23 | # liability) for any loss or damage of any kind or nature 24 | # related to, arising under or in connection with these 25 | # materials, including for any direct, or any indirect, 26 | # special, incidental, or consequential loss or damage 27 | # (including loss of data, profits, goodwill, or any type of 28 | # loss or damage suffered as a result of any action brought 29 | # by a third party) even if such damage or loss was 30 | # reasonably foreseeable or Xilinx had been advised of the 31 | # possibility of the same. 32 | # 33 | # CRITICAL APPLICATIONS 34 | # Xilinx products are not designed or intended to be fail- 35 | # safe, or for use in any application requiring fail-safe 36 | # performance, such as life-support or safety devices or 37 | # systems, Class III medical devices, nuclear facilities, 38 | # applications related to the deployment of airbags, or any 39 | # other applications that could lead to death, personal 40 | # injury, or severe property or environmental damage 41 | # (individually and collectively, "Critical 42 | # Applications"). Customer assumes the sole risk and 43 | # liability of any use of Xilinx products in Critical 44 | # Applications, subject only to applicable laws and 45 | # regulations governing limitations on product liability. 46 | # 47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | # PART OF THIS FILE AT ALL TIMES. 49 | # 50 | 51 | # Input clock periods. These duplicate the values entered for the 52 | # input clocks. You can use these to time your system. If required 53 | # commented constraints can be used in the top level xdc 54 | #---------------------------------------------------------------- 55 | # Connect to input port when clock capable pin is selected for input 56 | create_clock -period 10.000 [get_ports clk_in1] 57 | set_input_jitter [get_clocks -of_objects [get_ports clk_in1]] 0.100 58 | 59 | 60 | set_property PHASESHIFT_MODE WAVEFORM [get_cells -hierarchical *adv*] 61 | -------------------------------------------------------------------------------- /lib/io/delay_test_io.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | (* Sample config for testing. *) 5 | let sample_read_delay = 2 6 | let sample_write_delay = 4 7 | let sample_read_data = of_int ~width:32 30 8 | 9 | module I = struct 10 | type 'a t = { 11 | clock : 'a; [@bits 1] 12 | write_enable : 'a; [@bits 1] 13 | write_addr : 'a; [@bits 32] 14 | write_data : 'a; [@bits 32] 15 | read_enable : 'a; [@bits 1] 16 | read_addr : 'a; [@bits 32] 17 | } 18 | [@@deriving sexp_of, hardcaml] 19 | end 20 | 21 | module O = struct 22 | type 'a t = { io_busy : 'a; [@bits 1] read_data : 'a [@bits 32] } 23 | [@@deriving sexp_of, hardcaml] 24 | end 25 | 26 | module States = struct 27 | type t = Not_stalling | Stalling | Done_stalling 28 | [@@deriving sexp_of, compare, enumerate] 29 | end 30 | 31 | let stall_sm ~clock ~stall_cycles ?(done_output = of_int ~width:32 0) 32 | should_stall = 33 | let width = Base.Int.ceil_log2 stall_cycles in 34 | 35 | (* One cycle is taken while switching into the Stalling state. 36 | * The other is taken while switching out of it. 37 | *) 38 | let stall_cycles_sig = of_int ~width (stall_cycles - 2) in 39 | let r = Reg_spec.create ~clock () in 40 | let sm = Always.State_machine.create (module States) ~enable:vdd r in 41 | let remaining_cycles = Always.Variable.reg r ~enable:vdd ~width in 42 | Always.( 43 | compile 44 | [ 45 | sm.switch 46 | [ 47 | ( Not_stalling, 48 | [ 49 | when_ should_stall 50 | [ 51 | sm.set_next Stalling; remaining_cycles <-- stall_cycles_sig; 52 | ]; 53 | ] ); 54 | ( Stalling, 55 | [ 56 | remaining_cycles <-- remaining_cycles.value -:. 1; 57 | when_ 58 | (remaining_cycles.value <=:. 0) 59 | [ 60 | sm.set_next Done_stalling; 61 | remaining_cycles <-- stall_cycles_sig; 62 | ]; 63 | ] ); 64 | (Done_stalling, [ sm.set_next Not_stalling ]); 65 | ]; 66 | ]); 67 | (* If an I/O operation was just initiated, we are always stalling regardless of the state. *) 68 | let busy = should_stall |: sm.is Stalling &: ~:(sm.is Done_stalling) in 69 | let output = mux2 (sm.is Done_stalling) done_output (of_int ~width:32 0) in 70 | (busy, output) 71 | 72 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 73 | let write_busy, _ = 74 | stall_sm ~clock:input.clock ~stall_cycles:sample_write_delay 75 | input.write_enable 76 | in 77 | let read_busy, read_data = 78 | stall_sm ~clock:input.clock ~stall_cycles:sample_read_delay 79 | ~done_output:sample_read_data input.read_enable 80 | in 81 | let io_busy = write_busy |: read_busy in 82 | { O.read_data; io_busy } 83 | 84 | let hierarchical scope input = 85 | let module H = Hierarchy.In_scope (I) (O) in 86 | H.hierarchical ~scope ~name:"delay_test_io" circuit_impl input 87 | -------------------------------------------------------------------------------- /test/instruction_fetch/test_instruction_fetch.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Instruction_fetch 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | (* Arbitrary values, these don't map to actual instructions. *) 7 | let program = Mips.Program.create [ "00000008"; "00000001"; "99999999" ] 8 | 9 | let testbench () = 10 | let scope = Scope.create ~flatten_design:true () in 11 | let sim = Simulator.create (circuit_impl_exn program scope) in 12 | let waves, sim = Waveform.create sim in 13 | let inputs = Cyclesim.inputs sim in 14 | 15 | let step ~pc = 16 | inputs.pc := Bits.of_string pc; 17 | Cyclesim.cycle sim 18 | in 19 | 20 | step ~pc:"32'h00000000"; 21 | step ~pc:"32'h00000001"; 22 | (* Not an increment of 4, so should get instruction rounded down *) 23 | step ~pc:"32'h00000004"; 24 | step ~pc:"32'h00000008"; 25 | step ~pc:"32'h0000000C"; 26 | (* There are only 3 instructions, so it should return a no-op *) 27 | step ~pc:"32'h00000000"; 28 | 29 | waves 30 | 31 | let%expect_test "fetches appropriate instructions, increments PC by 4 correctly" 32 | = 33 | let waves = testbench () in 34 | Waveform.print ~wave_width:4 ~display_width:90 waves; 35 | [%expect 36 | {| 37 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 38 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────── │ 39 | │pc ││ 00000000 │00000001 │00000004 │00000008 │0000000C │00000000 │ 40 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────── │ 41 | │ ││────────────────────┬─────────┬─────────┬─────────┬───────── │ 42 | │instruction ││ 00000008 │00000001 │99999999 │00000000 │00000008 │ 43 | │ ││────────────────────┴─────────┴─────────┴─────────┴───────── │ 44 | │ ││ │ 45 | │ ││ │ 46 | │ ││ │ 47 | │ ││ │ 48 | │ ││ │ 49 | │ ││ │ 50 | │ ││ │ 51 | │ ││ │ 52 | │ ││ │ 53 | │ ││ │ 54 | │ ││ │ 55 | │ ││ │ 56 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ 57 | |}] 58 | -------------------------------------------------------------------------------- /test/test_writeback/test_writeback.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Writeback 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let testbench () = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl_exn scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step ~sel_mem_for_reg_data ~alu_result ~data_output = 13 | inputs.sel_mem_for_reg_data := Bits.of_string sel_mem_for_reg_data; 14 | inputs.alu_result := Bits.of_string alu_result; 15 | inputs.data_output := Bits.of_string data_output; 16 | Cyclesim.cycle sim 17 | in 18 | 19 | step ~sel_mem_for_reg_data:"1'h0" ~alu_result:"32'h9" ~data_output:"32'h6"; 20 | 21 | (* Output = alu_result *) 22 | step ~sel_mem_for_reg_data:"1'h1" ~alu_result:"32'h9" ~data_output:"32'h6"; 23 | 24 | (* Output = data_output *) 25 | step ~sel_mem_for_reg_data:"1'h0" ~alu_result:"32'h9" ~data_output:"32'h6"; 26 | 27 | (* Output = alu_result *) 28 | waves 29 | 30 | let%expect_test "writes back correct value depending on selector" = 31 | let waves = testbench () in 32 | Waveform.print ~wave_width:4 ~display_width:90 waves; 33 | [%expect 34 | {| 35 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 36 | │ ││────────────────────────────── │ 37 | │alu_result ││ 00000009 │ 38 | │ ││────────────────────────────── │ 39 | │ ││────────────────────────────── │ 40 | │data_output ││ 00000006 │ 41 | │ ││────────────────────────────── │ 42 | │sel_mem_for_reg_da││ ┌─────────┐ │ 43 | │ ││──────────┘ └───────── │ 44 | │ ││──────────┬─────────┬───────── │ 45 | │writeback_data ││ 00000009 │00000006 │00000009 │ 46 | │ ││──────────┴─────────┴───────── │ 47 | │ ││ │ 48 | │ ││ │ 49 | │ ││ │ 50 | │ ││ │ 51 | │ ││ │ 52 | │ ││ │ 53 | │ ││ │ 54 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 55 | -------------------------------------------------------------------------------- /test/instruction_decode/test_stall_unit.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Stall_unit 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let gen_testbench () = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl_exn scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step ~rs ~rt ~e_dest ~e_sel_mem_for_reg_data = 13 | inputs.e_sel_mem_for_reg_data := Bits.of_string e_sel_mem_for_reg_data; 14 | inputs.rs := Bits.of_string rs; 15 | inputs.rt := Bits.of_string rt; 16 | inputs.e_dest := Bits.of_string e_dest; 17 | 18 | Cyclesim.cycle sim 19 | in 20 | 21 | (waves, step) 22 | 23 | let display_rules = 24 | [ Display_rule.port_name_is "stall_pc" ~wave_format:Wave_format.Bit ] 25 | 26 | let%expect_test "Stalls if LW in execute and should forward" = 27 | let waves, step = gen_testbench () in 28 | let step_lw = step ~e_sel_mem_for_reg_data:"1'b1" in 29 | 30 | step_lw ~rs:"5'h8" ~rt:"5'h8" ~e_dest:"5'h8"; 31 | step_lw ~rs:"5'h7" ~rt:"5'h8" ~e_dest:"5'h8"; 32 | step_lw ~rs:"5'h8" ~rt:"5'h7" ~e_dest:"5'h8"; 33 | 34 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 35 | ~display_height:5 waves; 36 | [%expect 37 | {| 38 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 39 | │stall_pc ││────────────────────────────── │ 40 | │ ││ │ 41 | │ ││ │ 42 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 43 | 44 | let%expect_test "Doesn't stall if not LW in execute" = 45 | let waves, step = gen_testbench () in 46 | 47 | step ~e_sel_mem_for_reg_data:"1'b1" ~rs:"5'h7" ~rt:"5'h7" ~e_dest:"5'h8"; 48 | 49 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 50 | ~display_height:5 waves; 51 | [%expect 52 | {| 53 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 54 | │stall_pc ││ │ 55 | │ ││────────── │ 56 | │ ││ │ 57 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 58 | 59 | let%expect_test "Doesn't stall if LW in execute, but shouldn't forward" = 60 | let waves, step = gen_testbench () in 61 | 62 | step ~e_sel_mem_for_reg_data:"1'b0" ~rs:"5'h8" ~rt:"5'h8" ~e_dest:"5'h7"; 63 | 64 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 65 | ~display_height:5 waves; 66 | [%expect 67 | {| 68 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 69 | │stall_pc ││ │ 70 | │ ││────────── │ 71 | │ ││ │ 72 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 73 | -------------------------------------------------------------------------------- /lib/cpu.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | module UA = Hardcaml_arty.User_application 4 | module I = Hardcaml_arty.User_application.I 5 | 6 | module O = struct 7 | type 'a t = { 8 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "uart_tx_"] 9 | ethernet : 'a UA.Ethernet.O.t; [@rtlprefix "eth_"] 10 | writeback_data : 'a; [@bits 32] 11 | writeback_pc : 'a; [@bits 32] 12 | } 13 | [@@deriving sexp_of, hardcaml] 14 | end 15 | 16 | let uart_addr = "32'hFFFFFFFE" 17 | let delay_test_addr = "32'hFFFFFFFF" 18 | 19 | let circuit_impl program scope (input : t I.t) = 20 | let io_busy = wire 1 in 21 | let read_data = wire 32 in 22 | let datapath = 23 | Datapath.hierarchical program scope 24 | { Datapath.I.clock = input.clk_166; read_data; io_busy } 25 | in 26 | 27 | let using_uart_read = datapath.read_addr ==: of_string uart_addr in 28 | let using_uart_write = datapath.write_addr ==: of_string uart_addr in 29 | let uart = 30 | Uart.hierarchical scope 31 | { 32 | Uart.I.clock = input.clk_166; 33 | write_enable = using_uart_write &: datapath.write_enable; 34 | write_addr = datapath.write_addr; 35 | write_data = datapath.write_data; 36 | read_enable = using_uart_read &: datapath.read_enable; 37 | read_addr = datapath.read_addr; 38 | uart_rx = input.uart_rx; 39 | } 40 | in 41 | let uart_busy = using_uart_read |: using_uart_write &: uart.io_busy in 42 | let uart_read = Signal.sresize using_uart_read 32 &: uart.read_data in 43 | 44 | let using_delay_test_read = 45 | datapath.read_addr ==: of_string delay_test_addr 46 | in 47 | let using_delay_test_write = 48 | datapath.write_addr ==: of_string delay_test_addr 49 | in 50 | let delay_test_io = 51 | Delay_test_io.hierarchical scope 52 | { 53 | Delay_test_io.I.clock = input.clk_166; 54 | write_enable = using_delay_test_write &: datapath.write_enable; 55 | write_addr = datapath.write_addr; 56 | write_data = datapath.write_data; 57 | read_enable = using_delay_test_read &: datapath.read_enable; 58 | read_addr = datapath.read_addr; 59 | } 60 | in 61 | let delay_test_io_busy = 62 | using_delay_test_read |: using_delay_test_write &: delay_test_io.io_busy 63 | in 64 | let delay_test_read = 65 | Signal.sresize using_delay_test_read 32 &: delay_test_io.read_data 66 | in 67 | 68 | let using_memory_read = ~:using_delay_test_read &: ~:using_uart_read in 69 | let using_memory_write = ~:using_delay_test_write &: ~:using_uart_write in 70 | let memory = 71 | Memory.hierarchical scope 72 | { 73 | Memory.I.clock = input.clk_166; 74 | write_enable = using_memory_write &: datapath.write_enable; 75 | write_addr = datapath.write_addr; 76 | write_data = datapath.write_data; 77 | read_enable = using_memory_read &: datapath.read_enable; 78 | read_addr = datapath.read_addr; 79 | } 80 | in 81 | let memory_busy = using_memory_read |: using_memory_write &: memory.io_busy in 82 | let memory_read = Signal.sresize using_memory_read 32 &: memory.read_data in 83 | 84 | read_data <== (delay_test_read |: memory_read |: uart_read); 85 | io_busy <== (delay_test_io_busy |: memory_busy |: uart_busy); 86 | 87 | { 88 | O.ethernet = Hardcaml_arty.User_application.Ethernet.O.unused (module Signal); 89 | uart_tx = uart.uart_tx; 90 | writeback_data = datapath.writeback_data; 91 | writeback_pc = datapath.writeback_pc; 92 | } 93 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.veo: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 4 | // 5 | // This file contains confidential and proprietary information 6 | // of Xilinx, Inc. and is protected under U.S. and 7 | // international copyright and other intellectual property 8 | // laws. 9 | // 10 | // DISCLAIMER 11 | // This disclaimer is not a license and does not grant any 12 | // rights to the materials distributed herewith. Except as 13 | // otherwise provided in a valid license issued to you by 14 | // Xilinx, and to the maximum extent permitted by applicable 15 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 16 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 17 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 18 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 19 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 20 | // (2) Xilinx shall not be liable (whether in contract or tort, 21 | // including negligence, or under any other theory of 22 | // liability) for any loss or damage of any kind or nature 23 | // related to, arising under or in connection with these 24 | // materials, including for any direct, or any indirect, 25 | // special, incidental, or consequential loss or damage 26 | // (including loss of data, profits, goodwill, or any type of 27 | // loss or damage suffered as a result of any action brought 28 | // by a third party) even if such damage or loss was 29 | // reasonably foreseeable or Xilinx had been advised of the 30 | // possibility of the same. 31 | // 32 | // CRITICAL APPLICATIONS 33 | // Xilinx products are not designed or intended to be fail- 34 | // safe, or for use in any application requiring fail-safe 35 | // performance, such as life-support or safety devices or 36 | // systems, Class III medical devices, nuclear facilities, 37 | // applications related to the deployment of airbags, or any 38 | // other applications that could lead to death, personal 39 | // injury, or severe property or environmental damage 40 | // (individually and collectively, "Critical 41 | // Applications"). Customer assumes the sole risk and 42 | // liability of any use of Xilinx products in Critical 43 | // Applications, subject only to applicable laws and 44 | // regulations governing limitations on product liability. 45 | // 46 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 47 | // PART OF THIS FILE AT ALL TIMES. 48 | // 49 | //---------------------------------------------------------------------------- 50 | // User entered comments 51 | //---------------------------------------------------------------------------- 52 | // None 53 | // 54 | //---------------------------------------------------------------------------- 55 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 56 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 57 | //---------------------------------------------------------------------------- 58 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575 59 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575 60 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575 61 | // 62 | //---------------------------------------------------------------------------- 63 | // Input Clock Freq (MHz) Input Jitter (UI) 64 | //---------------------------------------------------------------------------- 65 | // __primary_________100.000____________0.010 66 | 67 | // The following must be inserted into your Verilog file for this 68 | // core to be instantiated. Change the instance name and port connections 69 | // (in parentheses) to your own signal names. 70 | 71 | //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG 72 | 73 | design_1_clk_wiz_0_0 instance_name 74 | ( 75 | // Clock out ports 76 | .clk_out1(clk_out1), // output clk_out1 77 | .clk_out2(clk_out2), // output clk_out2 78 | .clk_out3(clk_out3), // output clk_out3 79 | // Status and control signals 80 | .resetn(resetn), // input resetn 81 | .locked(locked), // output locked 82 | // Clock in ports 83 | .clk_in1(clk_in1)); // input clk_in1 84 | 85 | // INST_TAG_END ------ End INSTANTIATION Template --------- 86 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.v: -------------------------------------------------------------------------------- 1 | 2 | // file: design_1_clk_wiz_0_0.v 3 | // 4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | // 6 | // This file contains confidential and proprietary information 7 | // of Xilinx, Inc. and is protected under U.S. and 8 | // international copyright and other intellectual property 9 | // laws. 10 | // 11 | // DISCLAIMER 12 | // This disclaimer is not a license and does not grant any 13 | // rights to the materials distributed herewith. Except as 14 | // otherwise provided in a valid license issued to you by 15 | // Xilinx, and to the maximum extent permitted by applicable 16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | // (2) Xilinx shall not be liable (whether in contract or tort, 22 | // including negligence, or under any other theory of 23 | // liability) for any loss or damage of any kind or nature 24 | // related to, arising under or in connection with these 25 | // materials, including for any direct, or any indirect, 26 | // special, incidental, or consequential loss or damage 27 | // (including loss of data, profits, goodwill, or any type of 28 | // loss or damage suffered as a result of any action brought 29 | // by a third party) even if such damage or loss was 30 | // reasonably foreseeable or Xilinx had been advised of the 31 | // possibility of the same. 32 | // 33 | // CRITICAL APPLICATIONS 34 | // Xilinx products are not designed or intended to be fail- 35 | // safe, or for use in any application requiring fail-safe 36 | // performance, such as life-support or safety devices or 37 | // systems, Class III medical devices, nuclear facilities, 38 | // applications related to the deployment of airbags, or any 39 | // other applications that could lead to death, personal 40 | // injury, or severe property or environmental damage 41 | // (individually and collectively, "Critical 42 | // Applications"). Customer assumes the sole risk and 43 | // liability of any use of Xilinx products in Critical 44 | // Applications, subject only to applicable laws and 45 | // regulations governing limitations on product liability. 46 | // 47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | // PART OF THIS FILE AT ALL TIMES. 49 | // 50 | //---------------------------------------------------------------------------- 51 | // User entered comments 52 | //---------------------------------------------------------------------------- 53 | // None 54 | // 55 | //---------------------------------------------------------------------------- 56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 58 | //---------------------------------------------------------------------------- 59 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575 60 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575 61 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575 62 | // 63 | //---------------------------------------------------------------------------- 64 | // Input Clock Freq (MHz) Input Jitter (UI) 65 | //---------------------------------------------------------------------------- 66 | // __primary_________100.000____________0.010 67 | 68 | `timescale 1ps/1ps 69 | 70 | (* CORE_GENERATION_INFO = "design_1_clk_wiz_0_0,clk_wiz_v6_0_9_0_0,{component_name=design_1_clk_wiz_0_0,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=MMCM,num_out_clk=3,clkin1_period=10.000,clkin2_period=10.000,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=false}" *) 71 | 72 | module design_1_clk_wiz_0_0 73 | ( 74 | // Clock out ports 75 | output clk_out1, 76 | output clk_out2, 77 | output clk_out3, 78 | // Status and control signals 79 | input resetn, 80 | output locked, 81 | // Clock in ports 82 | input clk_in1 83 | ); 84 | 85 | design_1_clk_wiz_0_0_clk_wiz inst 86 | ( 87 | // Clock out ports 88 | .clk_out1(clk_out1), 89 | .clk_out2(clk_out2), 90 | .clk_out3(clk_out3), 91 | // Status and control signals 92 | .resetn(resetn), 93 | .locked(locked), 94 | // Clock in ports 95 | .clk_in1(clk_in1) 96 | ); 97 | 98 | endmodule 99 | -------------------------------------------------------------------------------- /lib/instruction_decode/instruction_decode.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | clock : 'a; [@bits 1] 7 | enable_pipeline : 'a; [@bits 1] 8 | writeback_reg_write_enable : 'a; [@bits 1] 9 | writeback_address : 'a; [@bits 5] 10 | writeback_data : 'a; [@bits 32] 11 | instruction : 'a; [@bits 32] 12 | e_alu_output : 'a; [@bits 32] 13 | m_alu_output : 'a; [@bits 32] 14 | m_data_output : 'a; [@bits 32] 15 | } 16 | [@@deriving sexp_of, hardcaml] 17 | end 18 | 19 | module O = struct 20 | type 'a t = { 21 | control_signals : 'a Control_unit.Control_signals.t; 22 | alu_a : 'a; [@bits 32] 23 | alu_b : 'a; [@bits 32] 24 | rdest : 'a; [@bits 5] 25 | se_imm : 'a; [@bits 32] 26 | alu_imm : 'a; [@bits 32] 27 | addr : 'a; [@bits 26] 28 | } 29 | [@@deriving sexp_of, hardcaml] 30 | end 31 | 32 | let regfile rs rt clock write_enable write_address write_data = 33 | let write_port = 34 | { write_clock = clock; write_address; write_enable; write_data } 35 | in 36 | let number_of_regs = 32 in 37 | let regs = 38 | multiport_memory number_of_regs ~write_ports:[| write_port |] 39 | ~read_addresses:[| rs; rt |] 40 | in 41 | let alu_a = 42 | mux2 (write_enable &: (write_address ==: rs)) write_data regs.(0) 43 | in 44 | let alu_b = 45 | mux2 (write_enable &: (write_address ==: rt)) write_data regs.(1) 46 | in 47 | 48 | (alu_a, alu_b) 49 | 50 | let stall_signals scope (sigs : _ Control_unit.Control_signals.t) rs rt e_dest 51 | e_sel_mem_for_reg_data = 52 | let stall_unit = 53 | Stall_unit.hierarchical scope { rs; rt; e_dest; e_sel_mem_for_reg_data } 54 | in 55 | let stall_pc = stall_unit.stall_pc in 56 | { 57 | sigs with 58 | stall_pc; 59 | reg_write_enable = mux2 stall_pc gnd sigs.reg_write_enable; 60 | mem_write_enable = mux2 stall_pc gnd sigs.mem_write_enable; 61 | } 62 | 63 | let circuit_impl (scope : Scope.t) (input : _ I.t) = 64 | let enable = input.enable_pipeline in 65 | 66 | let control_unit = 67 | Control_unit.hierarchical scope { instruction = input.instruction } 68 | in 69 | 70 | let parsed = control_unit.parsed_instruction in 71 | let rs_val, rt_val = 72 | regfile parsed.rs parsed.rt input.clock input.writeback_reg_write_enable 73 | input.writeback_address input.writeback_data 74 | in 75 | 76 | let r = Reg_spec.create ~clock:input.clock () in 77 | let e_dest = reg ~enable r parsed.rdest in 78 | let m_dest = pipeline ~n:2 ~enable r parsed.rdest in 79 | 80 | let m2reg = control_unit.control_signals.sel_mem_for_reg_data in 81 | let wreg = control_unit.control_signals.reg_write_enable in 82 | let e_sel_mem_for_reg_data = reg ~enable r m2reg in 83 | let m_sel_mem_for_reg_data = pipeline ~n:2 ~enable r m2reg in 84 | let e_reg_write_enable = reg ~enable r wreg in 85 | let m_reg_write_enable = pipeline ~n:2 ~enable r wreg in 86 | 87 | let full_control_signals = 88 | stall_signals scope control_unit.control_signals parsed.rs parsed.rt e_dest 89 | e_sel_mem_for_reg_data 90 | in 91 | 92 | let e_stalled = reg ~enable r full_control_signals.stall_pc in 93 | 94 | let forwarding_unit_inputs reg reg_value = 95 | { 96 | Forwarding_unit.I.options = 97 | { 98 | Forwarding_unit.Data_options.reg_value; 99 | e_alu_output = input.e_alu_output; 100 | m_alu_output = input.m_alu_output; 101 | m_data_output = input.m_data_output; 102 | }; 103 | controls = 104 | { 105 | Forwarding_unit.Controls.e_sel_mem_for_reg_data; 106 | m_sel_mem_for_reg_data; 107 | e_reg_write_enable; 108 | m_reg_write_enable; 109 | e_stalled; 110 | }; 111 | source = reg; 112 | e_dest; 113 | m_dest; 114 | } 115 | in 116 | 117 | let fwd_a = 118 | Forwarding_unit.hierarchical scope (forwarding_unit_inputs parsed.rs rs_val) 119 | in 120 | let fwd_b = 121 | Forwarding_unit.hierarchical scope (forwarding_unit_inputs parsed.rt rt_val) 122 | in 123 | 124 | let check_zero_reg reg fwd = 125 | mux2 (reg ==: of_string "5'b0") (of_string "32'b0") fwd 126 | in 127 | 128 | let alu_a = check_zero_reg parsed.rs fwd_a.forward_data in 129 | let alu_b = check_zero_reg parsed.rt fwd_b.forward_data in 130 | 131 | { 132 | O.control_signals = full_control_signals; 133 | alu_a; 134 | alu_b; 135 | rdest = parsed.rdest; 136 | se_imm = parsed.se_imm; 137 | alu_imm = parsed.alu_imm; 138 | addr = parsed.addr; 139 | } 140 | 141 | let circuit_impl_exn scope input = 142 | let module W = Width_check.With_interface (I) (O) in 143 | W.check_widths (circuit_impl scope) input 144 | 145 | let hierarchical scope input = 146 | let module H = Hierarchy.In_scope (I) (O) in 147 | H.hierarchical ~scope ~name:"instruction_decode" circuit_impl_exn input 148 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [1.0.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.14.0...v1.0.0) 4 | 5 | - Implemented control flow instructions 6 | - j, jal, jr 7 | - bne, beq 8 | - Fixed sw source bugs 9 | - Use alu_b instead of alu_a 10 | - Pipeline data address properly 11 | - Use zero-extended immediate for shift instructions 12 | - Added integration tests 13 | - Added an actual program 14 | - Bump ocamlformat version 15 | 16 | ## [0.14.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.13.0...v0.14.0) 17 | 18 | - Added stalls 19 | - We stall if there's a LW in Execute, and we need to forward Execute => Decode 20 | - This is needed because LW data isn't available for forwarding until the Memory stage 21 | - Also moved "next PC" logic out of "instruction fetch": this will be its own module in a coming release. 22 | 23 | ## [0.13.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.12.1...v0.13.0) 24 | 25 | Refactor to avoid writeback => decode forwarding 26 | 27 | - Instead, support write-before-read in the regfile 28 | - Also, fix a wiring issue with forwarding 29 | 30 | ## [0.12.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.11.1...v0.12.1) 31 | 32 | - Use interactive waveform viewer 33 | 34 | ## [0.11.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.10.0...v0.11.1) 35 | 36 | - Added a forwarding unit 37 | - Forwards values from execute, memory, and writeback 38 | - `rs_val` and `rt_val` renamed to `alu_a` and `alu_b` throughout the design. 39 | - The register file no longer delays writes by half a cycle 40 | - Simulating half-cycle operations is [not supported in Hardcaml](https://github.com/janestreet/hardcaml/issues/11). 41 | 42 | ## [0.10.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.9.0...v0.10.0) 43 | 44 | - Outputs verilog code to a separate file, "mips_datapath.v" 45 | 46 | ## [0.9.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.8.0...v0.9.0) 47 | 48 | - Added most MIPS instructions 49 | - Excluded mult/divide because we don't have hi/lo registers yet 50 | - Excluded jump, branch because we don't have next_pc selector logic yet 51 | - Excluded system calls / exception handling because we don't have an exception handling unit. 52 | - Output `pc` in datapath 53 | - Added some regfile-initializing instructions in the sample program 54 | - Split `imm` parsed instructions into `ze_imm` (for eventual branching) and `alu_imm` (for ALU ops, is zero or sign extended depending on the instruction) 55 | 56 | ## [0.8.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.7.0...v0.8.0) 57 | 58 | - Added memory and writeback stages. This completes the basic core of our CPU. 59 | - Added write support to regfile, made it write-before-read to reduce hazards. 60 | 61 | ## [0.7.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.6.1...v0.7.0) 62 | 63 | - Added instruction decode stage 64 | - Includes a 3 part control unit from v0.6.1 65 | - Created register file 66 | - Added instruction execute stage 67 | - Created ALU with support for adds and subtracts 68 | - Added tests for new components 69 | 70 | ## [0.6.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.5.2...v0.6.1) 71 | 72 | - Added control unit. 73 | - Split into [3 components](https://excalidraw.com/#json=4874675947569152,f4jus3Ehk-DGZspiJAGUWw) for maintainability. 74 | 75 | ## [0.5.2](https://github.com/askvortsov1/hardcaml-mips/compare/v0.4.0...v0.5.2) 76 | 77 | - Renamed circuit `create` functions to `circuit_impl`. 78 | - Created a `Width_check.With_interface` functor with a `check_widths` function that checks input/output width compliance for circuit implementation. 79 | - Instruction memory now returns noops when `pc` exceeds the length of the program to avoid unexpected effects. 80 | - Standardized and cleaned up naming input 81 | - Inputs are type hinted in the circuit implementation functions, and derived functions use type inference for concision. 82 | 83 | ## [0.4.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.3.0...v0.4.0) 84 | 85 | - Implemented feedback in datapath via register. This allows us to store and mutate the state of our system over time. 86 | 87 | ## [0.3.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.2.0...v0.3.0) 88 | 89 | - Implemented `instruction_memory`. The program being executed is treated as an input to the entire processor. 90 | - See `instruction_fetch.ml` for an explanation of why we implemented instruction memory the way we did. 91 | - Defined `Program` module to abstract away the concept of a program. 92 | 93 | ## [0.2.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.1.2...v0.2.0) 94 | 95 | Proof of concept for module hierarchies: 96 | 97 | - Started instruction fetch module 98 | - No memory or registers yet, just constant output for now 99 | 100 | ## [0.1.2](https://github.com/askvortsov1/hardcaml-mips/tree/v0.1.2) 6/14/2021 101 | 102 | Proof of concept: 103 | 104 | - Created trivial circuit 105 | - Added waveform-based expect test 106 | - Built executable to print circuit in Verilog -------------------------------------------------------------------------------- /test/instruction_execute/test_alu.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Alu 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let testbench () = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl_exn scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step ~arg_a ~arg_b ~alu_control = 13 | inputs.arg_a := Bits.of_string arg_a; 14 | inputs.arg_b := Bits.of_string arg_b; 15 | inputs.alu_control := Bits.of_constant (Signal.to_constant alu_control); 16 | Cyclesim.cycle sim 17 | in 18 | 19 | step ~arg_a:"32'h5" ~arg_b:"32'h10" ~alu_control:Mips.Control_unit.Alu_ops.add; 20 | step ~arg_a:"32'h10" ~arg_b:"32'h5" ~alu_control:Mips.Control_unit.Alu_ops.addu; 21 | step ~arg_a:"32'h000F0FF0" ~arg_b:"32'hFF0F00FF" ~alu_control:Mips.Control_unit.Alu_ops.and_; 22 | step ~arg_a:"32'hABCDEF01" ~arg_b:"32'h9876ABCD" ~alu_control:Mips.Control_unit.Alu_ops.lui; 23 | step ~arg_a:"32'h000F0FF0" ~arg_b:"32'hFF0F00FF" ~alu_control:Mips.Control_unit.Alu_ops.or_; 24 | step ~arg_a:"32'h0" ~arg_b:"32'hFFFFFFFF" ~alu_control:Mips.Control_unit.Alu_ops.slt; 25 | step ~arg_a:"32'h0" ~arg_b:"32'hFFFFFFFF" ~alu_control:Mips.Control_unit.Alu_ops.sltu; 26 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.sll; 27 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.sra; 28 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.srl; 29 | step ~arg_a:"32'h15" ~arg_b:"32'h2" ~alu_control:Mips.Control_unit.Alu_ops.sub; 30 | step ~arg_a:"32'h15" ~arg_b:"32'h2" ~alu_control:Mips.Control_unit.Alu_ops.subu; 31 | step ~arg_a:"32'h005F" ~arg_b:"32'hF0AF" ~alu_control:Mips.Control_unit.Alu_ops.xor; 32 | 33 | waves 34 | 35 | let%expect_test "Operations behave as expected" 36 | = 37 | let waves = testbench () in 38 | Waveform.print ~wave_width:4 ~display_width:155 waves; 39 | [%expect 40 | {| 41 | ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ 42 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────── │ 43 | │alu_control ││ 02 │03 │04 │05 │06 │07 │08 │09 │0A │0B │0C │0D │0E │ 44 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────── │ 45 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬─────────────────────────────┬───────────────────┬───────── │ 46 | │arg_a ││ 00000005 │00000010 │000F0FF0 │ABCDEF01 │000F0FF0 │00000000 │00000002 │00000015 │0000005F │ 47 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴─────────────────────────────┴───────────────────┴───────── │ 48 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬─────────────────────────────┬───────────────────┬───────── │ 49 | │arg_b ││ 00000010 │00000005 │FF0F00FF │9876ABCD │FF0F00FF │FFFFFFFF │000000F0 │00000002 │0000F0AF │ 50 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴─────────────────────────────┴───────────────────┴───────── │ 51 | │ ││────────────────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬───────────────────┬───────── │ 52 | │result ││ 00000015 │000F00F0 │ABCD0000 │FF0F0FFF │00000001 │00000000 │000003C0 │0000003C │00000013 │0000F0F0 │ 53 | │ ││────────────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴───────────────────┴───────── │ 54 | │ ││ │ 55 | │ ││ │ 56 | │ ││ │ 57 | │ ││ │ 58 | │ ││ │ 59 | │ ││ │ 60 | └──────────────────┘└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 61 | |}] 62 | -------------------------------------------------------------------------------- /test/io/test_memory.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Memory 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | type test_input = { 7 | write_enable : string; 8 | write_data : string; 9 | data_address : string; 10 | } 11 | 12 | let testbench () = 13 | let scope = Scope.create ~flatten_design:true () in 14 | let sim = Simulator.create (circuit_impl scope) in 15 | let waves, sim = Waveform.create sim in 16 | let inputs = Cyclesim.inputs sim in 17 | 18 | let step ~test = 19 | inputs.write_enable := Bits.of_string test.write_enable; 20 | inputs.read_addr := Bits.of_string test.data_address; 21 | inputs.write_addr := Bits.of_string test.data_address; 22 | inputs.write_data := Bits.of_string test.write_data; 23 | Cyclesim.cycle sim 24 | in 25 | 26 | step 27 | ~test: 28 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h7" }; 29 | (* alu_a should now be 8 after this step *) 30 | step 31 | ~test: 32 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h6" }; 33 | 34 | (* Memory should be 0 since everything has been disabled so far *) 35 | step 36 | ~test: 37 | { write_enable = "1'h1"; data_address = "32'h9"; write_data = "32'h86" }; 38 | 39 | step 40 | ~test: 41 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h6" }; 42 | (* Now we can read what we wrote. 43 | * It's delayed by a stage since the simulator isn't half-cycle accurate 44 | * (see test_instruction_decode for more details) but we don't care about 45 | * that for data memory. 46 | *) 47 | waves 48 | 49 | let%expect_test "can we read and write to/from data memory properly" = 50 | let waves = testbench () in 51 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:35 waves; 52 | [%expect 53 | {| 54 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 55 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 56 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 57 | │ ││──────────────────────────────────────── │ 58 | │read_addr ││ 00000009 │ 59 | │ ││──────────────────────────────────────── │ 60 | │ ││──────────────────────────────────────── │ 61 | │write_addr ││ 00000009 │ 62 | │ ││──────────────────────────────────────── │ 63 | │ ││──────────┬─────────┬─────────┬───────── │ 64 | │write_data ││ 00000007 │00000006 │00000086 │00000006 │ 65 | │ ││──────────┴─────────┴─────────┴───────── │ 66 | │write_enable ││ ┌─────────┐ │ 67 | │ ││────────────────────┘ └───────── │ 68 | │io_busy ││ │ 69 | │ ││──────────────────────────────────────── │ 70 | │ ││──────────────────────────────┬───────── │ 71 | │read_data ││ 00000000 │00000086 │ 72 | │ ││──────────────────────────────┴───────── │ 73 | │ ││ │ 74 | │ ││ │ 75 | │ ││ │ 76 | │ ││ │ 77 | │ ││ │ 78 | │ ││ │ 79 | │ ││ │ 80 | │ ││ │ 81 | │ ││ │ 82 | │ ││ │ 83 | │ ││ │ 84 | │ ││ │ 85 | │ ││ │ 86 | │ ││ │ 87 | │ ││ │ 88 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 89 | -------------------------------------------------------------------------------- /lib/datapath.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module I = struct 5 | type 'a t = { 6 | clock : 'a; [@bits 1] 7 | io_busy : 'a; [@bits 1] 8 | read_data : 'a; [@bits 32] 9 | } 10 | [@@deriving sexp_of, hardcaml] 11 | end 12 | 13 | module O = struct 14 | type 'a t = { 15 | write_enable : 'a; [@bits 1] 16 | write_addr : 'a; [@bits 32] 17 | write_data : 'a; [@bits 32] 18 | read_enable : 'a; [@bits 1] 19 | read_addr : 'a; [@bits 32] 20 | writeback_data : 'a; [@bits 32] 21 | writeback_pc : 'a; [@bits 32] 22 | } 23 | [@@deriving sexp_of, hardcaml] 24 | end 25 | 26 | let circuit_impl (program : Program.t) (scope : Scope.t) (input : _ I.t) = 27 | (* Stall the pipeline while devices on the bus are busy. *) 28 | let enable = ~:(input.io_busy) in 29 | let r = Reg_spec.create ~clock:input.clock () in 30 | 31 | (* Instruction Fetch Stage *) 32 | let pc = wire 32 in 33 | 34 | let instruction_fetch = Instruction_fetch.hierarchical program scope { pc } in 35 | 36 | (* Instruction Decode *) 37 | let reg_write_enable = wire 1 in 38 | let reg_write_enable_reg = pipeline ~n:3 ~enable r reg_write_enable in 39 | let writeback_address = wire 5 in 40 | let writeback_address_reg = pipeline ~n:3 ~enable r writeback_address in 41 | let writeback_data = wire 32 in 42 | 43 | let prev_stall_pc = wire 1 in 44 | let prev_instruction = 45 | pipeline ~n:2 ~enable r instruction_fetch.instruction 46 | in 47 | let curr_instruction = reg ~enable r instruction_fetch.instruction in 48 | let instruction = mux2 prev_stall_pc prev_instruction curr_instruction in 49 | 50 | let e_alu_output = wire 32 in 51 | let m_alu_output = wire 32 in 52 | let instruction_decode = 53 | Instruction_decode.hierarchical scope 54 | { 55 | Instruction_decode.I.clock = input.clock; 56 | enable_pipeline = enable; 57 | writeback_reg_write_enable = reg_write_enable_reg; 58 | writeback_address = writeback_address_reg; 59 | writeback_data; 60 | instruction; 61 | e_alu_output; 62 | m_alu_output; 63 | m_data_output = input.read_data; 64 | } 65 | in 66 | let ctrl_sigs = instruction_decode.control_signals in 67 | reg_write_enable <== ctrl_sigs.reg_write_enable; 68 | writeback_address <== instruction_decode.rdest; 69 | 70 | let gen_next_pc = 71 | Gen_next_pc.hierarchical scope 72 | { 73 | Gen_next_pc.I.alu_a = instruction_decode.alu_a; 74 | alu_b = instruction_decode.alu_b; 75 | addr = instruction_decode.addr; 76 | se_imm = instruction_decode.se_imm; 77 | pc; 78 | prev_pc = reg ~enable r pc; 79 | pc_sel = ctrl_sigs.pc_sel; 80 | } 81 | in 82 | 83 | let pc_reg = 84 | reg ~enable r (mux2 ctrl_sigs.stall_pc pc gen_next_pc.next_pc) 85 | in 86 | pc <== pc_reg; 87 | prev_stall_pc <== reg ~enable r ctrl_sigs.stall_pc; 88 | 89 | (* Instruction Execute *) 90 | let sel_shift_for_alu = reg ~enable r ctrl_sigs.sel_shift_for_alu in 91 | let sel_imm_for_alu = reg ~enable r ctrl_sigs.sel_imm_for_alu in 92 | let alu_control = reg ~enable r ctrl_sigs.alu_control in 93 | let alu_a = reg ~enable r instruction_decode.alu_a in 94 | let alu_b = reg ~enable r instruction_decode.alu_b in 95 | let alu_imm = reg ~enable r instruction_decode.alu_imm in 96 | let jal = reg ~enable r ctrl_sigs.jal in 97 | let instruction_execute = 98 | Instruction_execute.hierarchical scope 99 | { 100 | alu_a; 101 | alu_b; 102 | imm = alu_imm; 103 | sel_shift_for_alu; 104 | sel_imm_for_alu; 105 | alu_control; 106 | jal; 107 | prev2_pc = pipeline ~n:2 ~enable r pc; 108 | } 109 | in 110 | e_alu_output <== instruction_execute.alu_result; 111 | m_alu_output <== reg ~enable r instruction_execute.alu_result; 112 | 113 | (* Memory *) 114 | let mem_write_enable = 115 | pipeline ~n:2 ~enable r ctrl_sigs.mem_write_enable 116 | in 117 | let mem_read_enable = 118 | pipeline ~n:2 ~enable r ctrl_sigs.mem_read_enable 119 | in 120 | let data = pipeline ~n:2 ~enable r instruction_decode.alu_b in 121 | let data_address = reg ~enable r instruction_execute.alu_result in 122 | 123 | (* Memory access is handled by the bus. *) 124 | 125 | (* Writeback *) 126 | let sel_mem_for_reg_data = 127 | pipeline ~n:3 ~enable r ctrl_sigs.sel_mem_for_reg_data 128 | in 129 | let alu_result = pipeline ~n:2 ~enable r instruction_execute.alu_result in 130 | let data_output = reg ~enable r input.read_data in 131 | 132 | let writeback = 133 | Writeback.hierarchical scope 134 | { Writeback.I.sel_mem_for_reg_data; alu_result; data_output } 135 | in 136 | writeback_data <== writeback.writeback_data; 137 | 138 | (* Outputs *) 139 | { 140 | O.write_enable = mem_write_enable; 141 | write_addr = data_address; 142 | write_data = data; 143 | read_enable = mem_read_enable; 144 | read_addr = data_address; 145 | writeback_data; 146 | writeback_pc = pipeline ~n:4 ~enable r pc; 147 | } 148 | 149 | let circuit_impl_exn program scope input = 150 | let module W = Width_check.With_interface (I) (O) in 151 | W.check_widths (circuit_impl program scope) input 152 | 153 | let hierarchical program scope input = 154 | let module H = Hierarchy.In_scope (I) (O) in 155 | H.hierarchical ~scope ~name:"datapath" (circuit_impl_exn program) input 156 | -------------------------------------------------------------------------------- /test/instruction_decode/test_forwarding_unit.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Forwarding_unit 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let gen_testbench () = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl_exn scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step ?(e_dest = "5'h9") ?(m_dest = "5'h9") ?(e_mem2reg = "1'b0") 13 | ?(m_mem2reg = "1'b0") ?(e_rwrite = "1'b1") ?(m_rwrite = "1'b1") 14 | ?(e_stalled = "1'b0") () = 15 | inputs.options.reg_value := Bits.of_string "32'd0"; 16 | inputs.options.e_alu_output := Bits.of_string "32'd1"; 17 | inputs.options.m_alu_output := Bits.of_string "32'd2"; 18 | inputs.options.m_data_output := Bits.of_string "32'd3"; 19 | inputs.source := Bits.of_string "5'd8"; 20 | inputs.e_dest := Bits.of_string e_dest; 21 | inputs.m_dest := Bits.of_string m_dest; 22 | inputs.controls.e_sel_mem_for_reg_data := Bits.of_string e_mem2reg; 23 | inputs.controls.m_sel_mem_for_reg_data := Bits.of_string m_mem2reg; 24 | inputs.controls.e_reg_write_enable := Bits.of_string e_rwrite; 25 | inputs.controls.m_reg_write_enable := Bits.of_string m_rwrite; 26 | inputs.controls.e_stalled := Bits.of_string e_stalled; 27 | Cyclesim.cycle sim 28 | in 29 | (waves, step) 30 | 31 | let display_rules = 32 | [ Display_rule.port_name_is "forward_data" ~wave_format:Wave_format.Hex ] 33 | 34 | let%expect_test "Forwards correctly, if should forward" = 35 | let waves, step = gen_testbench () in 36 | 37 | step ~e_dest:"5'h8" (); 38 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b0" (); 39 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b1" (); 40 | 41 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 42 | ~display_height:5 waves; 43 | [%expect 44 | {| 45 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 46 | │ ││──────────┬─────────┬───────── │ 47 | │forward_data ││ 00000001 │00000002 │00000003 │ 48 | │ ││──────────┴─────────┴───────── │ 49 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 50 | 51 | let%expect_test "Doesn't forward for instructions that don't write to registers" 52 | = 53 | let waves, step = gen_testbench () in 54 | 55 | step ~e_dest:"5'h8" ~e_rwrite:"1'b0" (); 56 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b0" ~m_rwrite:"1'b0" (); 57 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~m_rwrite:"1'b0" (); 58 | 59 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 60 | ~display_height:5 waves; 61 | [%expect 62 | {| 63 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 64 | │ ││────────────────────────────── │ 65 | │forward_data ││ 00000000 │ 66 | │ ││────────────────────────────── │ 67 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 68 | 69 | let%expect_test "Prioritizes which stage forwarding happens if dest is same" = 70 | let waves, step = gen_testbench () in 71 | 72 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b0" (); 73 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" (); 74 | 75 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 76 | ~display_height:5 waves; 77 | [%expect 78 | {| 79 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 80 | │ ││──────────────────── │ 81 | │forward_data ││ 00000001 │ 82 | │ ││──────────────────── │ 83 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 84 | 85 | let%expect_test "Ensures no forwarding occurs when LW is in execute stage" = 86 | let waves, step = gen_testbench () in 87 | 88 | step ~e_dest:"5'h8" ~e_mem2reg:"1'b1" (); 89 | 90 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 91 | ~display_height:5 waves; 92 | [%expect 93 | {| 94 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 95 | │ ││────────── │ 96 | │forward_data ││ 00000000 │ 97 | │ ││────────── │ 98 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 99 | 100 | let%expect_test "Does not forward from previous if prev was stalled." = 101 | let waves, step = gen_testbench () in 102 | 103 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~e_stalled:"1'b0" (); 104 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~e_stalled:"1'b1" (); 105 | 106 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90 107 | ~display_height:5 waves; 108 | [%expect 109 | {| 110 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 111 | │ ││──────────┬───────── │ 112 | │forward_data ││ 00000001 │00000003 │ 113 | │ ││──────────┴───────── │ 114 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] -------------------------------------------------------------------------------- /lib/io/uart.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module Word_with_valid = struct 5 | module Pre = struct 6 | include With_valid 7 | 8 | let t = { valid = ("valid", 1); value = ("value", 32) } 9 | end 10 | 11 | include Pre 12 | include Hardcaml.Interface.Make (Pre) 13 | end 14 | 15 | let num_start_bits = 1 16 | let num_data_bits = 8 17 | let num_stop_bits = 1 18 | let bits_per_packet = num_start_bits + num_data_bits + num_stop_bits 19 | 20 | let cycles_per_bit = 21 | 166_667_000 / 115_200 (* 166.667 MHz running at 115200 baud *) 22 | 23 | let cycles_per_packet = bits_per_packet * cycles_per_bit 24 | let newline_hex = 0x0A 25 | 26 | module Rx_buffer = struct 27 | module States = struct 28 | type t = S_idle | S_wait_next_byte | S_finished 29 | [@@deriving sexp_of, compare, enumerate] 30 | end 31 | 32 | let create ~clock ~read_enable 33 | (input : t Hardcaml_arty.Uart.Byte_with_valid.t) = 34 | let spec = Reg_spec.create ~clock () in 35 | 36 | let sm = Always.State_machine.create (module States) spec ~enable:vdd in 37 | 38 | (* This will never be true when sm.is S_finished, 39 | * b/c input.valid is only vdd for one cycle/packet 40 | *) 41 | let should_update_buffer = 42 | input.valid &: (sm.is S_wait_next_byte |: read_enable) 43 | in 44 | let buffer_index = Always.Variable.reg spec ~enable:vdd ~width:2 in 45 | let reg_read_buffer = 46 | reg_fb spec ~enable:vdd ~width:32 ~f:(fun curr -> 47 | let curr_byte_word = uresize input.value 32 in 48 | let new_buffer_val = 49 | mux buffer_index.value 50 | [ 51 | curr &: of_string "32'h00000000" |: sll curr_byte_word 24; 52 | curr &: of_string "32'hFF000000" |: sll curr_byte_word 16; 53 | curr &: of_string "32'hFFFF0000" |: sll curr_byte_word 8; 54 | curr &: of_string "32'hFFFFFF00" |: curr_byte_word; 55 | ] 56 | in 57 | mux2 should_update_buffer new_buffer_val curr) 58 | in 59 | 60 | Always.( 61 | compile 62 | [ 63 | sm.switch 64 | [ 65 | ( S_idle, 66 | [ 67 | when_ read_enable 68 | [ 69 | when_ input.valid 70 | [ 71 | buffer_index <-- buffer_index.value +:. 1; 72 | ]; 73 | sm.set_next S_wait_next_byte; 74 | ]; 75 | ] ); 76 | ( S_wait_next_byte, 77 | [ 78 | when_ input.valid 79 | [ 80 | buffer_index <-- buffer_index.value +:. 1; 81 | when_ 82 | (buffer_index.value ==:. 3 83 | |: (input.value ==: of_int ~width:8 newline_hex)) 84 | [ sm.set_next S_finished ]; 85 | ]; 86 | ] ); 87 | (S_finished, [ buffer_index <--. 0; sm.set_next S_idle ]); 88 | ]; 89 | ]); 90 | let read_busy = 91 | ~:(sm.is S_finished) &: (sm.is S_wait_next_byte |: read_enable) 92 | in 93 | ({ With_valid.valid = sm.is S_finished; value = reg_read_buffer }, read_busy) 94 | end 95 | 96 | module Tx_buffer = struct 97 | module States = struct 98 | type t = S_idle | S_start_of_byte | S_transmitting_byte | S_finished 99 | [@@deriving sexp_of, compare, enumerate] 100 | end 101 | 102 | let create ~clock (input : t Word_with_valid.t) = 103 | let spec = Reg_spec.create ~clock () in 104 | 105 | let reg_write_buffer = 106 | reg_fb spec ~enable:vdd ~width:32 ~f:(fun curr -> 107 | mux2 input.valid input.value curr) 108 | in 109 | 110 | let cycles_width = Base.Int.ceil_log2 cycles_per_packet + 2 in 111 | 112 | let sm = Always.State_machine.create (module States) spec ~enable:vdd in 113 | let read_buffer_index = Always.Variable.reg spec ~enable:vdd ~width:2 in 114 | let tx_cycles_count = 115 | Always.Variable.reg spec ~enable:vdd ~width:cycles_width 116 | in 117 | 118 | Always.( 119 | compile 120 | [ 121 | sm.switch 122 | [ 123 | ( S_idle, 124 | [ 125 | when_ input.valid 126 | [ read_buffer_index <--. 0; sm.set_next S_start_of_byte ]; 127 | ] ); 128 | ( S_start_of_byte, 129 | [ 130 | tx_cycles_count <-- of_int ~width:cycles_width 0; 131 | sm.set_next S_transmitting_byte; 132 | ] ); 133 | ( S_transmitting_byte, 134 | [ 135 | tx_cycles_count <-- tx_cycles_count.value +:. 1; 136 | when_ 137 | (tx_cycles_count.value >=:. cycles_per_packet) 138 | [ 139 | read_buffer_index <-- read_buffer_index.value +:. 1; 140 | if_ 141 | (read_buffer_index.value ==:. 3) 142 | [ sm.set_next S_finished ] 143 | [ sm.set_next S_start_of_byte ]; 144 | ]; 145 | ] ); 146 | (S_finished, [ read_buffer_index <--. 0; sm.set_next S_idle ]); 147 | ]; 148 | ]); 149 | let value = 150 | mux read_buffer_index.value 151 | [ 152 | reg_write_buffer.:[(31, 24)]; 153 | reg_write_buffer.:[(23, 16)]; 154 | reg_write_buffer.:[(15, 8)]; 155 | reg_write_buffer.:[(7, 0)]; 156 | ] 157 | in 158 | let write_busy = 159 | sm.is S_start_of_byte |: sm.is S_transmitting_byte 160 | |: (input.valid &: ~:(sm.is S_finished)) 161 | in 162 | ({ With_valid.valid = sm.is S_start_of_byte; value }, write_busy) 163 | end 164 | 165 | module I = struct 166 | type 'a t = { 167 | clock : 'a; [@bits 1] 168 | write_enable : 'a; [@bits 1] 169 | write_addr : 'a; [@bits 32] 170 | write_data : 'a; [@bits 32] 171 | read_enable : 'a; [@bits 1] 172 | read_addr : 'a; [@bits 32] 173 | uart_rx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "rx_"] 174 | } 175 | [@@deriving sexp_of, hardcaml] 176 | end 177 | 178 | module O = struct 179 | type 'a t = { 180 | io_busy : 'a; [@bits 1] 181 | read_data : 'a; [@bits 32] 182 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "tx_"] 183 | } 184 | [@@deriving sexp_of, hardcaml] 185 | end 186 | 187 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 188 | let tx, write_busy = 189 | Tx_buffer.create ~clock:input.clock 190 | { With_valid.value = input.write_data; valid = input.write_enable } 191 | in 192 | let rx, read_busy = 193 | Rx_buffer.create ~clock:input.clock ~read_enable:input.read_enable 194 | input.uart_rx 195 | in 196 | let io_busy = write_busy |: read_busy in 197 | { O.read_data = rx.value; io_busy; uart_tx = tx } 198 | 199 | let hierarchical scope input = 200 | let module H = Hierarchy.In_scope (I) (O) in 201 | H.hierarchical ~scope ~name:"uart" circuit_impl input 202 | -------------------------------------------------------------------------------- /test/instruction_execute/test_instruction_execute.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Instruction_execute 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let testbench () = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl_exn scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step ~sel_shift_for_alu ~sel_imm_for_alu ~jal = 13 | inputs.sel_shift_for_alu := Bits.of_string sel_shift_for_alu; 14 | inputs.sel_imm_for_alu := Bits.of_string sel_imm_for_alu; 15 | inputs.alu_a := Bits.of_string "32'h1"; 16 | inputs.alu_b := Bits.of_string "32'h2"; 17 | inputs.imm := Bits.of_string "32'h183"; 18 | inputs.jal := Bits.of_string jal; 19 | inputs.prev2_pc := Bits.of_string "32'h100"; 20 | inputs.alu_control := Bits.of_constant (Signal.to_constant Mips.Control_unit.Alu_ops.add); 21 | Cyclesim.cycle sim 22 | in 23 | 24 | step, waves 25 | 26 | let%expect_test "Uses control selector properly for ALU inputs" 27 | = 28 | let step, waves = testbench () in 29 | 30 | let step = step ~jal:"1'b0" in 31 | 32 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b0"; 33 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b1"; 34 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b0"; 35 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b1"; 36 | 37 | Waveform.print ~wave_width:4 ~display_height:30 ~display_width:90 waves; 38 | [%expect 39 | {| 40 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 41 | │ ││──────────────────────────────────────── │ 42 | │alu_a ││ 00000001 │ 43 | │ ││──────────────────────────────────────── │ 44 | │ ││──────────────────────────────────────── │ 45 | │alu_b ││ 00000002 │ 46 | │ ││──────────────────────────────────────── │ 47 | │ ││──────────────────────────────────────── │ 48 | │alu_control ││ 02 │ 49 | │ ││──────────────────────────────────────── │ 50 | │ ││──────────────────────────────────────── │ 51 | │imm ││ 00000183 │ 52 | │ ││──────────────────────────────────────── │ 53 | │jal ││ │ 54 | │ ││──────────────────────────────────────── │ 55 | │ ││──────────────────────────────────────── │ 56 | │prev2_pc ││ 00000100 │ 57 | │ ││──────────────────────────────────────── │ 58 | │sel_imm_for_alu ││ ┌─────────┐ ┌───────── │ 59 | │ ││──────────┘ └─────────┘ │ 60 | │sel_shift_for_alu ││ ┌─────────────────── │ 61 | │ ││────────────────────┘ │ 62 | │ ││──────────┬─────────┬─────────┬───────── │ 63 | │alu_result ││ 00000003 │00000184 │00000008 │00000189 │ 64 | │ ││──────────┴─────────┴─────────┴───────── │ 65 | │ ││ │ 66 | │ ││ │ 67 | │ ││ │ 68 | │ ││ │ 69 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ 70 | |}] 71 | 72 | let%expect_test "jal mux" 73 | = 74 | let step, waves = testbench () in 75 | 76 | let step = step ~jal:"1'b1" in 77 | 78 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b0"; 79 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b1"; 80 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b0"; 81 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b1"; 82 | 83 | Waveform.print ~wave_width:4 ~display_height:30 ~display_width:90 waves; 84 | [%expect 85 | {| 86 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 87 | │ ││──────────────────────────────────────── │ 88 | │alu_a ││ 00000001 │ 89 | │ ││──────────────────────────────────────── │ 90 | │ ││──────────────────────────────────────── │ 91 | │alu_b ││ 00000002 │ 92 | │ ││──────────────────────────────────────── │ 93 | │ ││──────────────────────────────────────── │ 94 | │alu_control ││ 02 │ 95 | │ ││──────────────────────────────────────── │ 96 | │ ││──────────────────────────────────────── │ 97 | │imm ││ 00000183 │ 98 | │ ││──────────────────────────────────────── │ 99 | │jal ││──────────────────────────────────────── │ 100 | │ ││ │ 101 | │ ││──────────────────────────────────────── │ 102 | │prev2_pc ││ 00000100 │ 103 | │ ││──────────────────────────────────────── │ 104 | │sel_imm_for_alu ││ ┌─────────┐ ┌───────── │ 105 | │ ││──────────┘ └─────────┘ │ 106 | │sel_shift_for_alu ││ ┌─────────────────── │ 107 | │ ││────────────────────┘ │ 108 | │ ││──────────────────────────────────────── │ 109 | │alu_result ││ 00000108 │ 110 | │ ││──────────────────────────────────────── │ 111 | │ ││ │ 112 | │ ││ │ 113 | │ ││ │ 114 | │ ││ │ 115 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ 116 | |}] 117 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_clk_wiz.v: -------------------------------------------------------------------------------- 1 | 2 | // file: design_1_clk_wiz_0_0.v 3 | // 4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved. 5 | // 6 | // This file contains confidential and proprietary information 7 | // of Xilinx, Inc. and is protected under U.S. and 8 | // international copyright and other intellectual property 9 | // laws. 10 | // 11 | // DISCLAIMER 12 | // This disclaimer is not a license and does not grant any 13 | // rights to the materials distributed herewith. Except as 14 | // otherwise provided in a valid license issued to you by 15 | // Xilinx, and to the maximum extent permitted by applicable 16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 21 | // (2) Xilinx shall not be liable (whether in contract or tort, 22 | // including negligence, or under any other theory of 23 | // liability) for any loss or damage of any kind or nature 24 | // related to, arising under or in connection with these 25 | // materials, including for any direct, or any indirect, 26 | // special, incidental, or consequential loss or damage 27 | // (including loss of data, profits, goodwill, or any type of 28 | // loss or damage suffered as a result of any action brought 29 | // by a third party) even if such damage or loss was 30 | // reasonably foreseeable or Xilinx had been advised of the 31 | // possibility of the same. 32 | // 33 | // CRITICAL APPLICATIONS 34 | // Xilinx products are not designed or intended to be fail- 35 | // safe, or for use in any application requiring fail-safe 36 | // performance, such as life-support or safety devices or 37 | // systems, Class III medical devices, nuclear facilities, 38 | // applications related to the deployment of airbags, or any 39 | // other applications that could lead to death, personal 40 | // injury, or severe property or environmental damage 41 | // (individually and collectively, "Critical 42 | // Applications"). Customer assumes the sole risk and 43 | // liability of any use of Xilinx products in Critical 44 | // Applications, subject only to applicable laws and 45 | // regulations governing limitations on product liability. 46 | // 47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 48 | // PART OF THIS FILE AT ALL TIMES. 49 | // 50 | //---------------------------------------------------------------------------- 51 | // User entered comments 52 | //---------------------------------------------------------------------------- 53 | // None 54 | // 55 | //---------------------------------------------------------------------------- 56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase 57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps) 58 | //---------------------------------------------------------------------------- 59 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575 60 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575 61 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575 62 | // 63 | //---------------------------------------------------------------------------- 64 | // Input Clock Freq (MHz) Input Jitter (UI) 65 | //---------------------------------------------------------------------------- 66 | // __primary_________100.000____________0.010 67 | 68 | `timescale 1ps/1ps 69 | 70 | module design_1_clk_wiz_0_0_clk_wiz 71 | 72 | (// Clock in ports 73 | // Clock out ports 74 | output clk_out1, 75 | output clk_out2, 76 | output clk_out3, 77 | // Status and control signals 78 | input resetn, 79 | output locked, 80 | input clk_in1 81 | ); 82 | // Input buffering 83 | //------------------------------------ 84 | wire clk_in1_design_1_clk_wiz_0_0; 85 | wire clk_in2_design_1_clk_wiz_0_0; 86 | IBUF clkin1_ibufg 87 | (.O (clk_in1_design_1_clk_wiz_0_0), 88 | .I (clk_in1)); 89 | 90 | 91 | 92 | 93 | // Clocking PRIMITIVE 94 | //------------------------------------ 95 | 96 | // Instantiation of the MMCM PRIMITIVE 97 | // * Unused inputs are tied off 98 | // * Unused outputs are labeled unused 99 | 100 | wire clk_out1_design_1_clk_wiz_0_0; 101 | wire clk_out2_design_1_clk_wiz_0_0; 102 | wire clk_out3_design_1_clk_wiz_0_0; 103 | wire clk_out4_design_1_clk_wiz_0_0; 104 | wire clk_out5_design_1_clk_wiz_0_0; 105 | wire clk_out6_design_1_clk_wiz_0_0; 106 | wire clk_out7_design_1_clk_wiz_0_0; 107 | 108 | wire [15:0] do_unused; 109 | wire drdy_unused; 110 | wire psdone_unused; 111 | wire locked_int; 112 | wire clkfbout_design_1_clk_wiz_0_0; 113 | wire clkfbout_buf_design_1_clk_wiz_0_0; 114 | wire clkfboutb_unused; 115 | wire clkout0b_unused; 116 | wire clkout1b_unused; 117 | wire clkout2b_unused; 118 | wire clkout3_unused; 119 | wire clkout3b_unused; 120 | wire clkout4_unused; 121 | wire clkout5_unused; 122 | wire clkout6_unused; 123 | wire clkfbstopped_unused; 124 | wire clkinstopped_unused; 125 | wire reset_high; 126 | 127 | MMCME2_ADV 128 | #(.BANDWIDTH ("OPTIMIZED"), 129 | .CLKOUT4_CASCADE ("FALSE"), 130 | .COMPENSATION ("ZHOLD"), 131 | .STARTUP_WAIT ("FALSE"), 132 | .DIVCLK_DIVIDE (1), 133 | .CLKFBOUT_MULT_F (10.000), 134 | .CLKFBOUT_PHASE (0.000), 135 | .CLKFBOUT_USE_FINE_PS ("FALSE"), 136 | .CLKOUT0_DIVIDE_F (6.000), 137 | .CLKOUT0_PHASE (0.000), 138 | .CLKOUT0_DUTY_CYCLE (0.500), 139 | .CLKOUT0_USE_FINE_PS ("FALSE"), 140 | .CLKOUT1_DIVIDE (5), 141 | .CLKOUT1_PHASE (0.000), 142 | .CLKOUT1_DUTY_CYCLE (0.500), 143 | .CLKOUT1_USE_FINE_PS ("FALSE"), 144 | .CLKOUT2_DIVIDE (40), 145 | .CLKOUT2_PHASE (0.000), 146 | .CLKOUT2_DUTY_CYCLE (0.500), 147 | .CLKOUT2_USE_FINE_PS ("FALSE"), 148 | .CLKIN1_PERIOD (10.000)) 149 | mmcm_adv_inst 150 | // Output clocks 151 | ( 152 | .CLKFBOUT (clkfbout_design_1_clk_wiz_0_0), 153 | .CLKFBOUTB (clkfboutb_unused), 154 | .CLKOUT0 (clk_out1_design_1_clk_wiz_0_0), 155 | .CLKOUT0B (clkout0b_unused), 156 | .CLKOUT1 (clk_out2_design_1_clk_wiz_0_0), 157 | .CLKOUT1B (clkout1b_unused), 158 | .CLKOUT2 (clk_out3_design_1_clk_wiz_0_0), 159 | .CLKOUT2B (clkout2b_unused), 160 | .CLKOUT3 (clkout3_unused), 161 | .CLKOUT3B (clkout3b_unused), 162 | .CLKOUT4 (clkout4_unused), 163 | .CLKOUT5 (clkout5_unused), 164 | .CLKOUT6 (clkout6_unused), 165 | // Input clock control 166 | .CLKFBIN (clkfbout_buf_design_1_clk_wiz_0_0), 167 | .CLKIN1 (clk_in1_design_1_clk_wiz_0_0), 168 | .CLKIN2 (1'b0), 169 | // Tied to always select the primary input clock 170 | .CLKINSEL (1'b1), 171 | // Ports for dynamic reconfiguration 172 | .DADDR (7'h0), 173 | .DCLK (1'b0), 174 | .DEN (1'b0), 175 | .DI (16'h0), 176 | .DO (do_unused), 177 | .DRDY (drdy_unused), 178 | .DWE (1'b0), 179 | // Ports for dynamic phase shift 180 | .PSCLK (1'b0), 181 | .PSEN (1'b0), 182 | .PSINCDEC (1'b0), 183 | .PSDONE (psdone_unused), 184 | // Other control and status signals 185 | .LOCKED (locked_int), 186 | .CLKINSTOPPED (clkinstopped_unused), 187 | .CLKFBSTOPPED (clkfbstopped_unused), 188 | .PWRDWN (1'b0), 189 | .RST (reset_high)); 190 | assign reset_high = ~resetn; 191 | 192 | assign locked = locked_int; 193 | // Clock Monitor clock assigning 194 | //-------------------------------------- 195 | // Output buffering 196 | //----------------------------------- 197 | 198 | BUFG clkf_buf 199 | (.O (clkfbout_buf_design_1_clk_wiz_0_0), 200 | .I (clkfbout_design_1_clk_wiz_0_0)); 201 | 202 | 203 | 204 | 205 | 206 | 207 | BUFG clkout1_buf 208 | (.O (clk_out1), 209 | .I (clk_out1_design_1_clk_wiz_0_0)); 210 | 211 | 212 | BUFG clkout2_buf 213 | (.O (clk_out2), 214 | .I (clk_out2_design_1_clk_wiz_0_0)); 215 | 216 | BUFG clkout3_buf 217 | (.O (clk_out3), 218 | .I (clk_out3_design_1_clk_wiz_0_0)); 219 | 220 | 221 | 222 | endmodule 223 | -------------------------------------------------------------------------------- /arty/boards/arty-a7-35/E.0/part0_pins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /arty/boards/arty-a7-35/E.0/mig.prj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | design_1_mig_7series_0_0 5 | 1 6 | 1 7 | OFF 8 | 1024 9 | ON 10 | Enabled 11 | xc7a35ti-csg324/-1L 12 | 2.3 13 | No Buffer 14 | No Buffer 15 | ACTIVE LOW 16 | FALSE 17 | 1 18 | 50 Ohms 19 | 0 20 | 21 | DDR3_SDRAM/Components/MT41K128M16XX-15E 22 | 3000 23 | 1.8V 24 | 4:1 25 | 166.666 26 | 0 27 | 666 28 | 1.000 29 | 1 30 | 1 31 | 1 32 | 1 33 | 16 34 | 1 35 | 1 36 | Disabled 37 | Normal 38 | FALSE 39 | 40 | 14 41 | 10 42 | 3 43 | 1.35V 44 | 268435456 45 | BANK_ROW_COLUMN 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 8 - Fixed 105 | Sequential 106 | 5 107 | Normal 108 | No 109 | Slow Exit 110 | Enable 111 | RZQ/6 112 | Disable 113 | Enable 114 | RZQ/6 115 | 0 116 | Disabled 117 | Enabled 118 | Output Buffer Enabled 119 | Full Array 120 | 5 121 | Enabled 122 | Normal 123 | Dynamic ODT off 124 | AXI 125 | 126 | RD_PRI_REG 127 | 28 128 | 128 129 | 4 130 | 0 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /arty/ips/design_1_clk_wiz_0_0/doc/clk_wiz_v6_0_changelog.txt: -------------------------------------------------------------------------------- 1 | 2021.2: 2 | * Version 6.0 (Rev. 9) 3 | * Bug Fix: CR Fixes 4 | * Other: CR Fixes 5 | 6 | 2021.1.1: 7 | * Version 6.0 (Rev. 8) 8 | * No changes 9 | 10 | 2021.1: 11 | * Version 6.0 (Rev. 8) 12 | * Bug Fix: Internal GUI fixes 13 | * Other: CR Fixes 14 | 15 | 2020.3: 16 | * Version 6.0 (Rev. 7) 17 | * Bug Fix: Internal GUI fixes 18 | * Other: CR Fixes 19 | 20 | 2020.2.2: 21 | * Version 6.0 (Rev. 6) 22 | * No changes 23 | 24 | 2020.2.1: 25 | * Version 6.0 (Rev. 6) 26 | * No changes 27 | 28 | 2020.2: 29 | * Version 6.0 (Rev. 6) 30 | * Bug Fix: Internal GUI fixes 31 | * Other: CR Fixes 32 | 33 | 2020.1.1: 34 | * Version 6.0 (Rev. 5) 35 | * No changes 36 | 37 | 2020.1: 38 | * Version 6.0 (Rev. 5) 39 | * Bug Fix: Internal GUI fixes 40 | * Other: CR Fixes 41 | 42 | 2019.2.2: 43 | * Version 6.0 (Rev. 4) 44 | * No changes 45 | 46 | 2019.2.1: 47 | * Version 6.0 (Rev. 4) 48 | * No changes 49 | 50 | 2019.2: 51 | * Version 6.0 (Rev. 4) 52 | * Bug Fix: Internal GUI fixes 53 | * Other: CR Fixes 54 | 55 | 2019.1.3: 56 | * Version 6.0 (Rev. 3) 57 | * No changes 58 | 59 | 2019.1.2: 60 | * Version 6.0 (Rev. 3) 61 | * No changes 62 | 63 | 2019.1.1: 64 | * Version 6.0 (Rev. 3) 65 | * No changes 66 | 67 | 2019.1: 68 | * Version 6.0 (Rev. 3) 69 | * Bug Fix: Internal GUI fixes 70 | * Other: New family support added 71 | 72 | 2018.3.1: 73 | * Version 6.0 (Rev. 2) 74 | * No changes 75 | 76 | 2018.3: 77 | * Version 6.0 (Rev. 2) 78 | * Bug Fix: Made input source independent for primary and secondary clock 79 | * Other: New family support added 80 | 81 | 2018.2: 82 | * Version 6.0 (Rev. 1) 83 | * Bug Fix: Removed vco freq check when Primitive is None 84 | * Other: New family support added 85 | 86 | 2018.1: 87 | * Version 6.0 88 | * Bug Fix: Bug fixes in Dynamic Reconfiguration feature and Write DRP feature 89 | * Bug Fix: Bug fixes for connection issue for s_axi_aresetn pin in IPI 90 | * Feature Enhancement: The default value of USE_PHASE_ALIGMENT is updated to false for UltraScale and UltraScale+ devices. Phase Alignment feature uses extra clock routes in UltraScale and UltraScale+ designs when MMCMs are used. These routing resources are wasted when user do not understand when phase alignment is really needed. Now, implementation tools can use these extra clock routing resources for high fanout signals. 91 | * Feature Enhancement: A column "Max. freq of buffer" is added in the Output Clock table which shows the maximum frequency that the selected output buffer can support 92 | * Other: DRCs added for invalid input values in Override mode 93 | 94 | 2017.4: 95 | * Version 5.4 (Rev. 3) 96 | * Bug Fix: Internal GUI issues are fixed for COMPENSATION mode as INTERNAL 97 | * Bug Fix: Fixed issue in dynamic reconfiguration of fractional values of M in MMCME3, MMCME4 98 | 99 | 2017.3: 100 | * Version 5.4 (Rev. 2) 101 | * General: Internal GUI changes. No effect on the customer design. Added support for aspartan7 devices 102 | 103 | 2017.2: 104 | * Version 5.4 (Rev. 1) 105 | * General: Internal GUI changes. No effect on the customer design. 106 | 107 | 2017.1: 108 | * Version 5.4 109 | * Port Change: Minor version upgrade. CLR pins are added to the pin list when selected buffer is BUFGCEDIV for ultrascale and ultrascale plus devices. 110 | * Other: Added support for new zynq ultrascale plus devices. 111 | 112 | 2016.4: 113 | * Version 5.3 (Rev. 3) 114 | * Bug Fix: Internal GUI issues are fixed. 115 | 116 | 2016.3: 117 | * Version 5.3 (Rev. 2) 118 | * Feature Enhancement: Added new option "Auto" under PRIMITIVE selection for ultrascale and above devices. This option allows the Wizard to instantiate appropriate primitive for the user inputs. 119 | * Feature Enhancement: Added Matched Routing Option for better timing solutions. 120 | * Feature Enhancement: Options 'Buffer' and 'Buffer_with_CE' are added to the buffer selection list. 121 | * Other: Source HDL files are concatenated into a single file to speed up synthesis and simulation. No changes required by the user 122 | * Other: Added support for Spartan7 devices. 123 | 124 | 2016.2: 125 | * Version 5.3 (Rev. 1) 126 | * Internal register bit update, no effect on customer designs. 127 | 128 | 2016.1: 129 | * Version 5.3 130 | * Added Clock Monitor Feature as part of clocking wizard 131 | * DRP registers can be directly written through AXI without resource utilization 132 | * Changes to HDL library management to support Vivado IP simulation library 133 | 134 | 2015.4.2: 135 | * Version 5.2 (Rev. 1) 136 | * No changes 137 | 138 | 2015.4.1: 139 | * Version 5.2 (Rev. 1) 140 | * No changes 141 | 142 | 2015.4: 143 | * Version 5.2 (Rev. 1) 144 | * Internal device family change, no functional changes 145 | 146 | 2015.3: 147 | * Version 5.2 148 | * IP revision number added to HDL module, library, and include file names, to support designs with both locked and upgraded IP instances 149 | * Port Renaming tab is hidden in the GUI in IP Integrator as this feature is not supported 150 | * Phase alignment feature is removed for ultrascale PLL as primitve has limited capabilities of supporting this feature 151 | * When clocking wizard is targetted on a board part, the frequency values that gets propagated to primary and secondary clocks are displayed in floating number format 152 | * Example design and simulation files are delivered in verilog only 153 | 154 | 2015.2.1: 155 | * Version 5.1 (Rev. 6) 156 | * No changes 157 | 158 | 2015.2: 159 | * Version 5.1 (Rev. 6) 160 | * No changes 161 | 162 | 2015.1: 163 | * Version 5.1 (Rev. 6) 164 | * Updated mmcm_pll_filter_lookup and mmcm_pll_lock_lookup functions in the header file for 7-Series and UltraScale devices 165 | * Supported devices and production status are now determined automatically, to simplify support for future devices 166 | 167 | 2014.4.1: 168 | * Version 5.1 (Rev. 5) 169 | * No changes 170 | 171 | 2014.4: 172 | * Version 5.1 (Rev. 5) 173 | * Internal device family change, no functional changes 174 | * updates related to the source selection based on board interface for zed board 175 | 176 | 2014.3: 177 | * Version 5.1 (Rev. 4) 178 | * Option added to enable dynamic phase and duty cycle for resource optimization in AXI4-Lite interface 179 | 180 | 2014.2: 181 | * Version 5.1 (Rev. 3) 182 | * Updated for AXI4-Lite interface locked status register address and bit mapping to align with the pg065 183 | 184 | 2014.1: 185 | * Version 5.1 (Rev. 2) 186 | * Updated to use inverted output CLKOUTB 0-3 of Clocking Primitive based on requested 180 phase w.r.t. previous clock 187 | * Internal device family name change, no functional changes 188 | 189 | 2013.4: 190 | * Version 5.1 (Rev. 1) 191 | * Added support for Ultrascale devices 192 | * Updated Board Flow GUI to select the clock interfaces 193 | * Fixed issue with Stub file parameter error for BUFR output driver 194 | 195 | 2013.3: 196 | * Version 5.1 197 | * Added AXI4-Lite interface to dynamically reconfigure MMCM/PLL 198 | * Improved safe clock logic to remove glitches on clock outputs for odd multiples of input clock frequencies 199 | * Fixed precision issues between displayed and actual frequencies 200 | * Added tool tips to GUI 201 | * Added Jitter and Phase error values to IP properties 202 | * Added support for Cadence IES and Synopsys VCS simulators 203 | * Reduced warnings in synthesis and simulation 204 | * Enhanced support for IP Integrator 205 | 206 | 2013.2: 207 | * Version 5.0 (Rev. 1) 208 | * Fixed issue with clock constraints for multiple instances of clocking wizard 209 | * Updated Life-Cycle status of devices 210 | 211 | 2013.1: 212 | * Version 5.0 213 | * Lower case ports for Verilog 214 | * Added Safe Clock Startup and Clock Sequencing 215 | 216 | (c) Copyright 2008 - 2021 Xilinx, Inc. All rights reserved. 217 | 218 | This file contains confidential and proprietary information 219 | of Xilinx, Inc. and is protected under U.S. and 220 | international copyright and other intellectual property 221 | laws. 222 | 223 | DISCLAIMER 224 | This disclaimer is not a license and does not grant any 225 | rights to the materials distributed herewith. Except as 226 | otherwise provided in a valid license issued to you by 227 | Xilinx, and to the maximum extent permitted by applicable 228 | law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND 229 | WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES 230 | AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 231 | BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- 232 | INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and 233 | (2) Xilinx shall not be liable (whether in contract or tort, 234 | including negligence, or under any other theory of 235 | liability) for any loss or damage of any kind or nature 236 | related to, arising under or in connection with these 237 | materials, including for any direct, or any indirect, 238 | special, incidental, or consequential loss or damage 239 | (including loss of data, profits, goodwill, or any type of 240 | loss or damage suffered as a result of any action brought 241 | by a third party) even if such damage or loss was 242 | reasonably foreseeable or Xilinx had been advised of the 243 | possibility of the same. 244 | 245 | CRITICAL APPLICATIONS 246 | Xilinx products are not designed or intended to be fail- 247 | safe, or for use in any application requiring fail-safe 248 | performance, such as life-support or safety devices or 249 | systems, Class III medical devices, nuclear facilities, 250 | applications related to the deployment of airbags, or any 251 | other applications that could lead to death, personal 252 | injury, or severe property or environmental damage 253 | (individually and collectively, "Critical 254 | Applications"). Customer assumes the sole risk and 255 | liability of any use of Xilinx products in Critical 256 | Applications, subject only to applicable laws and 257 | regulations governing limitations on product liability. 258 | 259 | THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS 260 | PART OF THIS FILE AT ALL TIMES. 261 | -------------------------------------------------------------------------------- /test/io/uart/test_uart_tx.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | 4 | let clock = Signal.input "clock" 1 5 | 6 | let waves = 7 | let valid = Signal.input "valid" 1 in 8 | let value = Signal.input "value" 32 in 9 | let tx, tx_busy = Mips.Uart.Tx_buffer.create ~clock { valid; value } in 10 | let uart_tx_value = Signal.output "uart_tx_value" tx.value in 11 | let uart_tx_valid = Signal.output "uart_tx_valid" tx.valid in 12 | let uart_tx_busy = Signal.output "uart_tx_busy" tx_busy in 13 | let circuit = 14 | Circuit.create_exn ~name:"tx_state_machine" [ uart_tx_value; uart_tx_valid; uart_tx_busy ] 15 | in 16 | let waves, sim = 17 | Hardcaml_waveterm.Waveform.create 18 | (Cyclesim.create ~config:Cyclesim.Config.trace_all circuit) 19 | in 20 | Cyclesim.cycle sim; 21 | Cyclesim.cycle sim; 22 | Cyclesim.in_port sim "valid" := Bits.vdd; 23 | Cyclesim.in_port sim "value" := Bits.of_string "32'h61727479" (* "arty" *); 24 | Cyclesim.cycle sim; 25 | Cyclesim.in_port sim "valid" := Bits.gnd; 26 | for _ = 0 to Mips.Uart.cycles_per_packet * 5 do 27 | Cyclesim.cycle sim 28 | done; 29 | waves 30 | 31 | let%expect_test "tx_first_byte" = 32 | Waveform.print ~display_width:100 ~display_height:16 waves; 33 | [%expect 34 | {| 35 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐ 36 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ 37 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│ 38 | │valid ││ ┌───────┐ │ 39 | │ ││────────────────┘ └─────────────────────────────────────────────────────│ 40 | │ ││────────────────┬─────────────────────────────────────────────────────────────│ 41 | │value ││ 00000000 │61727479 │ 42 | │ ││────────────────┴─────────────────────────────────────────────────────────────│ 43 | │uart_tx_busy ││ ┌─────────────────────────────────────────────────────────────│ 44 | │ ││────────────────┘ │ 45 | │uart_tx_valid ││ ┌───────┐ │ 46 | │ ││────────────────────────┘ └─────────────────────────────────────────────│ 47 | │ ││────────────────────────┬─────────────────────────────────────────────────────│ 48 | │uart_tx_value ││ 00 │61 │ 49 | │ ││────────────────────────┴─────────────────────────────────────────────────────│ 50 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}] 51 | 52 | let%expect_test "tx_second_byte" = 53 | Waveform.print ~start_cycle:Mips.Uart.cycles_per_packet ~display_width:100 54 | ~display_height:16 waves; 55 | [%expect 56 | {| 57 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐ 58 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ 59 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│ 60 | │valid ││ │ 61 | │ ││──────────────────────────────────────────────────────────────────────────────│ 62 | │ ││──────────────────────────────────────────────────────────────────────────────│ 63 | │value ││ 61727479 │ 64 | │ ││──────────────────────────────────────────────────────────────────────────────│ 65 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│ 66 | │ ││ │ 67 | │uart_tx_valid ││ ┌───────┐ │ 68 | │ ││────────────────────────────────────────┘ └─────────────────────────────│ 69 | │ ││────────────────────────────────────────┬─────────────────────────────────────│ 70 | │uart_tx_value ││ 61 │72 │ 71 | │ ││────────────────────────────────────────┴─────────────────────────────────────│ 72 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}] 73 | 74 | let%expect_test "tx_third_byte" = 75 | Waveform.print 76 | ~start_cycle:(Mips.Uart.cycles_per_packet * 2) 77 | ~display_width:100 ~display_height:16 waves; 78 | [%expect 79 | {| 80 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐ 81 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ 82 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│ 83 | │valid ││ │ 84 | │ ││──────────────────────────────────────────────────────────────────────────────│ 85 | │ ││──────────────────────────────────────────────────────────────────────────────│ 86 | │value ││ 61727479 │ 87 | │ ││──────────────────────────────────────────────────────────────────────────────│ 88 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│ 89 | │ ││ │ 90 | │uart_tx_valid ││ ┌───────┐ │ 91 | │ ││────────────────────────────────────────────────────────┘ └─────────────│ 92 | │ ││────────────────────────────────────────────────────────┬─────────────────────│ 93 | │uart_tx_value ││ 72 │74 │ 94 | │ ││────────────────────────────────────────────────────────┴─────────────────────│ 95 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}] 96 | 97 | let%expect_test "tx_fourth_byte" = 98 | Waveform.print 99 | ~start_cycle:(Mips.Uart.cycles_per_packet * 3 + 3) 100 | ~display_width:100 ~display_height:16 waves; 101 | [%expect 102 | {| 103 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐ 104 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │ 105 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│ 106 | │valid ││ │ 107 | │ ││──────────────────────────────────────────────────────────────────────────────│ 108 | │ ││──────────────────────────────────────────────────────────────────────────────│ 109 | │value ││ 61727479 │ 110 | │ ││──────────────────────────────────────────────────────────────────────────────│ 111 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│ 112 | │ ││ │ 113 | │uart_tx_valid ││ ┌───────┐ │ 114 | │ ││────────────────────────────────────────────────┘ └─────────────────────│ 115 | │ ││────────────────────────────────────────────────┬─────────────────────────────│ 116 | │uart_tx_value ││ 74 │79 │ 117 | │ ││────────────────────────────────────────────────┴─────────────────────────────│ 118 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}] 119 | 120 | 121 | let%expect_test "tx_fifth_byte (should stop transmitting)" = 122 | Waveform.print 123 | ~start_cycle:(Mips.Uart.cycles_per_packet * 4 + 4) 124 | ~display_width:120 ~display_height:16 waves; 125 | [%expect 126 | {| 127 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────────────────────────┐ 128 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─│ 129 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ │ 130 | │valid ││ │ 131 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│ 132 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│ 133 | │value ││ 61727479 │ 134 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│ 135 | │uart_tx_busy ││────────────────────────────────────────────────────────┐ │ 136 | │ ││ └─────────────────────────────────────────│ 137 | │uart_tx_valid ││ │ 138 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│ 139 | │ ││────────────────────────────────────────────────────────┬─────────────────────────────────────────│ 140 | │uart_tx_value ││ 79 │61 │ 141 | │ ││────────────────────────────────────────────────────────┴─────────────────────────────────────────│ 142 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘ |}] 143 | -------------------------------------------------------------------------------- /test/io/test_delay_test_io.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml_waveterm 3 | open Mips.Delay_test_io 4 | module Simulator = Cyclesim.With_interface (I) (O) 5 | 6 | let testbench enableds = 7 | let scope = Scope.create ~flatten_design:true () in 8 | let sim = Simulator.create (circuit_impl scope) in 9 | let waves, sim = Waveform.create sim in 10 | let inputs = Cyclesim.inputs sim in 11 | 12 | let step read_enabled write_enabled = 13 | inputs.read_enable := Bits.of_bool read_enabled; 14 | inputs.write_enable := Bits.of_bool write_enabled; 15 | Cyclesim.cycle sim 16 | in 17 | 18 | List.iter 19 | (fun (read_enabled, write_enabled) -> step read_enabled write_enabled) 20 | enableds; 21 | 22 | waves 23 | 24 | let%expect_test "stays in not stalling state if nothing happens" = 25 | let pattern = 26 | [ 27 | (false, false); 28 | (false, false); 29 | (false, false); 30 | (false, false); 31 | (false, false); 32 | (false, false); 33 | ] 34 | in 35 | let waves = testbench pattern in 36 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 37 | [%expect 38 | {| 39 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 40 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 41 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 42 | │read_enable ││ │ 43 | │ ││──────────────────────────────────────────────────────────── │ 44 | │write_enable ││ │ 45 | │ ││──────────────────────────────────────────────────────────── │ 46 | │io_busy ││ │ 47 | │ ││──────────────────────────────────────────────────────────── │ 48 | │ ││──────────────────────────────────────────────────────────── │ 49 | │read_data ││ 00000000 │ 50 | │ ││──────────────────────────────────────────────────────────── │ 51 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 52 | 53 | let%expect_test "stalls for correct number of cycles if write happens" = 54 | let pattern = 55 | [ 56 | (false, false); 57 | (false, true); 58 | (false, false); 59 | (false, false); 60 | (false, false); 61 | (false, false); 62 | ] 63 | in 64 | let waves = testbench pattern in 65 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 66 | [%expect 67 | {| 68 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 69 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 70 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 71 | │read_enable ││ │ 72 | │ ││──────────────────────────────────────────────────────────── │ 73 | │write_enable ││ ┌─────────┐ │ 74 | │ ││──────────┘ └─────────────────────────────────────── │ 75 | │io_busy ││ ┌───────────────────────────────────────┐ │ 76 | │ ││──────────┘ └───────── │ 77 | │ ││──────────────────────────────────────────────────────────── │ 78 | │read_data ││ 00000000 │ 79 | │ ││──────────────────────────────────────────────────────────── │ 80 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 81 | 82 | let%expect_test "stalls for correct number of cycles if read and write happen \ 83 | concurrently" = 84 | let pattern = 85 | [ 86 | (false, false); 87 | (true, true); 88 | (false, false); 89 | (false, false); 90 | (false, false); 91 | (false, false); 92 | ] 93 | in 94 | let waves = testbench pattern in 95 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 96 | [%expect 97 | {| 98 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 99 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 100 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 101 | │read_enable ││ ┌─────────┐ │ 102 | │ ││──────────┘ └─────────────────────────────────────── │ 103 | │write_enable ││ ┌─────────┐ │ 104 | │ ││──────────┘ └─────────────────────────────────────── │ 105 | │io_busy ││ ┌───────────────────────────────────────┐ │ 106 | │ ││──────────┘ └───────── │ 107 | │ ││──────────────────────────────┬─────────┬─────────────────── │ 108 | │read_data ││ 00000000 │0000001E │00000000 │ 109 | │ ││──────────────────────────────┴─────────┴─────────────────── │ 110 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 111 | 112 | let%expect_test "stalls for correct number of cycles when reads not back to \ 113 | back" = 114 | let pattern = 115 | [ 116 | (false, false); 117 | (true, false); 118 | (false, false); 119 | (false, false); 120 | (true, false); 121 | (false, false); 122 | (false, false); 123 | (false, false); 124 | ] 125 | in 126 | let waves = testbench pattern in 127 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 128 | [%expect 129 | {| 130 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 131 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 132 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 133 | │read_enable ││ ┌─────────┐ ┌─────────┐ │ 134 | │ ││──────────┘ └───────────────────┘ └─────────────────│ 135 | │write_enable ││ │ 136 | │ ││────────────────────────────────────────────────────────────────────│ 137 | │io_busy ││ ┌───────────────────┐ ┌───────────────────┐ │ 138 | │ ││──────────┘ └─────────┘ └───────│ 139 | │ ││──────────────────────────────┬─────────┬───────────────────┬───────│ 140 | │read_data ││ 00000000 │0000001E │00000000 │0000001│ 141 | │ ││──────────────────────────────┴─────────┴───────────────────┴───────│ 142 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 143 | 144 | let%expect_test "when ops back to back, will always halt after first one." = 145 | let pattern = 146 | [ 147 | (false, false); 148 | (true, false); 149 | (false, false); 150 | (true, false); 151 | (false, false); 152 | (false, false); 153 | (false, false); 154 | ] 155 | in 156 | let waves = testbench pattern in 157 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 158 | [%expect 159 | {| 160 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 161 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 162 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 163 | │read_enable ││ ┌─────────┐ ┌─────────┐ │ 164 | │ ││──────────┘ └─────────┘ └───────────────────────────│ 165 | │write_enable ││ │ 166 | │ ││────────────────────────────────────────────────────────────────────│ 167 | │io_busy ││ ┌───────────────────┐ │ 168 | │ ││──────────┘ └─────────────────────────────────────│ 169 | │ ││──────────────────────────────┬─────────┬───────────────────────────│ 170 | │read_data ││ 00000000 │0000001E │00000000 │ 171 | │ ││──────────────────────────────┴─────────┴───────────────────────────│ 172 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 173 | 174 | let%expect_test "stalls for correct number of cycles starts with a read, ends \ 175 | with a write" = 176 | let pattern = 177 | [ 178 | (true, false); 179 | (false, false); 180 | (false, false); 181 | (false, true); 182 | (false, false); 183 | (false, false); 184 | (false, false); 185 | ] 186 | in 187 | let waves = testbench pattern in 188 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves; 189 | [%expect 190 | {| 191 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 192 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 193 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 194 | │read_enable ││──────────┐ │ 195 | │ ││ └─────────────────────────────────────────────────────────│ 196 | │write_enable ││ ┌─────────┐ │ 197 | │ ││──────────────────────────────┘ └───────────────────────────│ 198 | │io_busy ││────────────────────┐ ┌─────────────────────────────────────│ 199 | │ ││ └─────────┘ │ 200 | │ ││────────────────────┬─────────┬─────────────────────────────────────│ 201 | │read_data ││ 00000000 │0000001E │00000000 │ 202 | │ ││────────────────────┴─────────┴─────────────────────────────────────│ 203 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}] 204 | -------------------------------------------------------------------------------- /lib/instruction_decode/control_unit.ml: -------------------------------------------------------------------------------- 1 | open Hardcaml 2 | open Hardcaml.Signal 3 | 4 | module Instruction_format = struct 5 | let default = of_string "2'h0" 6 | 7 | let r_type = of_string "2'h1" 8 | 9 | let i_type = of_string "2'h2" 10 | 11 | let j_type = of_string "2'h3" 12 | end 13 | 14 | module Instruction_type = struct 15 | let default = of_int ~width:7 0 16 | 17 | (* Arithmetic *) 18 | let add = of_int ~width:7 10 19 | 20 | let addu = of_int ~width:7 11 21 | 22 | let addi = of_int ~width:7 12 23 | 24 | let addiu = of_int ~width:7 13 25 | 26 | let sub = of_int ~width:7 14 27 | 28 | let subu = of_int ~width:7 15 29 | 30 | (* Basic Logical *) 31 | let and_ = of_int ~width:7 20 32 | 33 | let andi = of_int ~width:7 21 34 | 35 | let or_ = of_int ~width:7 22 36 | 37 | let ori = of_int ~width:7 23 38 | 39 | let xor = of_int ~width:7 24 40 | 41 | let xori = of_int ~width:7 25 42 | 43 | (* Shifts *) 44 | let sll = of_int ~width:7 30 45 | 46 | let sllv = of_int ~width:7 31 47 | 48 | let srl = of_int ~width:7 32 49 | 50 | let srlv = of_int ~width:7 33 51 | 52 | let sra = of_int ~width:7 34 53 | 54 | let srav = of_int ~width:7 35 55 | 56 | (* Other I-Type *) 57 | let lui = of_int ~width:7 40 58 | 59 | (* Comparison *) 60 | let slt = of_int ~width:7 50 61 | 62 | let sltu = of_int ~width:7 51 63 | 64 | let slti = of_int ~width:7 52 65 | 66 | let sltiu = of_int ~width:7 53 67 | 68 | 69 | (* Memory *) 70 | let lw = of_int ~width:7 60 71 | 72 | let sw = of_int ~width:7 61 73 | 74 | (* Jump *) 75 | 76 | let j = of_int ~width:7 70 77 | 78 | let jr = of_int ~width:7 71 79 | 80 | let jal = of_int ~width:7 72 81 | 82 | (* Branch *) 83 | 84 | let bne = of_int ~width:7 80 85 | 86 | let beq = of_int ~width:7 81 87 | end 88 | 89 | module Alu_ops = struct 90 | let default = of_int ~width:5 0 91 | 92 | let noop = of_int ~width:5 1 93 | 94 | let add = of_int ~width:5 2 95 | 96 | let addu = of_int ~width:5 3 97 | 98 | let and_ = of_int ~width:5 4 99 | 100 | let lui = of_int ~width:5 5 101 | 102 | let or_ = of_int ~width:5 6 103 | 104 | let slt = of_int ~width:5 7 105 | 106 | let sltu = of_int ~width:5 8 107 | 108 | let sll = of_int ~width:5 9 109 | 110 | let sra = of_int ~width:5 10 111 | 112 | let srl = of_int ~width:5 11 113 | 114 | let sub = of_int ~width:5 12 115 | 116 | let subu = of_int ~width:5 13 117 | 118 | let xor = of_int ~width:5 14 119 | end 120 | 121 | module Pc_sel = struct 122 | module Enum = struct 123 | type t = 124 | | Pc_incr 125 | | Jump_addr 126 | | Jump_reg 127 | | Branch_eq 128 | | Branch_neq 129 | [@@deriving sexp_of, compare, enumerate] 130 | end 131 | 132 | include Interface.Make_enums(Enum) 133 | end 134 | 135 | module Parsed_instruction = struct 136 | type 'a t = { 137 | rs : 'a; [@bits 5] 138 | rt : 'a; [@bits 5] 139 | rdest : 'a; [@bits 5] 140 | shamt : 'a; [@bits 5] 141 | se_imm : 'a; [@bits 32] 142 | alu_imm : 'a; [@bits 32] 143 | addr: 'a; [@bits 26] 144 | } 145 | [@@deriving sexp_of, hardcaml] 146 | end 147 | 148 | module Control_signals = struct 149 | type 'a t = { 150 | reg_write_enable : 'a; 151 | sel_mem_for_reg_data : 'a; 152 | mem_write_enable : 'a; 153 | mem_read_enable : 'a; 154 | sel_shift_for_alu : 'a; 155 | sel_imm_for_alu : 'a; 156 | stall_pc: 'a; 157 | jal: 'a; 158 | alu_control : 'a; [@bits width Alu_ops.default] 159 | pc_sel: 'a Pc_sel.Binary.t; 160 | } 161 | [@@deriving sexp_of, hardcaml] 162 | end 163 | 164 | module I = struct 165 | type 'a t = { instruction : 'a [@bits 32] } [@@deriving sexp_of, hardcaml] 166 | end 167 | 168 | module O = struct 169 | type 'a t = { 170 | parsed_instruction : 'a Parsed_instruction.t; 171 | control_signals : 'a Control_signals.t; 172 | } 173 | [@@deriving sexp_of, hardcaml] 174 | end 175 | 176 | let rtype_classifier instr = 177 | let module T = Instruction_type in 178 | let funct = instr.:[(5, 0)] in 179 | let type_ = Always.Variable.wire ~default:T.default in 180 | Always.( 181 | compile 182 | [ 183 | switch funct 184 | [ 185 | (of_string "6'b100000", [ type_ <-- T.add ]); 186 | (of_string "6'b100001", [ type_ <-- T.addu ]); 187 | (of_string "6'b100011", [ type_ <-- T.subu ]); 188 | (of_string "6'b100100", [ type_ <-- T.and_ ]); 189 | (of_string "6'b100010", [ type_ <-- T.sub ]); 190 | (of_string "6'b100101", [ type_ <-- T.or_ ]); 191 | (of_string "6'b100110", [ type_ <-- T.xor ]); 192 | (of_string "6'b101010", [ type_ <-- T.slt ]); 193 | (of_string "6'b101011", [ type_ <-- T.sltu ]); 194 | (of_string "6'b000000", [ type_ <-- T.sll ]); 195 | (of_string "6'b000010", [ type_ <-- T.srl ]); 196 | (of_string "6'b000011", [ type_ <-- T.sra ]); 197 | (of_string "6'b000100", [ type_ <-- T.sllv ]); 198 | (of_string "6'b000110", [ type_ <-- T.srlv ]); 199 | (of_string "6'b000111", [ type_ <-- T.srav ]); 200 | (of_string "6'b001000", [ type_ <-- T.jr ]); 201 | ]; 202 | ]); 203 | Always.Variable.value type_ 204 | 205 | let classifier instr = 206 | let module F = Instruction_format in 207 | let module T = Instruction_type in 208 | let opcode = instr.:[(31, 26)] in 209 | let format = Always.Variable.wire ~default:Instruction_format.default in 210 | let type_ = Always.Variable.wire ~default:Instruction_type.default in 211 | Always.( 212 | compile 213 | [ 214 | switch opcode 215 | [ 216 | ( of_string "6'b000000", 217 | [ format <-- F.r_type; type_ <-- rtype_classifier instr ] ); 218 | (of_string "6'b001000", [ format <-- F.i_type; type_ <-- T.addi ]); 219 | (of_string "6'b001001", [ format <-- F.i_type; type_ <-- T.addiu ]); 220 | (of_string "6'b001100", [ format <-- F.i_type; type_ <-- T.andi ]); 221 | (of_string "6'b001101", [ format <-- F.i_type; type_ <-- T.ori ]); 222 | (of_string "6'b001110", [ format <-- F.i_type; type_ <-- T.xori ]); 223 | (of_string "6'b001111", [ format <-- F.i_type; type_ <-- T.lui ]); 224 | (of_string "6'b001010", [ format <-- F.i_type; type_ <-- T.slti ]); 225 | (of_string "6'b001011", [ format <-- F.i_type; type_ <-- T.sltiu ]); 226 | (of_string "6'b100011", [ format <-- F.i_type; type_ <-- T.lw ]); 227 | (of_string "6'b101011", [ format <-- F.i_type; type_ <-- T.sw ]); 228 | (of_string "6'b000010", [ format <-- F.j_type; type_ <-- T.j]); 229 | (of_string "6'b000011", [ format <-- F.j_type; type_ <-- T.jal]); 230 | (of_string "6'b000101", [ format <-- F.j_type; type_ <-- T.bne]); 231 | (of_string "6'b000100", [ format <-- F.j_type; type_ <-- T.beq]); 232 | 233 | ]; 234 | ]); 235 | (Always.Variable.value format, Always.Variable.value type_) 236 | 237 | 238 | let parser instr format type_ = 239 | let rt = instr.:[(20, 16)] in 240 | let rd = instr.:[(15, 11)] in 241 | let rdest = priority_select_with_default ~default:rd 242 | [ 243 | { 244 | With_valid.valid = type_ ==: Instruction_type.jal; 245 | value = of_string "5'd31"; 246 | }; 247 | { 248 | With_valid.valid = format ==: Instruction_format.i_type; 249 | value = rt; 250 | }; 251 | ] in 252 | let ze_imm = uresize instr.:[(15, 0)] 32 in 253 | let se_imm = sresize instr.:[(15, 0)] 32 in 254 | let use_ze_for_imm = 255 | type_ ==: Instruction_type.addiu 256 | |: (type_ ==: Instruction_type.sltiu) 257 | |: (type_ ==: Instruction_type.lw) 258 | |: (type_ ==: Instruction_type.sw) 259 | |: (type_ ==: Instruction_type.andi) 260 | |: (type_ ==: Instruction_type.ori) 261 | |: (type_ ==: Instruction_type.xori) 262 | |: (type_ ==: Instruction_type.sll) 263 | |: (type_ ==: Instruction_type.srl) 264 | |: (type_ ==: Instruction_type.sra) 265 | in 266 | let alu_imm = mux2 use_ze_for_imm ze_imm se_imm in 267 | let module P = Parsed_instruction in 268 | { 269 | P.rs = instr.:[(25, 21)]; 270 | rt; 271 | rdest; 272 | shamt = instr.:[(10, 6)]; 273 | se_imm; 274 | alu_imm; 275 | addr = instr.:[(25, 0)]; 276 | } 277 | 278 | let type_to_alu_control type_ = 279 | let module O = Alu_ops in 280 | let module T = Instruction_type in 281 | let aluc = Always.Variable.wire ~default:Alu_ops.default in 282 | Always.( 283 | compile 284 | [ 285 | switch type_ 286 | [ 287 | (* Arithmetic *) 288 | (T.add, [ aluc <-- O.add ]); 289 | (T.addu, [ aluc <-- O.addu ]); 290 | (T.addi, [ aluc <-- O.addu ]); 291 | (T.addiu, [ aluc <-- O.addu ]); 292 | (T.sub, [ aluc <-- O.sub ]); 293 | (T.subu, [ aluc <-- O.subu ]); 294 | (* Basic Logical *) 295 | (T.and_, [ aluc <-- O.and_ ]); 296 | (T.andi, [ aluc <-- O.and_ ]); 297 | (T.or_, [ aluc <-- O.or_ ]); 298 | (T.ori, [ aluc <-- O.or_ ]); 299 | (T.xor, [ aluc <-- O.xor ]); 300 | (T.xori, [ aluc <-- O.xor ]); 301 | (* Shifts *) 302 | (T.sll, [ aluc <-- O.sll ]); 303 | (T.sllv, [ aluc <-- O.sll ]); 304 | (T.sra, [ aluc <-- O.sra ]); 305 | (T.srav, [ aluc <-- O.sra ]); 306 | (T.srl, [ aluc <-- O.srl ]); 307 | (T.srlv, [ aluc <-- O.srl ]); 308 | (* Other I-Type *) 309 | (T.lui, [ aluc <-- O.lui ]); 310 | (* Comparison *) 311 | (T.slt, [ aluc <-- O.slt ]); 312 | (T.sltu, [ aluc <-- O.sltu ]); 313 | (T.slti, [ aluc <-- O.slt ]); 314 | (T.sltiu, [ aluc <-- O.sltu ]); 315 | (* Memory *) 316 | (T.lw, [ aluc <-- O.add ]); 317 | (T.sw, [ aluc <-- O.add ]); 318 | (* Jump *) 319 | (T.j, [ aluc <-- O.noop ]); 320 | (T.jal, [ aluc <-- O.noop ]); 321 | (T.jr, [ aluc <-- O.noop ]); 322 | (* Branch *) 323 | (T.bne, [ aluc <-- O.noop ]); 324 | (T.beq, [ aluc <-- O.noop ]); 325 | ]; 326 | ]); 327 | Always.Variable.value aluc 328 | 329 | let type_to_pc_sel type_ = 330 | let module PE = Pc_sel.Enum in 331 | let module PB = Pc_sel.Binary in 332 | let of_enum = PB.of_enum (module Signal) in 333 | PB.Of_signal.priority_select_with_default ~default:(of_enum PE.Pc_incr) 334 | [ 335 | { 336 | With_valid.valid = (type_ ==: Instruction_type.j )|: (type_ ==: Instruction_type.jal); 337 | value = of_enum PE.Jump_addr; 338 | }; 339 | { 340 | With_valid.valid = type_ ==: Instruction_type.jr; 341 | value = of_enum PE.Jump_reg; 342 | }; 343 | { 344 | With_valid.valid = type_ ==: Instruction_type.beq; 345 | value = of_enum PE.Branch_eq; 346 | }; 347 | { 348 | With_valid.valid = type_ ==: Instruction_type.bne; 349 | value = of_enum PE.Branch_neq; 350 | }; 351 | ] 352 | 353 | let control_core format type_ = 354 | let module F = Instruction_format in 355 | let module T = Instruction_type in 356 | let reg_write_enable = 357 | ((format ==: F.r_type) &: (type_ <>: T.jr)) |: (type_ ==: T.addi) |: (type_ ==: T.addiu) 358 | |: (type_ ==: T.andi) |: (type_ ==: T.ori) |: (type_ ==: T.xori) 359 | |: (type_ ==: T.lui) |: (type_ ==: T.slti) |: (type_ ==: T.sltiu) 360 | |: (type_ ==: T.lw) |: (type_ ==: T.jal) 361 | in 362 | let sel_mem_for_reg_data = type_ ==: T.lw in 363 | let mem_write_enable = type_ ==: T.sw in 364 | let mem_read_enable = type_ ==: T.lw in 365 | let sel_shift_for_alu = 366 | type_ ==: T.sll |: (type_ ==: T.srl) |: (type_ ==: T.sra) 367 | in 368 | let sel_imm_for_alu = format ==: F.i_type in 369 | let alu_control = type_to_alu_control type_ in 370 | let pc_sel = type_to_pc_sel type_ in 371 | let jal = type_ ==: T.jal in 372 | let module C = Control_signals in 373 | { 374 | C.reg_write_enable; 375 | sel_mem_for_reg_data; 376 | mem_write_enable; 377 | mem_read_enable; 378 | sel_shift_for_alu; 379 | sel_imm_for_alu; 380 | alu_control; 381 | (* This will get overriden in `instruction_decode` *) 382 | stall_pc = of_string "1'b0"; 383 | pc_sel; 384 | jal; 385 | } 386 | 387 | let circuit_impl (_scope : Scope.t) (input : _ I.t) = 388 | let instr_format, type_ = classifier input.instruction in 389 | let parsed_instruction = parser input.instruction instr_format type_ in 390 | let control_signals = control_core instr_format type_ in 391 | { O.parsed_instruction; control_signals } 392 | 393 | let circuit_impl_exn scope input = 394 | let module W = Width_check.With_interface (I) (O) in 395 | W.check_widths (circuit_impl scope) input 396 | 397 | let hierarchical scope input = 398 | let module H = Hierarchy.In_scope (I) (O) in 399 | H.hierarchical ~scope ~name:"control_unit" circuit_impl_exn input 400 | -------------------------------------------------------------------------------- /arty/boards/arty-a7-35/E.0/preset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | -------------------------------------------------------------------------------- /test/instruction_decode/test_instruction_decode.ml: -------------------------------------------------------------------------------- 1 | open! Base 2 | open Hardcaml 3 | open Hardcaml_waveterm 4 | open Mips.Instruction_decode 5 | module Simulator = Cyclesim.With_interface (I) (O) 6 | 7 | type test_input = { 8 | instruction : string; 9 | write_enable : string; 10 | write_address : string; 11 | write_data : string; 12 | } 13 | 14 | let testbench tests = 15 | let scope = Scope.create ~flatten_design:true () in 16 | let sim = Simulator.create (circuit_impl_exn scope) in 17 | let waves, sim = Waveform.create sim in 18 | let inputs = Cyclesim.inputs sim in 19 | 20 | let step ~test = 21 | inputs.enable_pipeline := Bits.of_bool true; 22 | inputs.instruction := Bits.of_string test.instruction; 23 | inputs.writeback_reg_write_enable := Bits.of_string test.write_enable; 24 | inputs.writeback_address := Bits.of_string test.write_address; 25 | inputs.writeback_data := Bits.of_string test.write_data; 26 | Cyclesim.cycle sim 27 | in 28 | 29 | List.iter tests ~f:(fun test -> step ~test); 30 | 31 | waves 32 | 33 | let%expect_test "can we read and write to/from reg file properly" = 34 | let add_rs_9_rt_8_rd_10 = "32'h01285020" in 35 | let tests = 36 | [ 37 | (* First, check that write_enable=0 doesn't write, and that initially reads 0 *) 38 | { 39 | instruction = add_rs_9_rt_8_rd_10; 40 | write_enable = "1'h0"; 41 | write_address = "5'h9"; 42 | write_data = "32'h7"; 43 | }; 44 | (* alu_a should now be 6 after this step *) 45 | { 46 | instruction = add_rs_9_rt_8_rd_10; 47 | write_enable = "1'h1"; 48 | write_address = "5'h9"; 49 | write_data = "32'h6"; 50 | }; 51 | (* Another test that write_enable=0 works as intended *) 52 | { 53 | instruction = add_rs_9_rt_8_rd_10; 54 | write_enable = "1'h0"; 55 | write_address = "5'h8"; 56 | write_data = "32'h20"; 57 | }; 58 | (* After this step, both alu_a and alu_b should have values: 6 and 21 respectively *) 59 | { 60 | instruction = add_rs_9_rt_8_rd_10; 61 | write_enable = "1'h1"; 62 | write_address = "5'h8"; 63 | write_data = "32'h21"; 64 | }; 65 | (* One more for good measure *) 66 | { 67 | instruction = add_rs_9_rt_8_rd_10; 68 | write_enable = "1'h0"; 69 | write_address = "5'h0"; 70 | write_data = "32'h0"; 71 | }; 72 | ] 73 | in 74 | let waves = testbench tests in 75 | Waveform.expect ~show_digest:true ~wave_width:4 ~display_width:90 76 | ~display_height:68 waves; 77 | [%expect 78 | {| 79 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 80 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 81 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 82 | │ ││────────────────────────────────────────────────── │ 83 | │e_alu_output ││ 00000000 │ 84 | │ ││────────────────────────────────────────────────── │ 85 | │enable_pipeline ││────────────────────────────────────────────────── │ 86 | │ ││ │ 87 | │ ││────────────────────────────────────────────────── │ 88 | │instruction ││ 01285020 │ 89 | │ ││────────────────────────────────────────────────── │ 90 | │ ││────────────────────────────────────────────────── │ 91 | │m_alu_output ││ 00000000 │ 92 | │ ││────────────────────────────────────────────────── │ 93 | │ ││────────────────────────────────────────────────── │ 94 | │m_data_output ││ 00000000 │ 95 | │ ││────────────────────────────────────────────────── │ 96 | │ ││────────────────────┬───────────────────┬───────── │ 97 | │writeback_address ││ 09 │08 │00 │ 98 | │ ││────────────────────┴───────────────────┴───────── │ 99 | │ ││──────────┬─────────┬─────────┬─────────┬───────── │ 100 | │writeback_data ││ 00000007 │00000006 │00000020 │00000021 │00000000 │ 101 | │ ││──────────┴─────────┴─────────┴─────────┴───────── │ 102 | │writeback_reg_writ││ ┌─────────┐ ┌─────────┐ │ 103 | │ ││──────────┘ └─────────┘ └───────── │ 104 | │ ││────────────────────────────────────────────────── │ 105 | │addr ││ 1285020 │ 106 | │ ││────────────────────────────────────────────────── │ 107 | │ ││──────────┬─────────────────────────────────────── │ 108 | │alu_a ││ 00000000 │00000006 │ 109 | │ ││──────────┴─────────────────────────────────────── │ 110 | │ ││──────────────────────────────┬─────────────────── │ 111 | │alu_b ││ 00000000 │00000021 │ 112 | │ ││──────────────────────────────┴─────────────────── │ 113 | │ ││────────────────────────────────────────────────── │ 114 | │alu_control ││ 02 │ 115 | │ ││────────────────────────────────────────────────── │ 116 | │ ││────────────────────────────────────────────────── │ 117 | │alu_imm ││ 00005020 │ 118 | │ ││────────────────────────────────────────────────── │ 119 | │ ││────────────────────────────────────────────────── │ 120 | │binary_variant ││ 0 │ 121 | │ ││────────────────────────────────────────────────── │ 122 | │jal ││ │ 123 | │ ││────────────────────────────────────────────────── │ 124 | │mem_read_enable ││ │ 125 | │ ││────────────────────────────────────────────────── │ 126 | │mem_write_enable ││ │ 127 | │ ││────────────────────────────────────────────────── │ 128 | │ ││────────────────────────────────────────────────── │ 129 | │rdest ││ 0A │ 130 | │ ││────────────────────────────────────────────────── │ 131 | │reg_write_enable ││────────────────────────────────────────────────── │ 132 | │ ││ │ 133 | │ ││────────────────────────────────────────────────── │ 134 | │se_imm ││ 00005020 │ 135 | │ ││────────────────────────────────────────────────── │ 136 | │sel_imm_for_alu ││ │ 137 | │ ││────────────────────────────────────────────────── │ 138 | │sel_mem_for_reg_da││ │ 139 | │ ││────────────────────────────────────────────────── │ 140 | │sel_shift_for_alu ││ │ 141 | │ ││────────────────────────────────────────────────── │ 142 | │stall_pc ││ │ 143 | │ ││────────────────────────────────────────────────── │ 144 | │ ││ │ 145 | │ ││ │ 146 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ 147 | b8927b78dd2fad3be72c95e9789ed5b9 |}] 148 | 149 | let%expect_test "0 register always returns 0, regardless of actual contents" = 150 | let add_rs_9_rt_0_rd_8 = "32'h01204020" in 151 | let tests = 152 | [ 153 | (* First, write to the 0 register. rt should still be 0 after this. *) 154 | { 155 | instruction = add_rs_9_rt_0_rd_8; 156 | write_enable = "1'h1"; 157 | write_address = "5'h0"; 158 | write_data = "32'h7"; 159 | }; 160 | (* Next, write to register 8. rs should be 7 after this. *) 161 | { 162 | instruction = add_rs_9_rt_0_rd_8; 163 | write_enable = "1'h1"; 164 | write_address = "5'h9"; 165 | write_data = "32'h7"; 166 | }; 167 | { 168 | instruction = add_rs_9_rt_0_rd_8; 169 | write_enable = "1'h0"; 170 | write_address = "5'h0"; 171 | write_data = "32'h7"; 172 | }; 173 | ] 174 | in 175 | let waves = testbench tests in 176 | Waveform.expect ~show_digest:true ~wave_width:4 ~display_width:90 177 | ~display_height:68 waves; 178 | [%expect 179 | {| 180 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐ 181 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ 182 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│ 183 | │ ││────────────────────────────── │ 184 | │e_alu_output ││ 00000000 │ 185 | │ ││────────────────────────────── │ 186 | │enable_pipeline ││────────────────────────────── │ 187 | │ ││ │ 188 | │ ││────────────────────────────── │ 189 | │instruction ││ 01204020 │ 190 | │ ││────────────────────────────── │ 191 | │ ││────────────────────────────── │ 192 | │m_alu_output ││ 00000000 │ 193 | │ ││────────────────────────────── │ 194 | │ ││────────────────────────────── │ 195 | │m_data_output ││ 00000000 │ 196 | │ ││────────────────────────────── │ 197 | │ ││──────────┬─────────┬───────── │ 198 | │writeback_address ││ 00 │09 │00 │ 199 | │ ││──────────┴─────────┴───────── │ 200 | │ ││────────────────────────────── │ 201 | │writeback_data ││ 00000007 │ 202 | │ ││────────────────────────────── │ 203 | │writeback_reg_writ││────────────────────┐ │ 204 | │ ││ └───────── │ 205 | │ ││────────────────────────────── │ 206 | │addr ││ 1204020 │ 207 | │ ││────────────────────────────── │ 208 | │ ││──────────┬─────────────────── │ 209 | │alu_a ││ 00000000 │00000007 │ 210 | │ ││──────────┴─────────────────── │ 211 | │ ││────────────────────────────── │ 212 | │alu_b ││ 00000000 │ 213 | │ ││────────────────────────────── │ 214 | │ ││────────────────────────────── │ 215 | │alu_control ││ 02 │ 216 | │ ││────────────────────────────── │ 217 | │ ││────────────────────────────── │ 218 | │alu_imm ││ 00004020 │ 219 | │ ││────────────────────────────── │ 220 | │ ││────────────────────────────── │ 221 | │binary_variant ││ 0 │ 222 | │ ││────────────────────────────── │ 223 | │jal ││ │ 224 | │ ││────────────────────────────── │ 225 | │mem_read_enable ││ │ 226 | │ ││────────────────────────────── │ 227 | │mem_write_enable ││ │ 228 | │ ││────────────────────────────── │ 229 | │ ││────────────────────────────── │ 230 | │rdest ││ 08 │ 231 | │ ││────────────────────────────── │ 232 | │reg_write_enable ││────────────────────────────── │ 233 | │ ││ │ 234 | │ ││────────────────────────────── │ 235 | │se_imm ││ 00004020 │ 236 | │ ││────────────────────────────── │ 237 | │sel_imm_for_alu ││ │ 238 | │ ││────────────────────────────── │ 239 | │sel_mem_for_reg_da││ │ 240 | │ ││────────────────────────────── │ 241 | │sel_shift_for_alu ││ │ 242 | │ ││────────────────────────────── │ 243 | │stall_pc ││ │ 244 | │ ││────────────────────────────── │ 245 | │ ││ │ 246 | │ ││ │ 247 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ 248 | d6d577b829d8e9bf8f327c83d9c64474 |}] 249 | 250 | let%expect_test "Stalls when appropriate" = 251 | let add_rs_9_rt_0_rd_8 = "32'h01204020" in 252 | let lw_into_9 = "32'h8D090000" in 253 | let lw_into_8 = "32'h8C080000" in 254 | let sw_from_8 = "32'hAD0D0000" in 255 | let sw_from_9 = "32'hAD2D0000" in 256 | 257 | let no_write = 258 | { 259 | instruction = "INVALID"; 260 | write_enable = "1'b0"; 261 | write_address = "5'h0"; 262 | write_data = "32'h0"; 263 | } 264 | in 265 | 266 | let tests = 267 | [ 268 | (* Should stall here *) 269 | { no_write with instruction = lw_into_9 }; 270 | { no_write with instruction = add_rs_9_rt_0_rd_8 }; 271 | (* Shouldn't stall on the first two as no register overlap *) 272 | { no_write with instruction = lw_into_8 }; 273 | { no_write with instruction = add_rs_9_rt_0_rd_8 }; 274 | (* Should stall again, but this time mem write should be affected *) 275 | { no_write with instruction = lw_into_9 }; 276 | { no_write with instruction = sw_from_9 }; 277 | (* Shouldn't stall here either, same reason. *) 278 | { no_write with instruction = lw_into_9 }; 279 | { no_write with instruction = sw_from_8 }; 280 | ] 281 | in 282 | let waves = testbench tests in 283 | 284 | let display_rules = 285 | [ 286 | Display_rule.port_name_is_one_of 287 | [ "stall_pc"; "mem_write_enable"; "reg_write_enable" ] 288 | ~wave_format:Wave_format.Bit; 289 | ] 290 | in 291 | Waveform.expect ~display_rules ~show_digest:true ~wave_width:4 292 | ~display_width:130 ~display_height:10 waves; 293 | [%expect 294 | {| 295 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────────────────────────────────────────────┐ 296 | │mem_write_enable ││ ┌───────── │ 297 | │ ││──────────────────────────────────────────────────────────────────────┘ │ 298 | │reg_write_enable ││──────────┐ ┌─────────────────────────────┐ ┌─────────┐ │ 299 | │ ││ └─────────┘ └─────────┘ └───────── │ 300 | │stall_pc ││ ┌─────────┐ ┌─────────┐ │ 301 | │ ││──────────┘ └─────────────────────────────┘ └─────────────────── │ 302 | │ ││ │ 303 | │ ││ │ 304 | └──────────────────┘└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 305 | 0c7d7f198064acf7ecb50adff2647c62 |}] 306 | --------------------------------------------------------------------------------