diff --git a/examples/mf8/MF8A18.v b/examples/mf8/MF8A18.v new file mode 100644 index 00000000..753612d4 --- /dev/null +++ b/examples/mf8/MF8A18.v @@ -0,0 +1,115 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + +module MF8A18 ( + CLK, + RST, + rom_addr, + rom_data, + maddr, + mwdata, + ramdata, + mwrite, + mread, + SPI_MISO, + SPI_MOSI, + SPI_SCK, + SPI_CS, + UART_TXD); + + +input CLK; +input RST; +output [9:0] rom_addr; +input [15:0] rom_data; +output [15:0] maddr; +output [7:0] mwdata; +input [7:0] ramdata; +output mwrite; +output mread; +input SPI_MISO; +output SPI_MOSI; +output SPI_SCK; +output SPI_CS; +output UART_TXD; + + +// +wire [9:0] rom_addr; +wire [15:0] maddr; +wire [7:0] mwdata; +wire mwrite; +wire mread; +reg SPI_MOSI; +reg SPI_SCK; +reg SPI_CS; +reg UART_TXD; +reg Reset_s; +wire Reset_s_i; +wire IO_Rd; +wire IO_Wr; +wire [5:0] IO_Addr; +wire [7:0] IO_WData; +wire [7:0] IO_RData; + +wire [15:0] Z; +wire [7:0] ram_datain; +wire ram_write; + +wire [15:0] maddr_i; +wire [15:0] maddr_s; +wire mread_i; +wire mwrite_i; + +assign maddr = maddr_i; +assign mread = mread_i; +assign mwrite = mwrite_i; + +always @(posedge CLK) +begin : process_1 + Reset_s <= RST; +end + +always @(posedge CLK) +begin : process_2 + if (Reset_s === 1'b 1) + begin + UART_TXD <= 1'b 1; + SPI_CS <= 1'b 1; + SPI_SCK <= 1'b 1; + SPI_MOSI <= 1'b 1; + end else + begin + if (IO_Wr === 1'b 1) + begin + if (IO_Addr[4:3] === 2'b 00) begin UART_TXD <= IO_WData[0]; end // 00 xxxxx 0x20 + if (IO_Addr[4:3] === 2'b 01) begin SPI_CS <= IO_WData[7]; end // 01 xxxx 0x10 + if (IO_Addr[4:3] === 2'b 10) begin SPI_SCK <= IO_WData[0]; end // 11 xxxx 0x20 + if (IO_Addr[4:3] === 2'b 11) begin SPI_MOSI <= IO_WData[7]; end // 10 xxxx 0x30 + end + end + end + +assign mwdata = IO_WData; + +mf8_core core ( + .Clk (CLK), + .Reset (Reset_s), + .ROM_Addr (rom_addr[9:0]), + .ROM_Data (rom_data), + .ZZ (maddr_i), + .ram_datain (ramdata), + .ram_write (mwrite_i), + .ram_read (mread_i), + .IO_Rd (IO_Rd), + .IO_Wr (IO_Wr), + .IO_Addr (IO_Addr), + .IO_RData (IO_RData), + .IO_WData (IO_WData) +); + +assign IO_RData = {7'b 0000000, SPI_MISO}; + +endmodule // diff --git a/examples/mf8/MF8A18_SoC.v b/examples/mf8/MF8A18_SoC.v new file mode 100644 index 00000000..b452d296 --- /dev/null +++ b/examples/mf8/MF8A18_SoC.v @@ -0,0 +1,65 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + + +module MF8A18_SoC ( + clk, + reset, + FLASH_SCK, + FLASH_CS, + FLASH_MISO, + FLASH_MOSI, + UART_TXD + ); + + output FLASH_SCK; + output FLASH_CS; + input FLASH_MISO; + output FLASH_MOSI; + + input clk; + input reset; + output UART_TXD; + + wire [9:0] rom_addr; + wire [15:0] rom_data; + + wire [15:0] maddr; + wire [7:0] mwdata; + wire [7:0] mrdata; + wire mwrite; + + MF8A18 cpu ( + .CLK (clk), + .RST (reset), + .SPI_CS (FLASH_CS), + .SPI_MISO (FLASH_MISO), + .SPI_MOSI (FLASH_MOSI), + .SPI_SCK (FLASH_SCK), + .UART_TXD (UART_TXD), + .maddr (maddr), + .mread (), + .mwdata (mwdata), + .mwrite (mwrite), + .ramdata (mrdata), + .rom_addr (rom_addr), + .rom_data (rom_data) + ); + + ROM1K16 rom ( + .addr (rom_addr), + .clk (clk), + .dout (rom_data) + ); + + RAM32K ram ( + .addr (maddr[14:0]), + .clk (clk), + .din (mwdata), + .dout (mrdata), + .we (mwrite) + ); + +endmodule \ No newline at end of file diff --git a/examples/mf8/RAM32K.v b/examples/mf8/RAM32K.v new file mode 100644 index 00000000..c17bd43e --- /dev/null +++ b/examples/mf8/RAM32K.v @@ -0,0 +1,51 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + +module RAM32K (clk, addr, din, dout, we); + +input clk; +input we; +input [14:0] addr; +input [7:0] din; +output [7:0] dout; + +// RAM +`ifdef SIM + +reg [7:0] mem [0:32*1024-1]; +reg [7:0] dout; +initial $readmemh("riscv.mem", mem); + +always @(posedge clk) begin + if (we) mem[addr] <= din; + dout <= mem[addr]; +end + +`else + +// SBRAM +wire [15:0] SBRAM_Dataout; +reg DelayOdd; +always @(posedge clk) begin + DelayOdd <= addr[0]; +end +assign dout = DelayOdd? SBRAM_Dataout[15:8] : SBRAM_Dataout[7:0]; + +SB_SPRAM256KA ram ( + .ADDRESS(addr[14:1]), + .DATAIN({din, din}), + .MASKWREN({addr[0], addr[0], ~addr[0], ~addr[0]}), + .WREN(we), + .CHIPSELECT(1'b1), + .CLOCK(clk), + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1), + .DATAOUT(SBRAM_Dataout) +); + +`endif + +endmodule \ No newline at end of file diff --git a/examples/mf8/ROM1K16.v b/examples/mf8/ROM1K16.v new file mode 100644 index 00000000..36a184ce --- /dev/null +++ b/examples/mf8/ROM1K16.v @@ -0,0 +1,20 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + +module ROM1K16 (clk, addr, dout); + +input clk; +input [8:0] addr; +output [15:0] dout; + +// ROM with a single synchronous read port (can be mapped to Block RAM) +reg [15:0] mem [0:511]; +reg [15:0] dout; +initial $readmemh("rv32i.mem", mem); +always @(posedge clk) begin + dout <= mem[addr]; +end + +endmodule \ No newline at end of file diff --git a/examples/mf8/addsub8.v b/examples/mf8/addsub8.v new file mode 100644 index 00000000..c1d83f97 --- /dev/null +++ b/examples/mf8/addsub8.v @@ -0,0 +1,42 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + + +module addsub8 ( + a, + b, + q, + sub, + cin, + cout +); + + +input [7:0] a; +input [7:0] b; +output [7:0] q; +input sub; +input cin; +output cout; + +wire [7:0] q; +wire cout; +wire [8:0] A_i; +wire [8:0] B_i; +wire [8:0] Full_Carry; +wire [8:0] Res_i; + +assign B_i[8] = 1'b 0; +assign B_i[7:0] = sub === 1'b 1 ? ~b : b; +assign A_i[8] = 1'b 0; +assign A_i[7:0] = a; +assign Full_Carry[8:1] = 8'b 00000000; +assign Full_Carry[0] = cin; +assign Res_i = A_i + B_i + Full_Carry; +assign cout = Res_i[8]; +assign q = Res_i[7:0]; + +endmodule // module addsub8 + diff --git a/examples/mf8/mf8_alu.v b/examples/mf8/mf8_alu.v new file mode 100644 index 00000000..9c142031 --- /dev/null +++ b/examples/mf8/mf8_alu.v @@ -0,0 +1,147 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + + +module mf8_alu ( + Clk, + ROM_Data, + ROM_Pattern, + A, + B, + Q, + SREG, + PassB, + Skip, + Do_Other, + Z_Skip, + Status_D, + Status_Wr +); + + +input Clk; +input [15:0] ROM_Data; +input [7:0] ROM_Pattern; +input [7:0] A; +input [7:0] B; +output [7:0] Q; +input [7:0] SREG; +input PassB; +input Skip; +output Do_Other; +output Z_Skip; +output [6:0] Status_D; +output [6:0] Status_Wr; + +wire [7:0] Q; +wire Do_Other; +wire Z_Skip; +wire [6:0] Status_D; +reg [6:0] Status_Wr; + +reg Do_ADD; +reg Do_SUB; +reg Do_AND; +reg Do_OR; +reg Do_XOR; +reg Do_SWAP; +reg Do_ROR; +reg Do_ASR; +reg Do_LSR; +reg Do_PASSB; +reg Do_SBRC; +reg Do_SBRS; +reg Use_Carry; +wire [7:0] Bit_Pattern; +wire [7:0] Bit_Test; +wire [7:0] Q_i; +wire [7:0] Q_L; +wire [7:0] Q_S; +wire [7:0] Q_R; +wire [7:0] Q_B; + +wire Carry7_v; +wire Carry_in; +wire Carry_v; +wire [7:0] Q_v; +wire [7:0] AAS; +wire [7:0] BAS; + +assign Q = Q_i; +assign Do_Other = Do_PASSB; +assign Q_i = Do_ADD === 1'b 1 | Do_SUB === 1'b 1 ? Q_v : Do_AND === 1'b 1 | Do_OR === 1'b 1 | Do_XOR === 1'b 1 ? Q_L : Do_SWAP === 1'b 1 ? Q_S : Q_R; + +always @(posedge Clk) +begin : process_1 + Do_SUB <= 1'b 0; + Do_ADD <= 1'b 0; + Use_Carry <= 1'b 0; + Do_AND <= 1'b 0; + Do_XOR <= 1'b 0; + Do_OR <= 1'b 0; + Do_SWAP <= 1'b 0; + Do_ASR <= 1'b 0; + Do_LSR <= 1'b 0; + Do_ROR <= 1'b 0; + Do_PASSB <= 1'b 0; + Do_SBRC <= 1'b 0; + Do_SBRS <= 1'b 0; + if (PassB === 1'b 0) + begin + if (Skip === 1'b 0) + begin + if (ROM_Data[15:10] === 6'b 000110 | ROM_Data[15:12] === 4'b 0101 | ROM_Data[15:10] === 6'b 000010) begin Do_SUB <= 1'b 1; end + if (ROM_Data[15:10] === 6'b 000011 | ROM_Data[15:10] === 6'b 000111) begin Do_ADD <= 1'b 1; end // ADD, ADC + if (ROM_Data[15:10] === 6'b 000010 | ROM_Data[15:10] === 6'b 000111) begin Use_Carry <= 1'b 1; end // SBC, ADC + if (ROM_Data[15:10] === 6'b 001000 | ROM_Data[15:12] === 4'b 0111) begin Do_AND <= 1'b 1; end // AND, ANDI + if (ROM_Data[15:10] === 6'b 001001) begin Do_XOR <= 1'b 1; end // XOR + if (ROM_Data[15:10] === 6'b 001010 | ROM_Data[15:12] === 4'b 0110) begin Do_OR <= 1'b 1; end // OR, ORI + if (ROM_Data[15: 9] === 7'b 1001010 & ROM_Data[ 3: 0] === 4'b 0010) begin Do_SWAP <= 1'b 1; end // SWAP + if (ROM_Data[15: 9] === 7'b 1001010 & ROM_Data[ 3: 0] === 4'b 0101) begin Do_ASR <= 1'b 1; end // ASR + if (ROM_Data[15: 9] === 7'b 1001010 & ROM_Data[ 3: 0] === 4'b 0110) begin Do_LSR <= 1'b 1; end // LSR + if (ROM_Data[15: 9] === 7'b 1001010 & ROM_Data[ 3: 0] === 4'b 0111) begin Do_ROR <= 1'b 1; end // ROR + if (ROM_Data[15:10] === 6'b 001011 | ROM_Data[15:12] === 4'b 1011 | ROM_Data[15:12] === 4'b 1110) begin Do_PASSB <= 1'b 1; end // MOV, IN/OUT, LDI + + if (ROM_Data[15:9] === 7'b 1111110) begin Do_SBRC <= 1'b 1; end else begin Do_SBRC <= 1'b 0; end + if (ROM_Data[15:9] === 7'b 1111111) begin Do_SBRS <= 1'b 1; end else begin Do_SBRS <= 1'b 0; end + end + end else + begin + Do_PASSB <= 1'b 1; + end +end + +assign Bit_Pattern = ROM_Pattern; +assign Bit_Test = Bit_Pattern & A; +assign Z_Skip = Bit_Test !== 8'b 00000000 & Do_SBRS === 1'b 1 | Bit_Test === 8'b 00000000 & Do_SBRC === 1'b 1 ? 1'b 1 : 1'b 0; +assign Carry_in = Do_SUB ^ Use_Carry & SREG[0]; + +addsub8 addsub_inst ( + .a (A[7:0]), + .b (B[7:0]), + .q (Q_v[7:0]), + .sub (Do_SUB), + .cin (Carry_in), + .cout (Carry_v) +); + +assign Q_L = Do_AND === 1'b 1 ? A & B : Do_OR === 1'b 1 ? A | B : A ^ B; +assign Q_S = {A[3:0], A[7:4]}; +assign Q_R[6:0] = A[7:1]; +assign Q_R[7] = A[7] & Do_ASR | SREG[0] & Do_ROR; + + +assign Status_D[1] = Q_i[7:0] === 8'b 00000000 & (Do_SUB === 1'b 0 | Use_Carry === 1'b 0) ? 1'b 1 : Q_i[7:0] === 8'b 00000000 & Do_SUB === 1'b 1 & Use_Carry === 1'b 1 ? SREG[1] : 1'b 0; +assign Status_D[0] = (Carry_v ^ Do_SUB) & (Do_ADD | Do_SUB) | A[0] & (Do_ASR | Do_LSR | Do_ROR); + + +always @(Do_SUB or Do_ADD or Do_ASR or Do_LSR or Do_ROR or Do_AND or Do_XOR or Do_OR) +begin : process_2 + Status_Wr = 7'b 0000000; + if ((Do_ASR | Do_LSR | Do_ROR | Do_SUB | Do_ADD | Do_AND | Do_XOR | Do_OR ) === 1'b 1) begin Status_Wr = 7'b 0000011; end +end + +endmodule // module mf8_alu + diff --git a/examples/mf8/mf8_core.v b/examples/mf8/mf8_core.v new file mode 100644 index 00000000..ad7cc71f --- /dev/null +++ b/examples/mf8/mf8_core.v @@ -0,0 +1,346 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + + +module mf8_core ( + Clk, + Reset, + ROM_Addr, + ROM_Data, + ZZ, + ram_datain, + ram_write, + ram_read, + ram_ready, + IO_Rd, + IO_Wr, + IO_Addr, + IO_RData, + IO_WData); + +input ram_ready; + +input Clk; +input Reset; +output [9:0] ROM_Addr; +input [15:0] ROM_Data; +output [15:0] ZZ; +input [7:0] ram_datain; +output ram_write; +output ram_read; +output IO_Rd; +output IO_Wr; +output [5:0] IO_Addr; +input [7:0] IO_RData; +output [7:0] IO_WData; + +wire [9:0] ROM_Addr; + +wire [15:0] ZZ; +wire ram_write; +wire ram_read; +wire IO_Rd; +wire IO_Wr; +wire [5:0] IO_Addr; +wire [7:0] IO_WData; + +// Registers +reg [7:0] SREG_i; +wire [15:0] SP_i; +wire [11:0] NPC; +wire [11:0] PC; +wire [7:0] PCH; +wire [15:0] Z; + +// ALU signals +wire Do_Other; +wire [7:0] Pass_Mux; +wire [7:0] Op_Mux; +wire [6:0] Status_D; +wire [4:0] Status_D_R; +wire [6:0] Status_Wr; +wire Status_D_Wr; + +// Misc signals +reg [15:0] Rd_Addr; +reg [15:0] Rr_Addr; +reg [5:0] IO_Addr_i; +wire [7:0] Wr_Data; +wire [7:0] Rd_Data; +wire [7:0] Rr_Data; +wire [7:0] RAM_Data; +wire [11:0] Offset; +wire [11:0] Offset_small; +wire [7:0] Q; +wire [5:0] Disp; +reg [7:0] Bit_Pattern; + +reg [15:0] Inst; +wire [15:0] N_Inst; + +// Control signals +reg Rst_r; +reg RAM_IR; +reg RAM_IW; +reg Reg_IW; +wire Reg_Wr; +reg Reg_Rd; +reg RAM_Rd; +wire PMH_Rd; +wire PML_Rd; +reg Reg_Wr_ID; +reg RAM_Wr_ID; +wire PassB; +reg IO_Rd_i; +reg IO_Wr_i; +wire Z_Skip; +wire [1:0] Pause; +reg [1:0] DidPause; +wire PCPause; +wire Inst_Skip; +wire PreDecode; +reg Imm_Op; + +wire RJmp; +wire CBranch; +wire IO_BMbitd; +wire IO_BMbit; + +assign ZZ[15:2] = Z[15:2]; +// This is the TRICK to compress microcode with price of 2 LUT +assign ZZ[0] = Z[0] ^ Inst[0]; +assign ZZ[1] = Z[1] ^ Inst[1]; + + +assign RAM_Data = ram_datain; +assign ram_write = RAM_IW; +assign ram_read = RAM_Rd; + +assign PreDecode = Rst_r === 1'b 0 & Inst_Skip === 1'b 0 & (Pause === 2'b 00 | DidPause === 2'b 01) ? 1'b 1 : 1'b 0; + +assign Disp = {Inst[13], Inst[11:10], Inst[2:0]}; + +assign Reg_Wr = + Inst[15:12] === 4'b 0010 | + Inst[15:14] === 2'b 01 | + Inst[15:11] === 5'b 00001 | + Inst[15:11] === 5'b 00011 | + Inst[15:12] === 4'b 1110 | + Inst[15: 9] === 7'b 1001010 & Inst[ 3: 1] !== 3'b 100 | + Inst[15:11] === 5'b 10110 | + Reg_Wr_ID === 1'b 1 ? 1'b 1 : 1'b 0; + +always @(posedge Clk) +begin : process_1 + Reg_Wr_ID <= Reg_IW; + RAM_Wr_ID <= RAM_IW; +end + + +always @(ROM_Data or Inst or DidPause or Pause or Z or Disp) +begin : process_2 + Rd_Addr = {16{1'b x}}; + Rr_Addr = {16{1'b x}}; + Rd_Addr[4:0] = ROM_Data[8:4]; + Rr_Addr[4:0] = {ROM_Data[9], ROM_Data[3:0]}; + if (ROM_Data[15:12] === 4'b 0011 | ROM_Data[15:14] === 2'b 01 | ROM_Data[15:12] === 4'b 1110) + begin + Rd_Addr[4] = 1'b 1; + end + if (DidPause === 2'b 00 & Pause === 2'b 01) + begin + if (Inst[15:9] === 7'b 1000000) + begin + Rd_Addr[4:0] = Inst[8:4]; + end + if (Inst[15:9] === 7'b 1000001) + begin + Rr_Addr[4:0] = Inst[8:4]; + end + end +end + + +always @(Inst or DidPause or Rd_Addr or Rr_Addr or Z) + begin : process_3 + RAM_IR = 1'b 0; + Reg_IW = 1'b 0; + RAM_IW = 1'b 0; + if (DidPause === 2'b 00 & Inst[15:10] === 6'b 100000) + begin + if (Inst[9] === 1'b 0) + begin + RAM_IR = 1'b 1; + Reg_IW = 1'b 1; + end + else + begin + RAM_IW = 1'b 1; + end + end + end + +assign IO_Addr = IO_Addr_i; +assign IO_Rd = IO_Rd_i; +assign IO_Wr = IO_Wr_i; + +assign IO_WData = Rd_Data; + +always @(posedge Clk) + begin : process_4 + if (Reset === 1'b 1) + begin + IO_Addr_i <= {6{1'b 0}}; + IO_Wr_i <= 1'b 0; + end + else + begin + if (Inst[15:11] === 5'b 10011 & Inst[8] === 1'b 0 & + DidPause[0] === 1'b 0 | ROM_Data[15:11] === 5'b 10111 & + PreDecode === 1'b 1) + begin + IO_Wr_i <= 1'b 1; + end + else + begin + IO_Wr_i <= 1'b 0; + end + if (Inst[15:10] !== 6'b 100110 | DidPause[0] === 1'b 1) + begin + if (ROM_Data[13] === 1'b 0) + begin + IO_Addr_i <= {1'b 0, ROM_Data[7:3]}; + end + else + begin + IO_Addr_i <= {ROM_Data[10:9], ROM_Data[3:0]}; + end + end + end + end + +assign Inst_Skip = Z_Skip | RJmp; + +assign N_Inst = Inst_Skip === 1'b 1 | Rst_r === 1'b 1 ? 16'h 0000 : Pause !== 2'b 00 & DidPause === 2'b 00 | DidPause[1] === 1'b 1 ? Inst : ROM_Data; + +always @(posedge Clk) +begin : process_5 + if (Reset === 1'b 1) + begin + Rst_r <= 1'b 1; + Inst <= {16{1'b 0}}; + DidPause <= 2'b 00; + end else + begin + Rst_r <= 1'b 0; + if (DidPause === 2'b 00) + begin + DidPause <= Pause; + end else + begin + DidPause <= DidPause - 1; + end + Inst <= N_Inst; + end +end + +always @(posedge Clk) +begin : process_6 + if (Status_Wr[0] === 1'b 1) begin SREG_i[1:0] <= Status_D[1:0]; end + + case (ROM_Data[2:0]) + 3'b 000: begin Bit_Pattern <= 8'b 00000001; end + 3'b 001: begin Bit_Pattern <= 8'b 00000010; end + 3'b 010: begin Bit_Pattern <= 8'b 00000100; end + 3'b 011: begin Bit_Pattern <= 8'b 00001000; end + 3'b 100: begin Bit_Pattern <= 8'b 00010000; end + 3'b 101: begin Bit_Pattern <= 8'b 00100000; end + 3'b 110: begin Bit_Pattern <= 8'b 01000000; end + default: begin Bit_Pattern <= 8'b 10000000; end + endcase +end + +assign ROM_Addr = NPC[9:0]; +assign PCPause = Rst_r === 1'b 1 | (Pause !== 2'b 00 & DidPause === 2'b 00 | DidPause[1] === 1'b 1) ? 1'b 1 : 1'b 0; + +assign RJmp = + Inst[15:12] === 4'b 1100 | Inst[15:12] === 4'b 1101 & DidPause === 2'b 10 | CBranch === 1'b 1 & + Inst[10] === 1'b 0 & (SREG_i[1:0] & Bit_Pattern[1:0]) !== 2'b 00 | CBranch === 1'b 1 & Inst[10] === 1'b 1 & + (SREG_i[1:0] & Bit_Pattern[1:0]) === 2'b 00 ? 1'b 1 : 1'b 0; + +assign CBranch = Inst[15:11] === 5'b 11110 ? 1'b 1 : 1'b 0; + +assign Pause = Inst[15:10] === 6'b 100000 ? 2'b 01 : 2'b 00; + +assign Offset_small = {Inst[9], Inst[9], Inst[9], Inst[9], Inst[9], Inst[9:3]}; +assign Offset = CBranch === 1'b 0 ? Inst[11:0] : Offset_small; + +assign PassB = Pause !== 2'b 00 & DidPause !== 2'b 01 ? 1'b 1 : 1'b 0; +assign Pass_Mux = Imm_Op === 1'b 1 ? {Inst[11:8], Inst[3:0]} : RAM_Rd === 1'b 1 ? RAM_Data : Reg_Rd === 1'b 1 ? Rr_Data : IO_RData; +assign Wr_Data = Do_Other === 1'b 1 ? Pass_Mux : Q; +assign Op_Mux = Imm_Op === 1'b 1 ? {Inst[11:8], Inst[3:0]} : Rr_Data; + +always @(posedge Clk) +begin : process_7 + IO_Rd_i <= 1'b 0; + Imm_Op <= 1'b 0; + RAM_Rd <= 1'b 0; + Reg_Rd <= 1'b 0; + if ((ROM_Data[15:12] === 4'b 0011 | ROM_Data[15:14] === 2'b 01 | ROM_Data[15:12] === 4'b 1110) & PreDecode === 1'b 1) + begin + Imm_Op <= 1'b 1; + end else + if (RAM_IR === 1'b 1 ) + begin + RAM_Rd <= 1'b 1; + end else + if (ROM_Data[15:11] === 5'b 10110 & PreDecode === 1'b 1 ) + begin + IO_Rd_i <= 1'b 1; + end else + begin + Reg_Rd <= 1'b 1; + end +end + +mf8_alu alu ( + .Clk (Clk), + .ROM_Data (ROM_Data), + .ROM_Pattern (Bit_Pattern), + .A (Rd_Data), + .B (Op_Mux), + .Q (Q), + .SREG (SREG_i), + .PassB (PassB), + .Skip (Inst_Skip), + .Do_Other (Do_Other), + .Z_Skip (Z_Skip), + .Status_D (Status_D), + .Status_Wr (Status_Wr) +); + +mf8_pcs mf8_pc ( + .Clk (Clk), + .Reset (Reset), + .Offs_In (Offset), + .Pause (PCPause), + .RJmp (RJmp), + .NPC (NPC[11:0]), + .PC (PC[11:0]) +); + +mf8_reg pr ( + .Clk (Clk), + .Reset (Reset), + .Wr (Reg_Wr), + .Rd_Addr (Rd_Addr[4:0]), + .Rr_Addr (Rr_Addr[4:0]), + .Data_In (Wr_Data), + .Rd_Data (Rd_Data), + .Rr_Data (Rr_Data), + .Z (Z) +); + +endmodule // diff --git a/examples/mf8/mf8_pcs.v b/examples/mf8/mf8_pcs.v new file mode 100644 index 00000000..a4b55215 --- /dev/null +++ b/examples/mf8/mf8_pcs.v @@ -0,0 +1,35 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + +module mf8_pcs(Clk, Reset, Offs_In, Pause, RJmp, NPC, PC); + input Clk; + input Reset; + input [11:0] Offs_In; + input Pause; + input RJmp; + output [11:0] NPC; + output [11:0] PC; + + reg [11:0] PC_i; + wire [11:0] NPC_i; + wire [11:0] inc_or_nop; + wire [11:0] real_offset; + + + assign NPC = NPC_i; + assign PC = PC_i; + + assign inc_or_nop = {11'b00000000000, ( ~Pause)}; + assign real_offset = (RJmp == 1'b0) ? (inc_or_nop) : (Offs_In); + assign NPC_i = PC_i + real_offset; + + always @(posedge Clk) begin + if (Reset == 1'b1) begin + PC_i <= 12'b000000000000; + end else begin + PC_i <= NPC_i; + end + end +endmodule diff --git a/examples/mf8/mf8_reg.v b/examples/mf8/mf8_reg.v new file mode 100644 index 00000000..aa962b56 --- /dev/null +++ b/examples/mf8/mf8_reg.v @@ -0,0 +1,65 @@ +/* + * Copyright 2018 MicroFPGA UG + * Apache 2.0 License + */ + + +module mf8_reg(Clk, Reset, Wr, Rd_Addr, Rr_Addr, Data_In, Rd_Data, Rr_Data, Z); + input Clk; + input Reset; + input Wr; + input [4:0] Rd_Addr; + input [4:0] Rr_Addr; + input [7:0] Data_In; + output [7:0] Rd_Data; + output [7:0] Rr_Data; + output [15:0] Z; + reg [15:0] Z; + + // Write Address Buffer + reg [4:0] RAM_Write_Address; + always @(posedge Clk) begin + RAM_Write_Address <= Rd_Addr; + end + + // RAM D + reg [7:0] RAMD [31:0]; + reg [7:0] RAMD_Out; + + always @(posedge Clk) begin + if (Wr) RAMD[RAM_Write_Address] <= Data_In; + RAMD_Out <= RAMD[Rd_Addr]; + end + + // RAM R + reg [7:0] RAMR [31:0]; + reg [7:0] RAMR_Out; + + always @(posedge Clk) begin + if (Wr) RAMR[RAM_Write_Address] <= Data_In; + RAMR_Out <= RAMR[Rr_Addr]; + end + + // Bypass + reg [7:0] Write_Data; + reg Bypass_D; + reg Bypass_R; + always @(posedge Clk) begin + Bypass_D <= Wr & (RAM_Write_Address == Rd_Addr); + Bypass_R <= Wr & (RAM_Write_Address == Rr_Addr); + Write_Data <= Data_In; + end + + assign Rd_Data = Bypass_D? Write_Data : RAMD_Out; + assign Rr_Data = Bypass_R? Write_Data : RAMR_Out; + + // Z Register + always @(posedge Clk) begin + if (Wr & RAM_Write_Address == 5'b11110) begin + Z[7:0] <= Data_In; + end + if (Wr & RAM_Write_Address == 5'b11111) begin + Z[15:8] <= Data_In; + end + end +endmodule \ No newline at end of file diff --git a/examples/mf8/mf8_regfile.out b/examples/mf8/mf8_regfile.out new file mode 100644 index 00000000..e69de29b diff --git a/examples/mf8/mf8_regfile.prot b/examples/mf8/mf8_regfile.prot new file mode 100644 index 00000000..b26de08a --- /dev/null +++ b/examples/mf8/mf8_regfile.prot @@ -0,0 +1,38 @@ +struct Mf8RegFile { + in Rd_Addr: u5, + in Rr_Addr: u5, + in Wr: u1, + in Data_In: u8, + + out Rd_Data: u8, + out Rr_Data: u8, + out Z: u16, +} + +// https://github.com/ekiwi/transactional-verification-with-protocols/blob/039fb8d5beafb3c4a464e5dac3dc8a3e00b69f04/enginev/check_mf8_reg.py#L28 +fn read_write( + in rd_addr: u5, // Address of a register that supports both reads/writes + in rr_addr: u5, // Address of a read-only register + in write_en: u1, // If 1, write to `rd_addr` + in write_data: u8, // The actual value to be written to the regsister + out rd_data: u8, + out rr_data: u8 +) { + DUT.Rd_Addr := rd_addr; + DUT.Rr_Addr := rr_addr; + step(); + + DUT.Wr := write_en; + DUT.Data_In := write_data; + assert_eq(DUT.Rd_Data, rd_data); + assert_eq(DUT.Rr_Data, rr_data); + step(); + + DUT.Rd_Addr := X; + DUT.Rr_Addr := X; + DUT.Wr := X; + DUT.Data_In := X; + + fork(); + step(); +} diff --git a/examples/mf8/mf8_regfile.tx b/examples/mf8/mf8_regfile.tx new file mode 100644 index 00000000..e280fbb6 --- /dev/null +++ b/examples/mf8/mf8_regfile.tx @@ -0,0 +1,19 @@ +// ARGS: --verilog mf8/mf8_reg.v --protocol mf8/mf8_regfile.prot --module mf8_reg + +// Arguments are: +// in rd_addr: u5, +// in rr_addr: u5, (address of a read-only register) +// in write_en: u1, (set to 1 if we want to write to `rd_addr`) +// in write_data: u8, +// out rd_data: u8, +// out rr_data: u8 + +// Example transactions for MF8 dual-port register file +// Both RAMD and RAMR initialize to 0x00 +// Writes go to both arrays simultaneously at the buffered write address + +// Transaction 1: Write 0x42 to address 5 +read_write(5, 0, 1, 0x42, 0, 0); + +// Transaction 2: Read back the written value from both ports +read_write(5, 5, 0, 0, 0x42, 0x42);