Added support for writing to memory

This commit is contained in:
(Tim) Efthimis Kritikos 2023-02-14 13:13:40 +00:00
parent 7c1067088c
commit 037f6dd7da
7 changed files with 155 additions and 61 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ cpu/boot_code.txt
cpu/brainfuck.bin
cpu/brainfuck.txt
cpu/memdump.txt
cpu/memdump.bin

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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