Added support for Verilator!

This commit is contained in:
(Tim) Efthimis Kritikos 2023-03-04 08:37:43 +00:00
parent ba52ff89e6
commit 5705b8e8a5
9 changed files with 129 additions and 39 deletions

5
.gitignore vendored
View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -15,9 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
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

View File

@ -17,8 +17,13 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
// 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

17
system/system.v Normal file
View File

@ -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

33
system/testbench.cpp Normal file
View File

@ -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;
}

View File

@ -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;

View File

@ -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