Added support for Verilator!
This commit is contained in:
parent
ba52ff89e6
commit
5705b8e8a5
5
.gitignore
vendored
5
.gitignore
vendored
@ -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/
|
||||
|
5
Makefile
5
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
|
||||
|
35
common.mk
35
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
|
||||
|
@ -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
|
||||
|
@ -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
17
system/system.v
Normal 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
33
system/testbench.cpp
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user