diff --git a/.gitignore b/.gitignore
index 1138ab5..8eb0af9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,11 +6,12 @@
*.swp
*.memdump
*.lxt # Not sure when those crop up
-boot_code/brainfuck.bin
-boot_code/brainfuck.txt
+boot_code/brainfuck_interpreted.bin
+boot_code/brainfuck_interpreted.txt
boot_code/brainfuck_mandelbrot.bin
boot_code/brainfuck_mandelbrot.txt
boot_code/brainfuck_compiled.bin
boot_code/brainfuck_compiled.txt
system/boot_code.bin
system/boot_code.txt
+system/obj_dir/
diff --git a/Makefile b/Makefile
index aed1553..3c9059d 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@
#
SYSTEM_VVP=system/system.vvp
+VERILATOR_BIN=system/obj_dir/Vsystem
BOOT_CODE=boot_code/brainfuck_mandelbrot.txt
GTKWSAVE=./gtkwave_savefile.gtkw
MICROCODE=system/ucode.txt
@@ -38,6 +39,10 @@ boot_code/%.txt:
${SYSTEM_VVP}:
${Q}make ${MAKEOPTS} -C system system.vvp
+.PHONY:${VERILATOR_BIN}
+${VERILATOR_BIN}:
+ ${Q}make ${MAKEOPTS} -C system obj_dir/Vsystem
+
.PHONY: clean
clean:
${Q}make ${MAKEOPTS} -C system clean
diff --git a/common.mk b/common.mk
index 80da53d..89d3a33 100644
--- a/common.mk
+++ b/common.mk
@@ -1,11 +1,22 @@
.PRECIOUS:${BOOT_CODE}
+
QUIET=1
+# QUIET: 1=clean, non-verbose output
+# 2=normal make output
+
+SIM=VERILATOR
+#SIM=ICARUS
+# SIM: VERILATOR: use Verilator
+# ICARUS: use Icarus Verilog
+
ifeq "${QUIET}" "1"
- QUIET_AS = @echo ' AS '$@;
- QUIET_VVP = @echo ' VVP '$@;
- QUIET_IVERILOG = @echo ' IVERILOG '$@;
- QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
+ QUIET_AS = @echo ' AS '$@;
+ QUIET_VVP = @echo ' VVP '$@;
+ QUIET_IVERILOG = @echo ' IVERILOG '$@;
+ QUIET_VERILATOR = @echo ' VERILATOR '$@;
+ QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
+ QUIET_VERILATOR_RUN = @printf ' %s %s\n' $1 $2;
Q = @
MAKEOPTS=--no-print-directory
.SILENT:
@@ -34,15 +45,27 @@ ifeq "${NO_ASM}" "0"
endif
# Running simulation
-%.lx2 %.memdump: %.txt ${SYSTEM_VVP}
+ifeq "${SIM}" "ICARUS"
+%.lx2 %.memdump: %.txt ${SYSTEM_VVP} ${MICROCODE}
${QUIET_VVP}
${Q}vvp "${SYSTEM_VVP}" -lxt2 +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.lx2,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
${Q}grep -v '^//' "$(subst .txt,.memdumptxt,$<)" | xxd -ps -c 2 -r > "$(subst .txt,.memdump,$<)"
${Q}rm "$(subst .txt,.memdumptxt,$<)"
-%.run: %.txt ${SYSTEM_VVP}
+%.run: %.txt ${SYSTEM_VVP} ${MICROCODE}
${QUIET_VVP}
${Q}vvp -i "${SYSTEM_VVP}" +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
+else ifeq "${SIM}" "VERILATOR"
+%.lx2 %.memdump: %.txt ${VERILATOR_BIN} ${MICROCODE}
+ $(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
+ ${Q}"${VERILATOR_BIN}" +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.lx2,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
+ ${Q}grep -v '^//' "$(subst .txt,.memdumptxt,$<)" | xxd -ps -c 2 -r > "$(subst .txt,.memdump,$<)"
+ ${Q}rm "$(subst .txt,.memdumptxt,$<)"
+
+%.run: %.txt ${VERILATOR_BIN} ${MICROCODE}
+ $(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
+ ${Q}numactl -m 0 -C 17,18 -- "${VERILATOR_BIN}" +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
+endif
%.disas: %.bin
objdump -D -b binary -m i8086 $^ | less
diff --git a/system/Makefile b/system/Makefile
index bad380c..d0c9e64 100644
--- a/system/Makefile
+++ b/system/Makefile
@@ -15,9 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-SOURCES=processor.v testbench.v memory.v registers.v alu.v decoder.v general.v
-INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v ${MICROCODE}
+TOP_LEVEL_SOURCE=system.v
+SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v
+EVENT_SIM_TESTBENCH=testbench.v
+VERILATOR_TESTBENCH=testbench.cpp
+INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v
SYSTEM_VVP=system.vvp
+VERILATOR_BIN=obj_dir/Vsystem
BOOT_CODE=boot_code.txt
GTKWSAVE=../gtkwave_savefile.gtkw
MICROCODE=ucode.txt
@@ -26,12 +30,15 @@ NO_ASM=0
include ../common.mk
# COMPILING
-${SYSTEM_VVP} : ${SOURCES} ${INCLUDES}
+${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH}
${QUIET_IVERILOG}
- ${Q}iverilog -g2012 -o "$@" ${SOURCES}
+ ${Q}iverilog -g2012 -o "$@" ${TOP_LEVEL_SOURCE} ${SOURCES} ${EVENT_SIM_TESTBENCH}
+${VERILATOR_BIN}: ${VERILATOR_TESTBENCH} ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES}
+ ${QUIET_VERILATOR}
+ ${Q}verilator --cc --exe --build -j 0 $^ -Wall --Wno-DECLFILENAME -Wno-SYNCASYNCNET -Wno-MULTIDRIVEN 2>&1 --threads 1 --autoflush >/dev/null #TODO: remove the silencing and make the generated Makefiles print quietly as well
.PHONY: clean
clean:
$(call QUIET_CLEAN,system)
- ${Q}rm -f ${SYSTEM_VVP} *.lx2 boot_code.txt boot_code.bin *memdump *memdumptxt
+ ${Q}rm -rf ${SYSTEM_VVP} *.lx2 boot_code.txt boot_code.bin *memdump *memdumptxt obj_dir
diff --git a/system/memory.v b/system/memory.v
index 56d4d8e..8c41203 100644
--- a/system/memory.v
+++ b/system/memory.v
@@ -17,8 +17,13 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
+// don't ask for the full 1MiB especially since we don't even have segmentation
+/* verilator lint_off UNUSEDSIGNAL */
module doublemem(input [19:0] address,inout wire [15:0] data ,input rd,input wr,input BHE,input cs);
+/* verilator lint_on UNUSEDSIGNAL */
+
reg [15:0] memory [0:32768];
+
initial begin
string boot_code;
if(!$value$plusargs("BOOT_CODE=%s",boot_code))begin
@@ -28,15 +33,15 @@ initial begin
$readmemh(boot_code, memory,0,16383);
end
-assign data[7:0] = !address[0:0] & !rd & !cs ? memory[address[15:1]][15:8] : 16'hz;
+assign data[7:0] = !address[0:0] & !rd & !cs ? memory[address[16:1]][15:8] : 8'hz;
-assign data[15:8] = !BHE & !rd & !cs ? memory[address[15:1]][7:0] : 16'hz;
+assign data[15:8] = !BHE & !rd & !cs ? memory[address[16:1]][7:0] : 8'hz;
always @(negedge wr) begin
if(BHE==0)
- memory[address[15:1]][7:0]=data[15:8];
+ memory[address[16:1]][7:0]<=data[15:8];
if(address[0]==0)
- memory[address[15:1]][15:8]=data[7:0];
+ memory[address[16:1]][15:8]<=data[7:0];
end
endmodule
diff --git a/system/system.v b/system/system.v
new file mode 100644
index 0000000..ca74ad2
--- /dev/null
+++ b/system/system.v
@@ -0,0 +1,17 @@
+`define CPU_SPEED 1000
+
+module system ( input clock,input reset, output [19:0]address_bus, inout [15:0]data_bus,output BHE, output rd, output wr, output IOMEM, output HALT, output ERROR);
+processor p(clock,reset,address_bus,data_bus,rd,wr,BHE,IOMEM,HALT,ERROR);
+doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM);
+
+string memdump_name;
+always @(posedge HALT) begin
+// $display("Processor halted.\nCycles run for: %d",cycles);
+ if($value$plusargs("MEMDUMP=%s",memdump_name))begin
+ $writememh(memdump_name, sysmem.memory,0,32767);
+ end
+// #(`CPU_SPEED) //Just for the waveform
+ $finish;
+end
+
+endmodule
diff --git a/system/testbench.cpp b/system/testbench.cpp
new file mode 100644
index 0000000..e395a7c
--- /dev/null
+++ b/system/testbench.cpp
@@ -0,0 +1,33 @@
+#include "Vsystem.h"
+#include "verilated.h"
+#include "stdio.h"
+
+Vsystem *system_state;
+
+void tick() {
+ system_state->clock = 1;
+ system_state->eval();
+ system_state->clock = 0;
+ system_state->eval();
+ //printf("tick() %04x\n",system_state->address_bus);
+ //trace->dump(timestamp);
+ //timestamp += 500/MHz;
+}
+
+int main(int argc, char** argv) {
+ VerilatedContext* contextp = new VerilatedContext;
+ contextp->commandArgs(argc, argv);
+ system_state = new Vsystem{contextp};
+ system_state->reset=1;
+ tick();
+ system_state->reset=0;
+ tick();
+ system_state->reset=1;
+ while(!contextp->gotFinish()){
+ tick();
+ }
+ delete system_state;
+ delete contextp;
+ return 0;
+}
+
diff --git a/system/testbench.v b/system/testbench.v
index 1352180..37a77ac 100644
--- a/system/testbench.v
+++ b/system/testbench.v
@@ -25,18 +25,25 @@ reg reset;
reg clk_enable;
wire [19:0]address_bus;
wire [15:0]data_bus;
-wire rd,wr,romcs,HALT;
+wire rd,wr,HALT;
wire ERROR;
wire IOMEM;
-processor p(clock,reset,address_bus,data_bus,rd,wr,BHE,IOMEM,HALT,ERROR);
-doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM);
+system system( .clock(clock),
+ .reset(reset),
+ .address_bus(address_bus),
+ .data_bus(data_bus),
+ .rd(rd),
+ .wr(wr),
+ .HALT(HALT),
+ .ERROR(ERROR),
+ .IOMEM(IOMEM)
+);
`define CPU_SPEED 1000
clock_gen #(.FREQ(1000)) u1(clk_enable, clock);
-assign romcs=0;
integer cycles=0;
string memdump_name;
@@ -44,7 +51,7 @@ initial begin
string waveform_name;
if($value$plusargs("WAVEFORM=%s",waveform_name))begin
$dumpfile(waveform_name);
- $dumpvars(0,p,u1);
+ $dumpvars(0,system);
end
clk_enable = 1;
@@ -56,20 +63,12 @@ initial begin
reset = 1;
end
-always @(posedge HALT) begin
- $display("Processor halted.\nCycles run for: %d",cycles);
- if($value$plusargs("MEMDUMP=%s",memdump_name))begin
- $writememh(memdump_name, sysmem.memory,0,32767);
- end
- #(`CPU_SPEED) //Just for the waveform
- $finish;
-end
always @(posedge ERROR) begin
clk_enable <= 0;
$display("PROCESSOR RUN INTO AN ERROR.\nCycles run for: %d",cycles);
if($value$plusargs("MEMDUMP=%s",memdump_name))begin
- $writememh(memdump_name, sysmem.memory,0,32767);
+ $writememh(memdump_name, system.sysmem.memory,0,32767);
end
#(`CPU_SPEED) //Just for the waveform
$finish;
diff --git a/system/ucode.txt b/system/ucode.txt
index 40ae329..d5e1cdc 100644
--- a/system/ucode.txt
+++ b/system/ucode.txt
@@ -55,31 +55,31 @@
//
//Nxt M: Next microcode address
-@000 0000_000_000__00__00_0000__00_000000
+@000 _00_000_0000_000_0000_000_000__00__00_0000__00_000000
// 36 34 32 28 25 21 18 15 13 11 7 5 0
// CALL
// wbo|krs|rr2 |imd|rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M |
@001 _00_000_0000_011_1100_001_011__00__01_1100__01_000010 // ALU_1: SP ALU_2: PARAM2 (2) ALU_OP:SUB ALU_out: SP (also fetch the opcode argument to PARAM1)
-@002 _00_000_0000_011_zzzz_000_110__10__11_zzzz__00_000011 // ALU_1: 0 ALU_2: PC ALU_OP:ADD ALU_out: [SP]
-@003 _00_000_0000_011_zzzz_000_101__10__00_zzzz__00_000000 // ALU_1: PARAM1 (arg) ALU_2: PC ALU_OP:ADD ALU_out: PC
+@002 _00_000_0000_011_xxxx_000_110__10__11_xxxx__00_000011 // ALU_1: 0 ALU_2: PC ALU_OP:ADD ALU_out: [SP]
+@003 _00_000_0000_011_xxxx_000_101__10__00_xxxx__00_000000 // ALU_1: PARAM1 (arg) ALU_2: PC ALU_OP:ADD ALU_out: PC
// RET
// wbo|krs|rr2 |imd|rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M |
-@004 _00_000_0000_110_zzzz_000_101__00__11_zzzz__11_000101 // ALU_1: 0 ALU_2: PARAM2 ([SP]) ALU_OP:ADD ALU_out: PC (also read [SP] to PARAM2)
+@004 _00_000_0000_110_xxxx_000_101__00__11_xxxx__11_000101 // ALU_1: 0 ALU_2: PARAM2 ([SP]) ALU_OP:ADD ALU_out: PC (also read [SP] to PARAM2)
@005 _00_000_1100_011_0000_000_011__01__00_1100__00_000000 // ALU_1: PARAM1 (2) ALU_2: SP ALU_OP:ADD ALU_out: SP
// STOS
// wbo|krs|rr2 |imd|rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M |
-@006 _00_000_1000_011_zzzz_000_000__01__11_zzzz__00_000111 // ALU_1: 0 ALU_2: AX ALU_OP:ADD ALU_out: [DI]
-@007 _11_000_zzzz_011_1111_000_011__00__01_1111__00_000000 // ALU_1: DI ALU_2: PARAM2 (2) ALU_OP:ADD ALU_OUT: DI
+@006 _00_000_1000_011_xxxx_000_000__01__11_xxxx__00_000111 // ALU_1: 0 ALU_2: AX ALU_OP:ADD ALU_out: [DI]
+@007 _11_000_xxxx_011_1111_000_011__00__01_1111__00_000000 // ALU_1: DI ALU_2: PARAM2 (2) ALU_OP:ADD ALU_OUT: DI
// PUSH
// wbo|krs|rr2 |imd|rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M |
@008 _00_010_0000_011_1100_001_011__00__01_1100__00_001001 // ALU_1: SP ALU_2: PARAM2 (2) ALU_OP:SUB ALU_out: SP (also fetch the opcode argument to PARAM1)
-@009 _00_010_0000_011_zzzz_000_110__01__11_zzzz__00_000000 // ALU_1: 0 ALU_2: REG ALU_OP:ADD ALU_out: [SP]
+@009 _00_010_0000_011_xxxx_000_110__01__11_xxxx__00_000000 // ALU_1: 0 ALU_2: REG ALU_OP:ADD ALU_out: [SP]
// POP
// wbo|krs|rr2 |imd|rr1 |a1f|a1o|a12|a11|rwa |nxs|Nxt M |
-@00a _00_100_0000_110_zzzz_011_011__00__11_zzzz__11_001011 // ALU_1: 0 ALU_2: PARAM2 ([SP]) ALU_OP:ADD ALU_out: REG
+@00a _00_100_0000_110_xxxx_011_011__00__11_xxxx__11_001011 // ALU_1: 0 ALU_2: PARAM2 ([SP]) ALU_OP:ADD ALU_out: REG
@00b _00_000_1100_011_0000_000_011__01__00_1100__00_000000 // ALU_1: PARAM1 (2) ALU_2: SP ALU_OP:ADD ALU_out: SP