From 037f6dd7da4295c8339da12ccdbb9ef682a42b05 Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Tue, 14 Feb 2023 13:13:40 +0000 Subject: [PATCH] Added support for writing to memory --- .gitignore | 1 + cpu/Makefile | 2 + cpu/gtkwave_savefile.gtkw | 23 ++++--- cpu/memory.v | 8 ++- cpu/proc_state_def.v | 43 +++++++----- cpu/processor.v | 133 +++++++++++++++++++++++++++++--------- cpu/testbench.v | 6 +- 7 files changed, 155 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 6d90a58..fa117e2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ cpu/boot_code.txt cpu/brainfuck.bin cpu/brainfuck.txt cpu/memdump.txt +cpu/memdump.bin diff --git a/cpu/Makefile b/cpu/Makefile index 7021585..a82df3c 100644 --- a/cpu/Makefile +++ b/cpu/Makefile @@ -22,6 +22,7 @@ VVP=processor.vvp .PHONY: brainf brainf: ${VVP} brainfuck.txt vvp ${VVP} +BOOT_CODE=brainfuck.txt + grep -v '^//' memdump.txt | xxd -ps -c 2 -r > memdump.bin .PHONY: run run: ${VVP} boot_code.txt @@ -34,6 +35,7 @@ build: ${VVP} wave: ${VVP} brainfuck.txt vvp ${VVP} -lxt2 +BOOT_CODE=brainfuck.txt gtkwave test.lx2 gtkwave_savefile.gtkw + grep -v '^//' memdump.txt | xxd -ps -c 2 -r > memdump.bin ${VVP} : ${SOURCES} ${INCLUDES} iverilog -g2012 ${SOURCES} -o $@ diff --git a/cpu/gtkwave_savefile.gtkw b/cpu/gtkwave_savefile.gtkw index 121166e..b54c00f 100644 --- a/cpu/gtkwave_savefile.gtkw +++ b/cpu/gtkwave_savefile.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI -[*] Fri Feb 10 01:43:01 2023 +[*] Tue Feb 14 12:39:46 2023 [*] [dumpfile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/cpu/test.lx2" -[dumpfile_mtime] "Fri Feb 10 01:42:12 2023" -[dumpfile_size] 1058 +[dumpfile_mtime] "Tue Feb 14 12:37:32 2023" +[dumpfile_size] 1922 [savefile] "/home/user/UNI_DATA/COMS30046_2022_TB-2/projects/9086/cpu/gtkwave_savefile.gtkw" [timestart] 0 [size] 1438 1059 [pos] -1 -1 -*-21.795050 6163000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-23.795050 41712000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] tb. [treeopen] tb.p. [sst_width] 221 @@ -19,18 +19,17 @@ @28 tb.p.clock[0] tb.p.reset[0] -tb.p.state[3:0] +tb.p.state[4:0] @22 tb.p.external_address_bus[19:0] tb.p.external_data_bus[15:0] tb.p.CIR[15:0] -@28 -tb.p.EXCEPTION[0] -@22 -tb.p.ADDER16_1.A[15:0] -tb.p.ADDER16_1.B[15:0] -tb.p.ADDER16_1.OUT[15:0] +tb.p.PARAM1[15:0] +tb.p.PARAM2[15:0] @29 -tb.p.reg_write[0] +tb.p.read[0] +@28 +tb.p.write[0] +tb.p.ERROR[0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/cpu/memory.v b/cpu/memory.v index af18550..9f09108 100644 --- a/cpu/memory.v +++ b/cpu/memory.v @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -module rom(input [19:0] address,output wire [15:0] data ,input rd,input cs); +module mem(input [19:0] address,inout wire [15:0] data ,input rd,input wr,input cs); reg [15:0] memory [0:599]; initial begin string boot_code; @@ -25,5 +25,11 @@ initial begin boot_code="boot_code.txt"; $readmemh(boot_code, memory); end + assign data = !rd & !cs ? memory[address]: 'hz; + +always @(negedge wr) begin + memory[address]=data; +end + endmodule diff --git a/cpu/proc_state_def.v b/cpu/proc_state_def.v index e21418a..5572fa5 100644 --- a/cpu/proc_state_def.v +++ b/cpu/proc_state_def.v @@ -18,26 +18,39 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -`define PROC_HALT_STATE 4'b0000 +`define PROC_STATE_BITS 5 + + +`define PROC_HALT_STATE 5'b00000 /*INSTRUCTION FETCH STATE*/ -`define PROC_IF_STATE_ENTRY 4'b0001 -`define PROC_IF_WRITE_CIR 4'b0010 -`define PROC_IF_STATE_EXTRA_FETCH_SET 4'b0011 -`define PROC_IF_STATE_EXTRA_FETCH 4'b1111 /******/ +`define PROC_IF_STATE_ENTRY 5'b00001 +`define PROC_IF_WRITE_CIR 5'b00010 +`define PROC_IF_STATE_EXTRA_FETCH_SET 5'b00011 +`define PROC_IF_STATE_EXTRA_FETCH 5'b00100 /*DECODE SATE*/ -`define PROC_DE_STATE_ENTRY 4'b0100 -`define PROC_DE_LOAD_16_PARAM 4'b0101 -`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 4'b0110 -`define PROC_DE_LOAD_16_EXTRA_FETCH 4'b0111 +`define PROC_DE_STATE_ENTRY 5'b01000 +`define PROC_DE_LOAD_16_PARAM 5'b01001 +`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 5'b01010 +`define PROC_DE_LOAD_16_EXTRA_FETCH 5'b01011 /*MEM/IO READ*/ -`define RPOC_MEMIO_READ 4'b1100 -`define PROC_MEMIO_SETADDR 4'b1101 -`define PROC_MEMIO_GET_ALIGNED_DATA 4'b1110 /* :) */ -`define PROC_MEMIO_GET_UNALIGNED_DATA 4'b1010 /* :( */ +`define RPOC_MEMIO_READ 5'b10000 +`define PROC_MEMIO_READ_SETADDR 5'b10001 +`define PROC_MEMIO_GET_ALIGNED_DATA 5'b10010 /* :) */ +`define PROC_MEMIO_GET_UNALIGNED_DATA 5'b10011 /* :( */ /*EXECUTE STATE*/ -`define PROC_EX_STATE_ENTRY 4'b1000 -`define PROC_EX_STATE_EXIT 4'b1001 +`define PROC_EX_STATE_ENTRY 5'b11000 +`define PROC_EX_STATE_EXIT 5'b11001 + +/*MEM/IO WRITE*/ +`define PROC_MEMIO_WRITE 5'b10100 +//`define PROC_MEMIO_WRITE_SETADDR 5'b10101 +`define PROC_MEMIO_PUT_ALIGNED_DATA 5'b10101 +`define PROC_MEMIO_PUT_UNALIGNED_DATA 5'b10110 +`define PROC_MEMIO_PUT_BYTE 5'b10111 +`define PROC_MEMIO_PUT_BYTE_STOP_READ 5'b11110 /****/ +`define PROC_MEMIO_PUT_BYTE_WRITE 5'b11111 /****/ + diff --git a/cpu/processor.v b/cpu/processor.v index cfda752..0268145 100644 --- a/cpu/processor.v +++ b/cpu/processor.v @@ -34,9 +34,13 @@ endmodule module processor ( input clock, input reset, output reg [19:0] external_address_bus, inout [15:0] external_data_bus,output reg read, output reg write, output reg HALT,output reg ERROR); +/*if we don't read, output the register to have the bus stable by the write falling edge*/ +reg [15:0] data_bus_output_register; +assign external_data_bus=read?data_bus_output_register:'hz; + /*** Global Definitions ***/ // State -reg [3:0] state; +reg [`PROC_STATE_BITS-1:0] state; // Registers reg [19:0] ProgCount; @@ -44,8 +48,8 @@ reg [15:0] CIR; reg [15:0] PARAM1; reg [15:0] PARAM2; reg unaligned_access; -reg [1:0]IN_MOD; -reg [2:0]IN_RM; +reg [1:0]MOD; +reg [2:0]RM; reg Wbit; reg [15:0]FLAGS; /* . . . . O D I T S Z . A . P . C */ @@ -69,6 +73,7 @@ reg [15:0]FLAGS; // D - Direction flag : 1: string instructions decrement 0: they increment // // O - Overflow flag : set on arithmetic overflow +reg [15:0] BYTE_WRITE_TEMP_REG;//we read 16bits here if we want to change just 8 and leave the rest // Execution units @@ -91,7 +96,7 @@ always @(negedge reset) begin @(posedge reset) @(negedge clock); state=`PROC_IF_STATE_ENTRY; - IN_MOD=2'b11; + MOD=2'b11; ERROR=0; end end @@ -134,7 +139,7 @@ ALU ALU(ALU_1A,ALU_1B,ALU_1OE,ALU_1O,ALU_1OP,ALU_FLAGS,Wbit); /*** Processor stages ***/ -`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;IN_MOD=2'b11; +`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;MOD=2'b11; `define start_aligning_instruction if(unaligned_access==0)begin ProgCount=ProgCount+1; external_address_bus <= ProgCount; end /*we normally don't advance PC in case of singly byte unaligning instructions leaving us with two instructions in one read so do that here*/ `define start_unaligning_instruction unaligned_access=~unaligned_access; @@ -156,6 +161,50 @@ always @(negedge clock) begin end `PROC_EX_STATE_EXIT:begin case(out_sel) + 3'b000, + 3'b001, + 3'b010 : begin + case (RM) /* Duplicate code with write... */ + 3'b000:begin + /*[BX]+[SI]*/ + `invalid_instruction + end + 3'b001:begin + /*[BX]+[SI]*/ + `invalid_instruction + end + 3'b010:begin + /*[BP]+[SI]*/ + `invalid_instruction + end + 3'b011:begin + /*[BP]+[DI]*/ + `invalid_instruction + end + 3'b100:begin + /*[SI]*/ + reg_read_addr=4'b1110; + reg_read_oe=0; + state=`PROC_MEMIO_WRITE; + end + 3'b101:begin + /*[DI]*/ + reg_read_addr=4'b1111; + reg_read_oe=0; + state=`PROC_MEMIO_WRITE; + end + 3'b110:begin + /*d16 */ + `invalid_instruction + end + 3'b111:begin + /*[BX]*/ + reg_read_addr=4'b1011; + reg_read_oe=0; + state=`PROC_MEMIO_WRITE; + end + endcase + end 3'b011:begin reg_write_we=0; state=`PROC_IF_STATE_ENTRY; @@ -177,10 +226,18 @@ always @(negedge clock) begin external_address_bus = ProgCount; state=`PROC_DE_LOAD_16_EXTRA_FETCH; end - `PROC_MEMIO_SETADDR:begin + `PROC_MEMIO_READ_SETADDR:begin external_address_bus = {1'b0,reg_read_data[15:1]}; state=reg_read_data[0:0]?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA; end + `PROC_MEMIO_PUT_BYTE:begin + BYTE_WRITE_TEMP_REG=external_data_bus; + state=`PROC_MEMIO_PUT_BYTE_STOP_READ; + end + `PROC_MEMIO_PUT_BYTE_WRITE:begin + write=0; + state=`PROC_IF_STATE_ENTRY; + end endcase end @@ -225,7 +282,7 @@ always @(posedge clock) begin `start_unaligning_instruction else `start_aligning_instruction - IN_MOD=2'b11; + MOD=2'b11; in1_sel=2'b00; in2_sel=2'b01; out_sel=3'b011; @@ -252,7 +309,7 @@ always @(posedge clock) begin /* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */ `start_aligning_instruction Wbit=CIR[8:8]; - IN_MOD=2'b11; + MOD=2'b11; in1_sel=2'b00; in2_sel=2'b01; out_sel={1'b0,CIR[7:6]}; @@ -282,7 +339,7 @@ always @(posedge clock) begin `start_unaligning_instruction else `start_aligning_instruction - IN_MOD=2'b11; + MOD=2'b11; in1_sel=2'b00; in2_sel=2'b00; out_sel=3'b011; @@ -301,7 +358,7 @@ always @(posedge clock) begin `start_unaligning_instruction else `start_aligning_instruction - IN_MOD=2'b11; + MOD=2'b11; in1_sel=2'b00; in2_sel=2'b00; out_sel=3'b011; @@ -316,13 +373,13 @@ always @(posedge clock) begin /* MOV - Reg/Mem to/from register */ /* 1 0 0 0 1 0 D W | MOD REG REG | < DISP LO > | < DISP HI > |*/ `start_aligning_instruction - IN_MOD=CIR[7:6]; - IN_RM=CIR[2:0]; + MOD=CIR[7:6]; + RM=CIR[2:0]; Wbit=CIR[8:8]; if(CIR[9:9] == 1)begin /* to reg */ - IN_MOD=CIR[7:6]; - if(IN_MOD==2'b11)begin + MOD=CIR[7:6]; + if(MOD==2'b11)begin in1_sel=2'b01; reg_read_addr=CIR[2:0]; end else begin @@ -339,7 +396,7 @@ always @(posedge clock) begin ALU_1OP=`ALU_OP_ADD; PARAM2=0; state=`PROC_DE_LOAD_16_PARAM; - if ( IN_MOD == 2'b11 ) + if ( MOD == 2'b11 ) state=`PROC_EX_STATE_ENTRY; else state=`RPOC_MEMIO_READ; @@ -357,7 +414,7 @@ always @(posedge clock) begin in1_sel=2'b01; in2_sel=2'b00; out_sel=3'b011; - IN_MOD=2'b11; + MOD=2'b11; PARAM2=1; reg_read_addr={1'b1,CIR[10:8]}; reg_write_addr={1'b1,CIR[10:8]}; @@ -378,14 +435,18 @@ always @(posedge clock) begin /* 1 1 1 1 1 1 1 W | MOD 0 0 0 R/M | < DISP LO> | < DISP HI> */ `start_aligning_instruction Wbit=CIR[8:8]; - IN_MOD=CIR[7:6]; - in1_sel=2'b00;/* number 1 */ - in2_sel=(CIR[7:6]==2'b11)? 2'b01 : 2'b00; - out_sel={1'b0,CIR[7:6]}; - PARAM1=1; - reg_read_addr={1'b0,CIR[2:0]}; - reg_write_addr={1'b0,CIR[2:0]}; + MOD=CIR[7:6]; + RM=CIR[2:0]; + in1_sel=(MOD==2'b11)? 2'b01 : 2'b00; + in2_sel=2'b00;/* number 1 */ + out_sel={1'b0,MOD}; + PARAM2=1; + + /*in case MOD=11 */ + reg_read_addr={1'b0,RM}; + reg_write_addr={1'b0,RM}; reg_read_oe=0; + ALU_1OE=0; ALU_1OP=`ALU_OP_ADD; if ( CIR[7:6] == 2'b11 ) @@ -408,7 +469,7 @@ always @(posedge clock) begin /* HLT - Halt */ /* 1 1 1 1 0 1 0 0 | */ `start_unaligning_instruction - IN_MOD=2'b11; + MOD=2'b11; HALT=1; state=`PROC_HALT_STATE; end @@ -430,7 +491,7 @@ always @(posedge clock) begin `start_unaligning_instruction else `start_aligning_instruction - IN_MOD=2'b11; + MOD=2'b11; in1_sel=2'b00; in2_sel=2'b01; reg_read_addr={CIR[8:8],3'b000}; @@ -530,7 +591,7 @@ always @(posedge clock) begin end `RPOC_MEMIO_READ:begin /*Decode MOD R/M, read the data and place it to PARAM1*/ - case (IN_RM) + case (RM) 3'b000:begin /*[BX]+[SI]*/ `invalid_instruction @@ -551,13 +612,13 @@ always @(posedge clock) begin /*[SI]*/ reg_read_addr=4'b1110; reg_read_oe=0; - state=`PROC_MEMIO_SETADDR; + state=`PROC_MEMIO_READ_SETADDR; end 3'b101:begin /*[DI]*/ reg_read_addr=4'b1111; reg_read_oe=0; - state=`PROC_MEMIO_SETADDR; + state=`PROC_MEMIO_READ_SETADDR; end 3'b110:begin /*d16 */ @@ -567,10 +628,10 @@ always @(posedge clock) begin /*[BX]*/ reg_read_addr=4'b1011; reg_read_oe=0; - state=`PROC_MEMIO_SETADDR; + state=`PROC_MEMIO_READ_SETADDR; end endcase - if(IN_MOD!=2'b00)begin + if(MOD!=2'b00)begin /*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/ `invalid_instruction; end @@ -593,6 +654,18 @@ always @(posedge clock) begin FLAGS[7:0] = ALU_FLAGS[7:0]; state=`PROC_EX_STATE_EXIT; end + `PROC_MEMIO_WRITE:begin + external_address_bus = {1'b0,reg_read_data[15:1]}; + state = (Wbit==0) ? `PROC_MEMIO_PUT_BYTE : (reg_read_data[0:0]?`PROC_MEMIO_PUT_UNALIGNED_DATA:`PROC_MEMIO_PUT_ALIGNED_DATA) ; + end + `PROC_MEMIO_PUT_BYTE_STOP_READ:begin + read=1; + state=`PROC_MEMIO_PUT_BYTE_WRITE; + if(reg_read_data[0:0]==0) + data_bus_output_register={ALU_1O[7:0],BYTE_WRITE_TEMP_REG[7:0]}; + else + data_bus_output_register={BYTE_WRITE_TEMP_REG[15:8],ALU_1O[7:0]}; + end endcase end diff --git a/cpu/testbench.v b/cpu/testbench.v index 098e175..508f0e0 100644 --- a/cpu/testbench.v +++ b/cpu/testbench.v @@ -29,7 +29,7 @@ wire rd,wr,romcs,HALT; wire ERROR; processor p(clock,reset,address_bus,data_bus,rd,wr,HALT,ERROR); -rom bootrom(address_bus,data_bus,rd,romcs); +mem sysmem(address_bus,data_bus,rd,wr,romcs); `define CPU_SPEED 1000 @@ -51,7 +51,7 @@ end always @(posedge HALT) begin $display("Processor halted.\nCycles run for: %d",cycles); - $writememh("memdump.txt", bootrom.memory); + $writememh("memdump.txt", sysmem.memory); #(`CPU_SPEED) //Just for the waveform $finish; end @@ -59,7 +59,7 @@ end always @(posedge ERROR) begin clk_enable <= 0; $display("PROCESSOR RUN INTO AN ERROR.\nCycles run for: %d",cycles); - $writememh("memdump.txt", bootrom.memory); + $writememh("memdump.txt", sysmem.memory); #(`CPU_SPEED) //Just for the waveform $finish; end