URL
https://opencores.org/ocsvn/m32632/m32632/trunk
Subversion Repositories m32632
Compare Revisions
- This comparison shows the changes necessary to convert path
/m32632
- from Rev 8 to Rev 9
- ↔ Reverse comparison
Rev 8 → Rev 9
/trunk/rtl/ICACHE_SM.v
0,0 → 1,359
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: ICACHE_SM.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. KOLDETECT Collision Detection Unit |
// 2. ICACHE_SM Instruction Cache State Machine |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. KOLDETECT Collision Detection Unit |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module KOLDETECT ( BCLK, BRESET, DRAM_WR, CVALID, ADDR, TAG0, TAG1 , CFG , C_VALID, READ_I, ACC_OK, |
NEWCVAL, KOLLISION, STOP_ICRD, RUN_ICRD, KILL, KILLADR, ICTODC, STOP_CINV ); |
|
input BCLK; |
input BRESET; |
input DRAM_WR; |
input [23:0] CVALID; // Data from master Valid RAM |
input [27:4] ADDR; |
input [27:12] TAG0,TAG1; |
input [1:0] CFG; |
input [23:0] C_VALID; // Data from secondary Valid RAM |
input READ_I; |
input ACC_OK; |
input HOLD; // active low |
input KDET; |
input INVAL_A; // Cache Invalidate All |
input ENA_HK; // Enable HOLD and Kohaerenz |
|
output [23:0] NEWCVAL; |
output KOLLISION; |
output STOP_ICRD; |
output RUN_ICRD; |
output KILL; |
output [11:7] KILLADR; |
output [2:0] ICTODC; |
output STOP_CINV; |
|
reg [27:4] addr_r; |
reg [7:0] maske,clear; |
reg do_koll; |
reg [2:0] counter; |
reg [1:0] wpointer,rpointer; |
reg [35:0] adrfifo; |
reg [8:0] fifo_q,fifo_c; |
reg [1:0] state; |
reg pipe; |
reg do_kill; |
reg dma; |
|
wire [7:0] set_0,set_1; |
wire match_0,match_1; |
wire valid_0,valid_1; |
wire found_0,found_1; |
wire kolli,dma_kolli; |
wire last_match; |
wire wr_entry; |
wire [23:0] cdaten; |
wire [8:0] kaddr; |
wire [7:0] new_0,new_1; |
wire dma_mode,ic_dma; |
wire free,ende; |
wire init_b; |
|
always @(posedge BCLK) do_koll <= DRAM_WR & CFG[0]; // one cycle pulse, without Cache Enable no col |
always @(posedge BCLK) addr_r <= ADDR; |
|
// similar logic like in CA_MATCH |
|
assign set_0 = C_VALID[7:0]; |
assign set_1 = C_VALID[15:8]; |
|
assign valid_0 = set_0[addr_r[6:4]]; |
assign valid_1 = set_1[addr_r[6:4]]; |
|
assign match_0 = ( TAG0 == addr_r[27:12] ); // 4KB |
assign match_1 = ( TAG1 == addr_r[27:12] ); // 4KB |
|
assign found_0 = valid_0 & match_0; |
assign found_1 = valid_1 & match_1; |
|
assign kolli = (found_0 | found_1) & ~CFG[1] & do_koll; // Action only if ICACHE is not locked |
|
assign KOLLISION = (found_0 | found_1) & do_koll; // to Statistik Modul, Register there |
|
assign dma_kolli = (found_0 | found_1) & ~CFG[1] & CFG[0]; |
|
// the FIFO with 4 entries : |
assign init_b = CFG[0] & ~INVAL_A; // initialise if CINV A too |
|
always @(posedge BCLK) |
if (!init_b) wpointer <= 2'b00; |
else |
wpointer <= wpointer + {1'b0,wr_entry}; |
|
always @(posedge BCLK) |
if (!init_b) rpointer <= 2'b00; |
else |
rpointer <= rpointer + {1'b0,do_kill}; |
|
always @(posedge BCLK) |
begin |
if (wr_entry && (wpointer == 2'b00)) adrfifo[8:0] <= {addr_r[11:4],found_1}; |
if (wr_entry && (wpointer == 2'b01)) adrfifo[17:9] <= {addr_r[11:4],found_1}; |
if (wr_entry && (wpointer == 2'b10)) adrfifo[26:18] <= {addr_r[11:4],found_1}; |
if (wr_entry && (wpointer == 2'b11)) adrfifo[35:27] <= {addr_r[11:4],found_1}; |
end |
|
always @(adrfifo or rpointer) |
case (rpointer) |
2'b00 : fifo_q = adrfifo[8:0]; |
2'b01 : fifo_q = adrfifo[17:9]; |
2'b10 : fifo_q = adrfifo[26:18]; |
2'b11 : fifo_q = adrfifo[35:27]; |
endcase |
|
always @(adrfifo or wpointer) // for Match of last entry use wpointer |
case (wpointer) |
2'b01 : fifo_c = adrfifo[8:0]; |
2'b10 : fifo_c = adrfifo[17:9]; |
2'b11 : fifo_c = adrfifo[26:18]; |
2'b00 : fifo_c = adrfifo[35:27]; |
endcase |
|
// Control |
|
assign last_match = counter[2] & (fifo_c == {addr_r[11:4],found_1}); // if Match with last Entry no |
|
assign wr_entry = kolli & ~last_match; |
|
always @(posedge BCLK) |
casex ({init_b,wr_entry,do_kill,counter}) |
6'b0_xx_xxx : counter <= 3'b000; |
6'b1_00_xxx : counter <= counter; |
6'b1_11_xxx : counter <= counter; |
6'b1_10_000 : counter <= 3'b100; |
6'b1_10_1xx : counter <= (counter[1:0] == 2'b11) ? 3'b111 : {counter[2],(counter[1:0] + 2'b01)}; |
6'b1_01_1xx : counter <= (counter[1:0] == 2'b00) ? 3'b000 : {counter[2],(counter[1:0] + 2'b11)}; |
default : counter <= counter; |
endcase |
|
// DMA Access |
always @(posedge BCLK) dma <= ~HOLD; // there is only one FF for this , from here to DCACHE |
|
// Controlling of ICACHE |
|
assign free = (~READ_I | ACC_OK) & ENA_HK; // switch off if CINV |
|
always @(posedge BCLK) // state[1] state[0] |
casex ({BRESET,dma,counter[2],free,ende,STOP_ICRD,dma_mode}) |
7'b0_xx_xx_xx : state <= 2'b00; |
7'b1_00_xx_00 : state <= 2'b00; |
7'b1_01_1x_00 : state <= 2'b10; // Start of DCACHE Kohaerenz |
7'b1_1x_1x_00 : state <= 2'b11; // Start of DMA |
// |
7'b1_xx_x0_10 : state <= 2'b10; // without "ende" it stays as is |
7'b1_0x_x1_10 : state <= 2'b00; // DMA is not active |
7'b1_1x_x1_10 : state <= 2'b11; // to DMA ! |
// |
7'b1_00_xx_11 : state <= 2'b00; |
7'b1_01_xx_11 : state <= 2'b10; |
7'b1_1x_xx_11 : state <= 2'b11; |
default : state <= 2'b00; |
endcase |
|
assign STOP_ICRD = state[1]; // used for Multiplexer |
assign dma_mode = state[0]; // internal Multiplexer |
|
assign STOP_CINV = state[1] & ~ENA_HK; // stops CINV if DMA access or Kohaerenz access |
|
assign ende = (counter[1:0] == 2'b00) & do_kill; |
|
assign ic_dma = STOP_ICRD & dma_mode; // Signal to DCACHE that ICACHE has stoped |
|
always @(posedge BCLK) pipe <= STOP_ICRD; |
|
assign RUN_ICRD = ~(STOP_ICRD | pipe); // Release for IC_READ |
|
always @(posedge BCLK) do_kill <= STOP_ICRD & ~dma_mode & ~do_kill; // Write pulse in Cache Valid R |
|
assign KILL = do_kill | (KDET & dma_kolli); |
|
// Valid Daten prepare : different sources for DMA and DCACHE Kohaerenz |
|
assign cdaten = dma_mode ? C_VALID : CVALID; |
assign kaddr = dma_mode ? {addr_r[11:4],found_1} : fifo_q; |
|
assign KILLADR = kaddr[8:4]; |
|
always @(kaddr) |
case (kaddr[3:1]) |
3'h0 : clear = 8'hFE; |
3'h1 : clear = 8'hFD; |
3'h2 : clear = 8'hFB; |
3'h3 : clear = 8'hF7; |
3'h4 : clear = 8'hEF; |
3'h5 : clear = 8'hDF; |
3'h6 : clear = 8'hBF; |
3'h7 : clear = 8'h7F; |
endcase |
|
assign new_0 = kaddr[0] ? cdaten[7:0] : (cdaten[7:0] & clear); |
assign new_1 = kaddr[0] ? (cdaten[15:8] & clear) : cdaten[15:8]; |
|
assign NEWCVAL = {cdaten[23:16],new_1,new_0}; |
|
// multiple signals are needed in DCACHE : |
assign ICTODC = {dma,ic_dma,~(counter[2:1] == 2'b11)}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. ICACHE_SM Instruction Cache State Machine |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ICACHE_SM ( BCLK, BRESET, IO_SPACE, MDONE, IO_READY, MMU_HIT, CA_HIT, READ, PTE_ACC, |
USE_CA, PTB_WR, PTB_SEL, USER, PROT_ERROR, |
DRAM_ACC, IO_RD, IO_ACC, IC_PREQ, ACC_OK, HIT_ALL, CUPDATE, AUX_DAT, NEW_PTB, PTB_ONE ); |
|
input BCLK; |
input BRESET; |
input IO_SPACE; |
input MDONE; // Memory Done : Feedback from DRAM Controller, BCLK aligned |
input IO_READY; |
input MMU_HIT,CA_HIT; |
input READ; |
input PTE_ACC; |
input USE_CA; |
input PTB_WR,PTB_SEL; |
input USER; |
input PROT_ERROR; |
|
output reg DRAM_ACC,IO_RD; |
output IO_ACC; |
output IC_PREQ; |
output ACC_OK; |
output HIT_ALL; |
output CUPDATE; |
output AUX_DAT; |
output reg NEW_PTB,PTB_ONE; |
|
reg [3:0] new_state; |
reg rd_done; |
reg card_flag; |
reg rd_rdy; |
|
wire io_busy; |
wire dram_go; |
wire rd_ende; |
wire do_ca_rd; |
|
// Cycle : /-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_ |
// Access : _/-----------------------------------\__ |
// State Machine : ____/----------------------------\______ |
// Busy status ... |
|
assign rd_ende = CA_HIT | rd_rdy; // CA_HIT only if Cache activ ! |
|
always @( READ // only READ , global control |
or PROT_ERROR // is not allowed ! |
// |
or IO_SPACE // indicates access in the IO_WELT |
or io_busy // is already active ? |
// |
or MMU_HIT // Hit in the MMU , now only a READ can be active |
or rd_ende // Cache Hit |
or DRAM_ACC // DRAM Access running |
// |
or PTE_ACC ) // PTE Access running |
// #_# #_# #_# |
casex ({READ,PROT_ERROR,IO_SPACE,io_busy,MMU_HIT,rd_ende,DRAM_ACC,PTE_ACC}) |
// MMU Miss : PTE load from memory |
8'b10_xx_0xx_0 : new_state = 4'b0100; // start PTE access |
// IO-Address selected : external access starts if not already BUSY |
8'b10_10_1xx_x : new_state = 4'b0001; |
// DRAM Access : Cache Miss at READ |
8'b10_0x_100_x : new_state = 4'b1010; // can start directly |
default : new_state = 4'b0; |
endcase |
|
assign IO_ACC = new_state[0]; // to load the Register for Data and Addr |
assign dram_go = new_state[1]; |
assign IC_PREQ = new_state[2]; // MMU to DCACHE ! |
assign do_ca_rd = new_state[3]; |
|
assign HIT_ALL = MMU_HIT & CA_HIT; // for Update "Last-Set" , MMU_HIT contains ZUGRIFF |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) card_flag <= 1'b0; |
else card_flag <= (do_ca_rd & ~rd_rdy) | (card_flag & ~MDONE); |
|
assign CUPDATE = card_flag & USE_CA & MDONE; // USE_CA = ~CI & ~LDC; |
|
always @(posedge BCLK) rd_rdy <= card_flag & MDONE; |
|
// The cache RAM can not provide fast enough the data after an Update. In this case a secondary dat |
assign AUX_DAT = rd_rdy; |
|
// DRAM Interface : |
|
always @(posedge BCLK) if (dram_go) DRAM_ACC <= 1'b1; |
else |
DRAM_ACC <= DRAM_ACC & ~MDONE & BRESET; |
// IO Interface : |
|
always @(posedge BCLK) |
begin |
if (IO_ACC) IO_RD <= READ; else IO_RD <= IO_RD & ~IO_READY & BRESET; |
end |
|
assign io_busy = IO_RD | rd_done; // access is gone in next clock cycle, therefore blocked with "rd |
|
always @(posedge BCLK) rd_done <= READ & IO_READY; // For READ one clock later for data to come thr |
|
// global feedback to opcode fetch unit : you can continue |
|
assign ACC_OK = IO_SPACE ? rd_done : (READ & MMU_HIT & rd_ende); |
|
// PTB1 und PTB0 |
|
always @(posedge BCLK) NEW_PTB <= PTB_WR; // to MMU Update Block |
always @(posedge BCLK) if (PTB_WR) PTB_ONE <= PTB_SEL; |
|
endmodule |
/trunk/rtl/ICACHE.v
0,0 → 1,421
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: ICACHE.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// ICACHE the instruction cache of M32632 |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module ICACHE( BCLK, MCLK, MDONE, BRESET, READ_I, IO_READY, PSR_USER, DATA_HOLD, PTB_WR, PTB_SEL, DR |
KDET, HOLD, CFG, DRAM_Q, CINVAL, IC_SIGS, IO_Q, IVAR, KOLLI_A, MCR_FLAGS, MMU_DIN, VADR, WADDR |
WCTRL, IO_RD, DRAM_ACC, INIT_RUN, PROT_ERROR, ACC_OK, IC_PREQ, KOLLISION, ENA_HK, STOP_CINV, |
DRAM_A, IC_DQ, IC_VA, ICTODC, IO_A, ENDRAM ); |
|
input BCLK; |
input MCLK; |
input MDONE; |
input BRESET; |
input READ_I; |
input IO_READY; |
input PSR_USER; |
input DATA_HOLD; |
input PTB_WR; |
input PTB_SEL; |
input DRAM_WR; |
input KDET; |
input HOLD; |
input [1:0] CFG; |
input [31:0] DRAM_Q; |
input [1:0] CINVAL; |
input [1:0] IC_SIGS; |
input [31:0] IO_Q; |
input [1:0] IVAR; |
input [27:4] KOLLI_A; |
input [3:0] MCR_FLAGS; |
input [23:0] MMU_DIN; |
input [31:0] VADR; |
input [11:2] WADDR; |
input [2:0] WCTRL; |
input ENA_HK; |
input ENDRAM; |
|
output IO_RD; |
output DRAM_ACC; |
output INIT_RUN; |
output PROT_ERROR; |
output ACC_OK; |
output IC_PREQ; |
output KOLLISION; |
output STOP_CINV; |
output [31:0] IC_DQ; |
output [31:12] IC_VA; |
output [3:0] ICTODC; |
output reg [27:0] DRAM_A; |
output reg [31:0] IO_A; |
|
reg [31:0] VADR_R; |
reg [31:0] CAPDAT; |
reg [31:0] DFFE_IOR; |
reg HOLD_ON; |
reg DFF_HDFF1; |
reg DFF_IRD_REG; |
|
wire [4:0] A_CV; |
wire ACOK; |
wire [4:0] ACV; |
wire AUX_DAT; |
wire CA_HIT; |
wire CA_SET; |
wire CUPDATE; |
wire [23:0] D_CV; |
wire HIT_ALL; |
wire INIT_CA_RUN; |
wire IO_ACC; |
wire KILL; |
wire NEW_PTB; |
wire PTB_ONE; |
wire [31:12] RADR; |
wire READ; |
wire RUN_ICRD; |
wire STOP_ICRD; |
wire [23:0] UPCD; |
wire [23:0] UPDATE_C; |
wire [31:0] UPDATE_M; |
wire USE_CA; |
wire USER; |
wire [11:7] V_ADR; |
wire WE_CV; |
wire WEMV; |
wire WRCRAM0; |
wire WRCRAM1; |
wire WRSET0; |
wire WRSET1; |
wire WRITE; |
wire [11:7] KILLADR; |
wire AUX_ALT; |
wire VIRT_A; |
wire CI; |
wire MMU_HIT; |
wire LD_DRAM_A; |
wire IO_SPACE; |
wire LAST_MUX; |
wire VIRTUELL; |
wire NEW_PTB_RUN; |
wire [31:0] SET_DAT; |
wire [31:0] ALT_DAT; |
wire [31:0] DAT_MV; |
wire [3:0] RADR_MV; |
wire [3:0] WADR_MV; |
wire [23:0] NEWCVAL; |
wire KILL_C,KILL_K; |
wire RMW; |
|
// +++++++++++++++++++ Memories ++++++++++++++++++++ |
|
reg [31:0] DATA0 [0:1023]; // Data Set 0 : 4 kBytes |
reg [31:0] SET_DAT0; |
|
reg [31:0] DATA1 [0:1023]; // Data Set 1 : 4 kBytes |
reg [31:0] SET_DAT1; |
|
reg [15:0] TAGSET_0 [0:255]; // Tag Set for Data Set 0 : 256 entries of 16 bits |
reg [15:0] TAG0; |
|
reg [15:0] TAGSET_1 [0:255]; // Tag Set for Data Set 1 : 256 entries of 16 bits |
reg [15:0] TAG1; |
|
reg [23:0] CA_VALID [0:31]; // Valid bits for Data Set 0 and 1 : 32 entries of 24 bits |
reg [23:0] CVALID; |
|
reg [35:0] MMU_TAGS [0:255]; // Tag Set for MMU : 256 entries of 36 bits |
reg [35:0] MMU_Q; |
|
reg [31:0] MMU_VALID [0:15]; // Valid bits for MMU Tag Set : 16 entries of 32 bits |
reg [31:0] MVALID; |
|
reg [15:0] KTAGSET_0 [0:255]; // Kollision Tag Set for Data Set 0 : 256 entries of 16 bits |
reg [15:0] KTAG0; |
|
reg [15:0] KTAGSET_1 [0:255]; // Kollision Tag Set for Data Set 1 : 256 entries of 16 bits |
reg [15:0] KTAG1; |
|
reg [23:0] KCA_VALID [0:31]; // Kollision Valid bits for Data Set 0 and 1 : 32 entries of 24 bits |
reg [23:0] KCVALID; |
|
assign READ = READ_I & ~HOLD_ON & RUN_ICRD; |
assign WRITE = 1'b0; |
assign RMW = 1'b0; |
|
assign ALT_DAT = AUX_ALT ? DFFE_IOR : CAPDAT ; |
|
assign RADR = VIRT_A ? MMU_Q[19:0] : VADR_R[31:12] ; |
|
assign V_ADR = STOP_ICRD ? KILLADR : VADR[11:7] ; |
assign ACV = STOP_ICRD ? KILLADR : A_CV ; |
assign UPCD = STOP_ICRD ? NEWCVAL : UPDATE_C ; |
|
assign IC_DQ = LAST_MUX ? ALT_DAT : SET_DAT ; |
|
assign SET_DAT = CA_SET ? SET_DAT1 : SET_DAT0 ; |
|
assign KILL = KILL_C | KILL_K; |
|
assign IC_VA = VADR_R[31:12]; |
|
assign VIRT_A = ~CINVAL[0] & VIRTUELL; |
|
assign ACC_OK = HOLD_ON | ACOK; |
|
assign USER = ~MCR_FLAGS[3] & PSR_USER; |
|
assign AUX_ALT = HOLD_ON | DFF_IRD_REG; |
|
assign LAST_MUX = AUX_ALT | AUX_DAT; |
|
assign INIT_RUN = NEW_PTB_RUN | INIT_CA_RUN; |
|
assign LD_DRAM_A = ~DRAM_ACC | MDONE; |
|
assign ICTODC[3] = USER; |
|
always @(posedge BCLK) VADR_R <= VADR; |
|
always @(posedge BCLK) DFF_IRD_REG <= IO_RD; |
|
always @(posedge BCLK) DFF_HDFF1 <= IO_READY; |
|
always @(posedge BCLK) if (LD_DRAM_A) DRAM_A[27:0] <= {RADR[27:12],VADR_R[11:2],USE_CA,CA_SET}; |
|
always @(posedge BCLK) if (IO_ACC) IO_A <= {RADR[31:12],VADR_R[11:0]}; |
|
always @(posedge BCLK) if (IO_RD) DFFE_IOR <= IO_Q; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) HOLD_ON <= 1'b0; |
else HOLD_ON <= (DATA_HOLD & DFF_HDFF1) | (HOLD_ON & DATA_HOLD); |
|
always @(posedge MCLK) if (WCTRL[2]) CAPDAT <= DRAM_Q; |
|
// +++++++++++++++++++++++++ Cache Valid +++++++++++++++++++ |
|
always @(posedge BCLK) CVALID <= CA_VALID[V_ADR[11:7]]; |
|
always @(negedge BCLK) if (WE_CV) CA_VALID[ACV] <= D_CV; |
|
// +++++++++++++++++++++++++ Tag Set 0 +++++++++++++++++++++ |
|
always @(posedge BCLK) TAG0 <= TAGSET_0[VADR[11:4]]; |
|
always @(negedge BCLK) if (WRCRAM0) TAGSET_0[VADR_R[11:4]] <= RADR[27:12]; |
|
// +++++++++++++++++++++++++ Tag Set 1 +++++++++++++++++++++ |
|
always @(posedge BCLK) TAG1 <= TAGSET_1[VADR[11:4]]; |
|
always @(negedge BCLK) if (WRCRAM1) TAGSET_1[VADR_R[11:4]] <= RADR[27:12]; |
|
// +++++++++++++++++++++++++ Data Set 0 ++++++++++++++++++++ |
|
always @(posedge BCLK) SET_DAT0 <= DATA0[VADR[11:2]]; |
|
always @(posedge MCLK) if (WRSET0) DATA0[WADDR] <= DRAM_Q; |
|
// +++++++++++++++++++++++++ Data Set 1 ++++++++++++++++++++ |
|
always @(posedge BCLK) SET_DAT1 <= DATA1[VADR[11:2]]; |
|
always @(posedge MCLK) if (WRSET1) DATA1[WADDR] <= DRAM_Q; |
|
CA_MATCH DCA_COMPARE( |
.INVAL_L(CINVAL[0]), |
.CI(CI), |
.MMU_HIT(MMU_HIT), |
.WRITE(WRITE), |
.KDET(1'b0), |
.ADDR({RADR[27:12],VADR_R[11:4]}), |
.CFG(CFG), |
.ENDRAM(ENDRAM), |
.CVALID(CVALID), |
.TAG0(TAG0), |
.TAG1(TAG1), |
.CA_HIT(CA_HIT), |
.CA_SET(CA_SET), |
.WB_ACC(), |
.USE_CA(USE_CA), |
.IOSEL(RADR[31:28]), |
.IO_SPACE(IO_SPACE), |
.DC_ILO(1'b0), |
.KILL(KILL_C), |
.UPDATE(UPDATE_C)); |
|
DCA_CONTROL DCA_CTRL( |
.BCLK(BCLK), |
.MCLK(1'b0), |
.WRCFG(1'b1), |
.BRESET(BRESET), |
.CA_SET(CA_SET), |
.HIT_ALL(HIT_ALL), |
.UPDATE(UPCD), |
.VADR_R(VADR_R[11:7]), |
.DRAM_ACC(DRAM_ACC), |
.CUPDATE(CUPDATE), |
.KILL(KILL), |
.WRITE(WRITE), |
.WCTRL(WCTRL[1:0]), |
.INVAL_A(CINVAL[1]), |
.DAT_CV(D_CV), |
.WADR_CV(A_CV), |
.WE_CV(WE_CV), |
.INIT_CA_RUN(INIT_CA_RUN), |
.WRCRAM0(WRCRAM0), |
.WRCRAM1(WRCRAM1), |
.WRSET0(WRSET0), |
.WRSET1(WRSET1)); |
|
ICACHE_SM IC_SM( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.IO_SPACE(IO_SPACE), |
.READ(READ), |
.MDONE(MDONE), |
.IO_READY(IO_READY), |
.MMU_HIT(MMU_HIT), |
.CA_HIT(CA_HIT), |
.USE_CA(USE_CA), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.USER(USER), |
.PROT_ERROR(PROT_ERROR), |
.PTE_ACC(IC_SIGS[1]), |
.ACC_OK(ACOK), |
.PTB_ONE(PTB_ONE), |
.NEW_PTB(NEW_PTB), |
.AUX_DAT(AUX_DAT), |
.CUPDATE(CUPDATE), |
.IO_RD(IO_RD), |
.IO_ACC(IO_ACC), |
.DRAM_ACC(DRAM_ACC), |
.IC_PREQ(IC_PREQ), |
.HIT_ALL(HIT_ALL)); |
|
// +++++++++++++++++++++++++ Kollision Valid +++++++++++++++ |
|
always @(posedge BCLK) KCVALID <= KCA_VALID[KOLLI_A[11:7]]; |
|
always @(negedge BCLK) if (WE_CV) KCA_VALID[ACV] <= D_CV; |
|
// +++++++++++++++++++++++++ Kollision Tag Set 0 +++++++++++ |
|
always @(posedge BCLK) KTAG0 <= KTAGSET_0[KOLLI_A[11:4]]; |
|
always @(negedge BCLK) if (WRCRAM0) KTAGSET_0[VADR_R[11:4]] <= RADR[27:12]; |
|
// +++++++++++++++++++++++++ Kollision Tag Set 1 +++++++++++ |
|
always @(posedge BCLK) KTAG1 <= KTAGSET_1[KOLLI_A[11:4]]; |
|
always @(negedge BCLK) if (WRCRAM1) KTAGSET_1[VADR_R[11:4]] <= RADR[27:12]; |
|
KOLDETECT KOLLOGIK( |
.DRAM_WR(DRAM_WR), |
.BCLK(BCLK), |
.READ_I(READ_I), |
.ACC_OK(ACC_OK), |
.BRESET(BRESET), |
.INVAL_A(CINVAL[1]), |
.KDET(KDET), |
.HOLD(HOLD), |
.ENA_HK(ENA_HK), |
.STOP_CINV(STOP_CINV), |
.ADDR(KOLLI_A), |
.C_VALID(KCVALID), |
.CFG(CFG), |
.CVALID(CVALID), |
.TAG0(KTAG0), |
.TAG1(KTAG1), |
.KOLLISION(KOLLISION), |
.STOP_ICRD(STOP_ICRD), |
.RUN_ICRD(RUN_ICRD), |
.KILL(KILL_K), |
.ICTODC(ICTODC[2:0]), |
.KILLADR(KILLADR), |
.NEWCVAL(NEWCVAL)); |
|
MMU_MATCH MMU_COMPARE( |
.USER(USER), |
.READ(READ), |
.WRITE(WRITE), |
.RMW(RMW), |
.IVAR(IVAR), |
.MCR_FLAGS(MCR_FLAGS[2:0]), |
.MMU_VA(MMU_Q[35:20]), |
.MVALID(MVALID), |
.VADR_R(VADR_R[31:12]), |
.MMU_HIT(MMU_HIT), |
.PROT_ERROR(PROT_ERROR), |
.VIRTUELL(VIRTUELL), |
.CI(CI), |
.SEL_PTB1(), |
.UPDATE(UPDATE_M)); |
|
MMU_UP MMU_CTRL( |
.NEW_PTB(NEW_PTB), |
.IVAR(IVAR[1]), |
.BRESET(BRESET), |
.PTB1(PTB_ONE), |
.BCLK(BCLK), |
.WR_MRAM(IC_SIGS[0]), |
.MVALID(MVALID), |
.UPDATE(UPDATE_M), |
.VADR(VADR[19:16]), |
.VADR_R(VADR_R[19:16]), |
.WE_MV(WEMV), |
.NEW_PTB_RUN(NEW_PTB_RUN), |
.DAT_MV(DAT_MV), |
.RADR_MV(RADR_MV), |
.WADR_MV(WADR_MV)); |
|
// +++++++++++++++++++++++++ MMU Valid +++++++++++++++++++++ |
|
always @(posedge BCLK) MVALID <= MMU_VALID[RADR_MV]; |
|
always @(negedge BCLK) if (WEMV) MMU_VALID[WADR_MV] <= DAT_MV; |
|
// +++++++++++++++++++++++++ MMU Tags ++++++++++++++++++++++ |
|
always @(posedge BCLK) MMU_Q <= MMU_TAGS[VADR[19:12]]; |
|
always @(negedge BCLK) if (IC_SIGS[0]) MMU_TAGS[VADR_R[19:12]] <= {VADR_R[31:20],MMU_DIN[23:0]}; |
|
endmodule |
/trunk/rtl/example_mods.v
0,0 → 1,356
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: example_mods.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. ex_io_bus_ctrl Input/Output Bus controller |
// 2. ex_in_reg Input Register |
// 3. ex_out_reg Output Register |
// 4. ex_boot_rom Boot ROM |
// 5. ex_statcou Statistic Counters |
// 6. ex_copro Coprocessor |
// 7. ex_dram_emul DRAM Emulator |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. ex_io_bus_ctrl Input/Output Bus controller |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_io_bus_ctrl( CLK, RESET_N, RST_N, IO_WR, IO_RD, IO_A, IO_BE, IO_Q, IO_READY, |
W_OUT_REG, IN_DAT, BOOT_DAT, STAT_DAT, ENDRAM ); |
|
input CLK; |
input RESET_N; |
input IO_WR,IO_RD; |
input [31:28] IO_A; |
input [3:0] IO_BE; |
|
input [31:0] BOOT_DAT; |
input [7:0] IN_DAT; |
input [31:0] STAT_DAT; |
|
output reg [31:0] IO_Q; |
output reg RST_N; |
output reg ENDRAM; |
output IO_READY; |
output W_OUT_REG; |
|
reg rd_rdy; |
reg [3:0] init_cou; |
|
always @(posedge CLK) rd_rdy <= IO_RD & ~rd_rdy; |
|
assign IO_READY = IO_WR | rd_rdy; |
|
always @(IO_A or BOOT_DAT or IN_DAT or STAT_DAT) |
casex({IO_A}) |
4'b000x : IO_Q = BOOT_DAT; // Boot-ROM |
4'b0010 : IO_Q = {24'd0,IN_DAT}; |
4'b0011 : IO_Q = STAT_DAT; |
default : IO_Q = 32'hxxxxxxxx; |
endcase |
|
assign W_OUT_REG = IO_WR & (IO_A == 4'h2) & IO_BE[0]; |
|
// ++++++++++++++++++++++++++ RESET Signal ++++++++++++++++++++++++++ |
|
always @(posedge CLK or negedge RESET_N) |
if (!RESET_N) init_cou <= 4'h0; |
else init_cou <= init_cou + 4'h1; |
|
always @(posedge CLK or negedge RESET_N) |
if (!RESET_N) RST_N <= 1'b0; |
else |
if (init_cou == 4'hF) RST_N <= 1'b1; |
|
// Reading from Boot ROM switches DRAM on! You must read program code - not data. |
always @(posedge CLK) ENDRAM <= (ENDRAM | (IO_RD & (IO_A == 4'h1))) & RST_N; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. ex_in_reg Input Register |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_in_reg( CLK, IN_REG, IN_DAT); |
|
parameter in_width = 7; |
|
input CLK; |
input [in_width:0] IN_REG; |
|
output reg [in_width:0] IN_DAT; |
|
reg [in_width:0] meta_reg; |
|
always @(posedge CLK) |
begin |
meta_reg <= IN_REG; |
IN_DAT <= meta_reg; |
end |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. ex_out_reg Output Register |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_out_reg( CLK, W_OUT_REG, DIN, OUT_REG); |
|
parameter out_width = 7; |
|
input CLK; |
input W_OUT_REG; |
input [31:0] DIN; |
|
output reg [out_width:0] OUT_REG; |
|
always @(posedge CLK) if (W_OUT_REG) OUT_REG <= DIN[out_width:0]; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. ex_boot_rom Boot ROM |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_boot_rom( CLK, ADDR, DATA); |
|
input CLK; |
input [9:2] ADDR; |
|
output reg [31:0] DATA; |
|
reg [31:0] BOOT_ROM [0:255]; // 1 kByte |
|
initial |
begin |
$readmemh("boot_rom.txt", BOOT_ROM); |
end |
|
always @(posedge CLK) DATA <= BOOT_ROM[ADDR[9:2]]; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 5. ex_statcou Statistic Counters |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_statcou( CLK, RST_N, STATSIGS, ADDR, DATA); |
|
input CLK; |
input RST_N; |
input [7:0] STATSIGS; |
input [2:0] ADDR; |
|
output [31:0] DATA; |
|
integer i; |
|
reg [31:0] counter [0:7]; |
|
always @(posedge CLK or negedge RST_N) |
for (i=0; i<=7; i=i+1) |
if (!RST_N) counter[i] <= 32'd0; |
else counter[i] <= counter[i] + {31'd0,STATSIGS[i]}; |
|
assign DATA = counter[ADDR]; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 6. ex_copro Coprocessor |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_copro( CLK, COP_GO, COP_OP, COP_INP, COP_DONE, COP_OUTP); |
|
input CLK; |
input COP_GO; |
input [23:0] COP_OP; |
input [127:0] COP_INP; |
|
output reg COP_DONE; |
output reg [63:0] COP_OUTP; |
|
always @(posedge CLK) |
COP_OUTP <= COP_OP[8] ? {COP_INP[71:64],COP_INP[79:72],COP_INP[87:80],COP_INP[95:88],32'd0} |
: {COP_INP[7:0],COP_INP[15:8],COP_INP[23:16],COP_INP[31:24],COP_INP[71:64],COP_INP[79:72],COP_I |
|
always @(posedge CLK) COP_DONE <= COP_GO; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 7. ex_dram_emul DRAM Emulator |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ex_dram_emul ( MCLK, RST_N, IC_ACC, IDRAM_ADR, DC_ACC, DC_WR, DRAM_ADR, DRAM_DI, |
IC_MDONE, DC_MDONE, ENWR, WAMUX, WADDR, MEM_Q, IWCTRL, DWCTRL ); |
|
input MCLK; |
input RST_N; |
input IC_ACC; |
input [27:0] IDRAM_ADR; |
input DC_ACC; |
input DC_WR; |
input [27:0] DRAM_ADR; |
input [35:0] DRAM_DI; |
|
output reg IC_MDONE; |
output reg DC_MDONE; |
output ENWR; |
output reg WAMUX; |
output [11:2] WADDR; |
output reg [2:0] IWCTRL; |
output reg [2:0] DWCTRL; |
|
output reg [31:0] MEM_Q; |
|
// +++++++++++++++++++ Memories ++++++++++++++++++++ |
|
parameter addr_msb = 13; // total memory is 16 kBytes |
|
reg [31:0] EDRAM [0:2**(addr_msb-1)-1]; |
reg [addr_msb+34:0] FIFO [0:15]; |
|
reg [addr_msb+34:0] fifo_q; |
reg [1:0] state; |
reg [1:0] nibble,lsb; |
reg [addr_msb:4] addr; |
reg use_cache; |
reg select; |
reg [3:0] w_poi,r_poi,r_zeiger; |
reg wr_next; |
|
wire [7:0] din_0,din_1,din_2,din_3; |
wire [addr_msb:2] raddr; |
wire frei; |
wire start; |
wire wr_req; |
wire ca_req; |
wire write; |
|
// +++++++++++++++++++++++++ Datapath +++++++++++++++++++ |
|
always @(negedge MCLK) if (DC_WR) FIFO[w_poi] <= {DRAM_ADR[addr_msb:2],DRAM_DI}; |
|
always @(posedge MCLK or negedge RST_N) |
if (!RST_N) w_poi <= 4'd0; |
else w_poi <= w_poi + {3'd0,DC_WR}; |
|
always @(posedge MCLK or negedge RST_N) |
if (!RST_N) r_poi <= 4'd0; |
else r_poi <= r_poi + {3'd0,write}; |
|
always @(negedge MCLK or negedge RST_N) |
if (!RST_N) r_zeiger <= 4'd0; |
else r_zeiger <= r_zeiger + {3'd0,write}; |
|
always @(posedge MCLK) fifo_q <= FIFO[r_zeiger]; |
|
always @(negedge MCLK) MEM_Q <= EDRAM[raddr]; // READ on falling edge |
|
assign din_0 = fifo_q[32] ? fifo_q[7:0] : MEM_Q[7:0]; |
assign din_1 = fifo_q[33] ? fifo_q[15:8] : MEM_Q[15:8]; |
assign din_2 = fifo_q[34] ? fifo_q[23:16] : MEM_Q[23:16]; |
assign din_3 = fifo_q[35] ? fifo_q[31:24] : MEM_Q[31:24]; |
|
always @(posedge MCLK) if (write) EDRAM[raddr] <= {din_3,din_2,din_1,din_0}; // WRITE on rising edg |
|
// +++++++++++++++++++++++++ Controllogic +++++++++++++++++++ |
|
assign ca_req = DC_ACC | IC_ACC; // Cache Read Request |
assign wr_req = (w_poi != r_poi); // Write Request |
|
assign write = (wr_req & ~ca_req & frei) | wr_next; |
|
always @(posedge MCLK or negedge RST_N) |
if (!RST_N) wr_next <= 1'b0; |
else wr_next <= write & (w_poi != (r_poi + 4'd1)); |
|
always @(posedge MCLK or negedge RST_N) |
if (!RST_N) state <= 2'd0; |
else |
if (frei) state <= (ca_req & ~wr_next) ? 2'b01 : 2'd0; |
else state <= state + 2'b01; |
|
assign frei = (state == 2'd0); |
|
assign start = ca_req & frei & ~wr_next; |
|
always @(negedge MCLK) |
if (start) |
begin |
addr <= DC_ACC ? DRAM_ADR[addr_msb:4] : IDRAM_ADR[addr_msb:4]; |
use_cache <= DC_ACC ? DRAM_ADR[1] : IDRAM_ADR[1]; |
select <= DC_ACC; |
end |
|
always @(negedge MCLK) |
if (start) nibble <= DC_ACC ? {DRAM_ADR[3],~DRAM_ADR[2]} : {IDRAM_ADR[3],~IDRAM_ADR[2]}; |
else |
if (state == 2'b01) nibble <= {~nibble[1],1'b0}; |
else |
if (state[1]) nibble <= {nibble[1],~nibble[0]}; |
|
assign raddr = write ? fifo_q[addr_msb+34:36] : (start ? (DC_ACC ? DRAM_ADR[addr_msb:2] : IDRAM_ADR |
|
always @(negedge MCLK) lsb <= raddr[3:2]; |
|
assign ENWR = 1'b1; // always active |
|
always @(posedge MCLK) |
begin |
WAMUX <= start | ~frei; |
|
DC_MDONE <= select & (state == 2'b01); |
DWCTRL[2] <= select & start; |
DWCTRL[1] <= select & (start | ~frei) & use_cache; |
DWCTRL[0] <= select & ~use_cache; |
|
IC_MDONE <= ~select & (state == 2'b10); // must be late to cover all cases |
IWCTRL[2] <= ~select & start; |
IWCTRL[1] <= ~select & (start | ~frei) & use_cache; |
IWCTRL[0] <= ~select & ~use_cache; |
end |
|
assign WADDR = {addr[11:4],lsb}; |
|
endmodule |
/trunk/rtl/DP_FPU.v
0,0 → 1,1390
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: DP_FPU.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. PREPDATA Prepare data for the big multiplier |
// 2. BCDADDER 4 bit BCD adder |
// 3. DFPU_BCD Binary coded decimal (BCD) adder and subtractor |
// 4. DFPU_ADDSUB Double precision floating point adder and subtractor |
// 5. DFPU_MISC Double precision floating point miscellaneous operations |
// 6. DFPU_MUL Double precision floating point multiplier |
// 7. DIVI_PREP Prepare data for the divider |
// 8. DFPU_DIV The divider for all divide opcodes : double, single and integer |
// 9. DP_LOGIK Control logic and result path for different functions |
// 10. DP_FPU Top level of long operations datapath |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. PREPDATA Prepare data for the big multiplier |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module PREPDATA ( START, MEI, DFLOAT, BWD, SRC1, SRC2, |
MSD_1, MSD_2, LSD_1, LSD_2, LOAD_MSD, LOAD_LSD1, LOAD_LSD2 ); |
|
input [1:0] START; |
input MEI,DFLOAT; |
input [1:0] BWD; |
input [31:0] SRC1,SRC2; |
|
output [52:32] MSD_1,MSD_2; |
output [31:0] LSD_1,LSD_2; |
output LOAD_MSD,LOAD_LSD1,LOAD_LSD2; |
|
reg [31:0] LSD_1,LSD_2; |
|
assign MSD_1 = MEI ? 21'h0 : {1'b1,SRC1[19:0]}; |
assign MSD_2 = MEI ? 21'h0 : {1'b1,SRC2[19:0]}; |
|
always @(MEI or BWD or SRC1) |
casex ({MEI,BWD}) |
3'b100 : LSD_1 = {24'h000000,SRC1[7:0]}; |
3'b101 : LSD_1 = {16'h0000,SRC1[15:0]}; |
default : LSD_1 = SRC1; |
endcase |
|
always @(MEI or BWD or SRC2) |
casex ({MEI,BWD}) |
3'b100 : LSD_2 = {24'h000000,SRC2[7:0]}; |
3'b101 : LSD_2 = {16'h0000,SRC2[15:0]}; |
default : LSD_2 = SRC2; |
endcase |
|
assign LOAD_MSD = (START[0] & MEI) | (START[0] & DFLOAT); // 1. step data load at DFLOAT |
assign LOAD_LSD1 = (START[0] & MEI) | (START[1] & DFLOAT); // 2. step execute at DFLOAT |
assign LOAD_LSD2 = (START[1] & MEI) | (START[1] & DFLOAT); // 2. step execute at DFLOAT |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. BCDADDER 4 bit BCD adder |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module BCDADDER ( A_IN, B_IN, CY_IN, SUBP, OUT, CY_OUT ); |
|
input [3:0] A_IN,B_IN; |
input CY_IN; |
input SUBP; |
|
output [3:0] OUT; |
output CY_OUT; |
|
wire [4:0] result; |
wire over; |
|
assign result = SUBP ? ({1'b0,A_IN} - {1'b0,B_IN} - {4'b0,CY_IN}) |
: ({1'b0,A_IN} + {1'b0,B_IN} + {4'b0,CY_IN}); |
|
assign over = result[4] | (result[3] & (result[2] | result[1])); |
|
// if result<0 : -6 if result>9 : -10 |
assign OUT = result[3:0] - (SUBP ? {1'b0,result[4],result[4],1'b0} : {over,1'b0,over,1'b0}); |
assign CY_OUT = SUBP ? result[4] : over; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. DFPU_BCD Binary coded decimal (BCD) adder and subtractor |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DFPU_BCD ( BCLK, BRESET, START, DO_BCD, BWD, SRC1, SRC2, CY_IN, SUBP, BCD_Q, CY_OUT, BCD_DONE |
|
// Byte : 3 cycles in shortest case REG-REG, Word : 4 cycles and Double : 6 cycles |
input BCLK; |
input BRESET; |
input START; // START[1] |
input DO_BCD; // BCD Opcode is valid |
input [1:0] BWD; |
input [31:0] SRC1,SRC2; // Source , Destination, data is stable during operation |
input CY_IN; // comes from PSR |
input SUBP; // SUBP = 1 : SUBP , 0 : ADDP |
|
output reg [31:0] BCD_Q; |
output reg CY_OUT; // went to PSR if DONE is valid |
output BCD_DONE; |
|
reg run_bcd; |
reg [1:0] byte_cou; |
reg [15:0] datain; |
|
wire [7:0] result; |
wire carry,carry_lsd,carry_msd; |
|
// START : _/---\________________ |
// byte_cou : xxxxxx 0 x 1 x 2 x 3 x |
// BCD_DONE : _____/---\____________ if BWD = Byte |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) run_bcd <= 1'b0; |
else |
run_bcd <= (START & DO_BCD) | (run_bcd & (BWD != byte_cou)); |
|
always @(posedge BCLK) byte_cou <= START ? 2'd0 : byte_cou + {1'b0,run_bcd}; |
|
always @(*) |
casex ({START,byte_cou}) |
3'b1_xx : datain = {SRC1[7:0], SRC2[7:0]}; |
3'b0_00 : datain = {SRC1[15:8], SRC2[15:8]}; |
3'b0_01 : datain = {SRC1[23:16],SRC2[23:16]}; |
3'b0_1x : datain = {SRC1[31:24],SRC2[31:24]}; |
endcase |
|
assign carry = START ? CY_IN : CY_OUT; |
|
BCDADDER lsd_inst ( .A_IN(datain[3:0]), .B_IN(datain[11:8]), .CY_IN(carry), .SUBP(SUBP), |
.OUT(result[3:0]), .CY_OUT(carry_lsd) ); |
|
BCDADDER msd_inst ( .A_IN(datain[7:4]), .B_IN(datain[15:12]), .CY_IN(carry_lsd), .SUBP(SUBP), |
.OUT(result[7:4]), .CY_OUT(carry_msd) ); |
|
always @(posedge BCLK) CY_OUT <= carry_msd; |
|
always @(posedge BCLK) if (START) BCD_Q[7:0] <= result; |
always @(posedge BCLK) if (byte_cou == 2'd0) BCD_Q[15:8] <= result; |
always @(posedge BCLK) if (byte_cou == 2'd1) BCD_Q[23:16] <= result; |
always @(posedge BCLK) if (byte_cou[1]) BCD_Q[31:24] <= result; |
|
assign BCD_DONE = run_bcd & (BWD == byte_cou); |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. DFPU_ADDSUB Double precision floating point adder and subtractor |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DFPU_ADDSUB ( BCLK, START, SRC1, SRC2, MAN1, MAN2, SRCFLAGS, BWD, SELECT, OUT, IOUT, CMPRES ) |
|
input BCLK; |
input [1:0] START; |
input [31:0] SRC1,SRC2; // The input data |
input [20:0] MAN1,MAN2; |
input [5:0] SRCFLAGS; // NAN, ZERO and SIGN of operands |
input [1:0] BWD; // size of integer |
input [3:0] SELECT; // upper 2 bits : R.T.F. code |
|
output [69:0] OUT; |
output [31:0] IOUT; // result of ROUNDLi/TRUNCLi/FLOORLi = R.T.F. |
output [1:0] CMPRES; |
|
reg [69:0] outreg; |
reg [31:0] IOUT; |
|
// MOViL : 2 cycles |
// ROUNDLi : 3 cycles (+TRUNC & FLOOR) |
// ADD/SUB : 4 cycles |
// CMP : 2 cycles |
|
// ++++++++++++++++++++++++++++++++++ |
// MOViL : 1. Pipeline stage : needs 3 cycles |
|
reg [31:8] movdat; |
reg [31:0] movif; |
reg sign_movif; |
|
always @(BWD or SRC1) |
casex({BWD,SRC1[15],SRC1[7]}) |
4'b00x0 : movdat = 24'h0000_00; // Byte |
4'b00x1 : movdat = 24'hFFFF_FF; |
4'b010x : movdat = {16'h0000,SRC1[15:8]}; // Word |
4'b011x : movdat = {16'hFFFF,SRC1[15:8]}; |
default : movdat = SRC1[31:8]; // Double |
endcase |
|
// This pipeline stage for better timing |
always @(posedge BCLK) movif <= movdat[31] ? (32'h0 - {movdat,SRC1[7:0]}) : {movdat,SRC1[7:0]}; // |
|
always @(posedge BCLK) sign_movif <= movdat[31]; |
|
// ROUNDLi/TRUNCLi/FLOORLi : 1. pipeline stage : can Opcode-Decoder deliver direct the 64 bit opera |
|
reg ovflag,ovflag2; |
reg rovfl; |
reg minint; |
wire [11:0] rexdiff,rexo; |
wire ganzklein; // Flag for 0 |
|
assign rexdiff = 12'h41D - {1'b0,SRC1[30:20]}; // 4..0 is the right shift value : like Single FP sa |
|
// ovflag2 at the end of rounding : Check for Overflow |
always @(posedge BCLK) rovfl <= (ovflag | ovflag2) & (SELECT[1:0] == 2'b11) & ~minint; |
|
// a large positiv difference is a very small number : |
assign ganzklein = (~rexdiff[11] & (rexdiff[10:5] != 6'b0)); // 0 is implicit via SRC1[30:20]=0 |
|
// Detection of Overflow |
assign rexo = ({1'b0,SRC1[30:20]} - {11'h1FF,~BWD[1]}); // subtract B/W = 3FF , D = 3FE |
|
always @(BWD or rexo) // 0 ist in implicitly |
casex (BWD) |
2'b00 : ovflag = (~rexo[11] & (rexo[10:3] != 8'h0)); // Exponent 0..7 because -128.4 => -128 |
2'b01 : ovflag = (~rexo[11] & (rexo[10:4] != 7'h0)); // Exponent 0..15 look above |
default : ovflag = (~rexo[11] & (rexo[10:5] != 6'h0)); // but Exponent only 0..30 |
endcase |
|
always @(posedge BCLK) |
if (START[1]) minint <= (SRC1 == 32'hC1E0_0000) & (SRC2 == 32'h0) & BWD[1]; // detection of -2^31 |
|
// ++++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 1. Pipeline Stage : which operand ist bigger ? Exchange if neccessary |
// SUB/CMP : SRC2 - SRC1 |
|
reg ex_null,ma_null,ex_msb,ma_msb; |
reg [10:0] expo1,expo2; |
wire [11:0] exdiff,exdiff12; |
wire [20:0] madiff; |
wire switch,nan,sign,sign1,sign2; |
reg [5:0] shift1,shift2; |
|
// Pipeline register : |
reg [63:0] muxsrc2; |
reg [55:3] pipe1; // Nummbers for right shifter |
reg [5:0] shift; |
reg vorz,addflag; |
|
wire [52:0] muxsrc1; |
wire [32:0] lowdiff; |
|
assign nan = (SELECT[1:0] == 2'b11) ? SRCFLAGS[1] : (~SELECT[1] & (SRCFLAGS[3] | SRCFLAGS[1])); // |
|
assign exdiff = {1'b0,SRC2[30:20]} - {1'b0,SRC1[30:20]}; // Difference of Exponents |
assign madiff = {1'b0,SRC2[19:0]} - {1'b0,SRC1[19:0]}; // Difference of Mantissa |
assign exdiff12 = {1'b0,SRC1[30:20]} - {1'b0,SRC2[30:20]}; // Diff. Exponents exchanged |
|
always @(posedge BCLK) |
if (START[0]) |
begin |
ex_null <= (exdiff[10:0] == 11'h0); |
ma_null <= (madiff[19:0] == 20'h0); |
ex_msb <= exdiff[11]; |
ma_msb <= madiff[20]; |
shift1 <= (exdiff[10:6] != 5'h0) ? 6'h3F : exdiff[5:0]; |
shift2 <= (exdiff12[10:6] != 5'h0) ? 6'h3F : exdiff12[5:0]; |
expo1 <= SRC1[30:20]; |
expo2 <= SRC2[30:20]; |
end |
|
assign lowdiff = {1'b0,SRC2} - {1'b0,SRC1}; // LSD compare |
|
assign switch = ex_msb | (ex_null & (ma_msb | (ma_null & lowdiff[32]))); // exchange ? |
|
assign muxsrc1 = switch ? {MAN2,SRC2} : {MAN1,SRC1}; |
|
always @(posedge BCLK) // Pipeline Reg |
begin |
muxsrc2 <= switch ? {expo1,MAN1,SRC1} : {expo2,MAN2,SRC2}; // Incl. Exponent & "1" of mantissa |
pipe1 <= SELECT[1] ? (ganzklein ? 53'd0 : {1'b1,SRC1[19:0],SRC2}) : muxsrc1; // Feeding of R.T.F. |
shift <= SELECT[1] ? {1'b0,rexdiff[4:0]} : (switch ? shift2 : shift1); |
end |
|
// SRC2 SRC1 : switch = 0 SRC2 SRC1 : switch = 1 |
// 5 + 3 : +(5 + 3) = 8 3 + 5 : +(5 + 3) = 8 SELECT[0] = 0 |
// 5 + (-3) : +(5 - 3) = 2 3 + (-5) : -(5 - 3) = -2 |
// (-5) + 3 : -(5 - 3) = -2 (-3) + 5 : +(5 - 3) = 2 |
// (-5) + (-3) : -(5 + 3) = -8 (-3) + (-5) : -(5 + 3) = -8 |
// 5 - 3 : +(5 - 3) = 2 3 - 5 : -(5 - 3) = -2 SELECT[0] = 1 |
// 5 - (-3) : +(5 + 3) = 8 3 - (-5) : +(5 + 3) = 8 |
// (-5) - 3 : -(5 + 3) = -8 (-3) - 5 : -(5 + 3) = -8 |
// (-5) - (-3) : -(5 - 3) = -2 (-3) - (-5) : +(5 - 3) = 2 |
|
assign sign1 = SRCFLAGS[4]; |
assign sign2 = SRCFLAGS[5]; |
|
always @(posedge BCLK) // Pipeline Reg |
begin |
vorz <= switch ? (SELECT[0] ^ sign1) : sign2; |
addflag <= ~(SELECT[0] ^ (sign1 ^ sign2)); |
end |
|
// CMPF : 1. Pipeline Stage : first result : is stored one level higer in Reg |
|
assign CMPRES[1] = ~CMPRES[0] & (switch ? ~sign1 : sign2); // look table above |
assign CMPRES[0] = (ex_null & ma_null & (sign1 == sign2) & (lowdiff == 33'h0)) | (SRCFLAGS[2] & SRC |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB + ROUND/TRUNC : 2. Step : Barrelshifter to the right --> |
|
wire [55:0] brshifta,brshiftb,brshiftc,brshiftd,brshifte,brshiftf; |
|
// 5..33322222222221111111111 is this picture still correct ? Took over from Single FP |
// 5..2109876543210987654321098765432-10 |
// 1..VVVVVVVVVVVVVVVVVVVVVVVV0000000-00 // last 2 bit for rounding |
|
assign brshifta = shift[5] ? {32'h0, pipe1[55:33], (pipe1[32:3] != 30'h0)} : {pipe1,3'h0}; |
assign brshiftb = shift[4] ? {16'h0,brshifta[55:17],(brshifta[16:0] != 17'h0)} : brshifta; |
assign brshiftc = shift[3] ? { 8'h0, brshiftb[55:9], (brshiftb[8:0] != 9'h0)} : brshiftb; |
assign brshiftd = shift[2] ? { 4'h0, brshiftc[55:5], (brshiftc[4:0] != 5'h0)} : brshiftc; |
assign brshifte = shift[1] ? { 2'h0, brshiftd[55:3], (brshiftd[2:0] != 3'h0)} : brshiftd; |
assign brshiftf = shift[0] ? { 1'b0, brshifte[55:2], (brshifte[1:0] != 2'h0)} : brshifte; |
|
// ++++++++++++++++++++++++++++++++++ |
// ROUNDLi/TRUNCLi/FLOORLi : 3. Step : round to Integer |
|
reg car_ry; |
wire [1:0] inex; |
wire [30:0] compl; |
wire [31:0] iadder; |
wire restbits; |
|
assign restbits = (brshiftf[23:0] != 24'h0); |
assign inex = {brshiftf[24],restbits}; // Inexact-Flag-Data transfered to multiplexer at the e |
|
always @(SELECT or sign1 or brshiftf or restbits or inex or ganzklein) |
casex (SELECT[3:2]) |
2'b00 : car_ry = sign1 ^ (((brshiftf[25:24] == 2'b11) & ~restbits) | (inex == 2'b11)); // ROUN |
2'b1x : car_ry = sign1 ? (~ganzklein & (inex == 2'b00)) : 1'b0; // +numbers like TRUNCLi, -num |
default : car_ry = sign1; // TRUNCLi , simple cut off |
endcase |
|
assign compl = sign1 ? ~brshiftf[55:25] : brshiftf[55:25]; |
|
assign iadder = {sign1,compl} + {31'h0,car_ry}; |
|
always @(posedge BCLK) IOUT <= minint ? 32'h8000_0000 : iadder; |
|
always @(iadder or BWD or sign1) // special overflow detection i.e. -129 to -255 at Byte |
casex (BWD) // or 127.9 -> 128 = error ! |
2'b00 : ovflag2 = (iadder[8] != iadder[7]); // Byte |
2'b01 : ovflag2 = (iadder[16] != iadder[15]); // Word |
default : ovflag2 = 1'b0; |
endcase |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 3. Step : Addition or Subtraction |
|
wire [67:0] result; |
wire [55:0] blshifti; |
wire [12:0] shiftl; |
wire shift_32; |
wire [65:0] add_q; |
|
// The central adder : the subtraction needs 3 Guard-Bits after LSB for correct rounding |
assign result = {1'b0,muxsrc2,3'b000} + (addflag ? {12'h0,brshiftf} : {12'hFFF,~brshiftf}) + {67'd0 |
|
assign blshifti = SELECT[1] ? {movif,24'h0} : result[55:0]; // Feeding of MOViL, comes from Registe |
|
assign shiftl = SELECT[1] ? 13'h041E : {1'b0,result[67:56]}; // MOViL |
|
assign shift_32 = (blshifti[55:24] == 32'h0); |
|
// In case of ADD the result bypasses the barrelshifter : LSB of exponent has changed |
assign add_q = (muxsrc2[53] != result[56]) ? {result[67:3],(result[2:0] != 3'b000)} |
: {result[67:56],result[54:2],(result[1:0] != 2'b00)} ; |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 4. Step : Barrelshifter left for SUB and MOViF : |
|
wire shift_16,shift_8,shift_4,shift_2,shift_1,zero; |
wire [1:0] lsb_bl; |
wire [55:0] blshifta,blshiftb,blshiftc,blshiftd,blshifte,blshiftf; |
wire [12:0] expol; |
|
assign blshifta = shift_32 ? {blshifti[23:0],32'h0} : blshifti; |
assign shift_16 = (blshifta[55:40] == 16'h0); |
assign blshiftb = shift_16 ? {blshifta[39:0],16'h0} : blshifta; |
assign shift_8 = (blshiftb[55:48] == 8'h00); |
assign blshiftc = shift_8 ? {blshiftb[47:0],8'h0} : blshiftb; |
assign shift_4 = (blshiftc[55:52] == 4'h0); |
assign blshiftd = shift_4 ? {blshiftc[51:0],4'h0} : blshiftc; |
assign shift_2 = (blshiftd[55:54] == 2'b00); |
assign blshifte = shift_2 ? {blshiftd[53:0],2'b0} : blshiftd; |
assign shift_1 = ~blshifte[55]; |
assign blshiftf = shift_1 ? {blshifte[54:0],1'b0} : blshifte; |
|
// Overflow at ROUNDLi/TRUNCLi/FLOORLi is shown in overflow of exponent , SELECT[1] is then 1 |
assign expol = shiftl - {7'h00,shift_32,shift_16,shift_8,shift_4,shift_2,shift_1}; |
|
// Inexact at ROUNDLi/TRUNCLi/FLOORLi : evaluation for all one level higher |
assign lsb_bl = (SELECT == 2'b11) ? inex : {blshiftf[2],(blshiftf[1:0] != 2'b0)}; |
|
assign zero = (~SELECT[1] & SRCFLAGS[2] & SRCFLAGS[0]) |
| ((blshifti == 56'h0) & ((~addflag & ~SELECT[1]) | (SELECT[1:0] == 2'b10))); |
|
assign sign = SELECT[1] ? sign_movif : (vorz & ~zero); // sign for MOViL |
|
// 2. Pipeline register for ADD , SUB and MOViL |
always @(posedge BCLK) |
outreg <= (addflag & ~SELECT[1]) ? {nan,zero,sign,1'b0,add_q} |
: {nan,zero,sign,expol,blshiftf[54:3],lsb_bl}; |
|
// ++++++++++++++++++++++++++++++++++ |
|
assign OUT = {outreg[69:67],(rovfl ? 2'b01 : outreg[66:65]),outreg[64:0]}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 5. DFPU_MISC Double precision floating point miscellaneous operations |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DFPU_MISC ( BCLK, START, SRC1, SRC2, SRCFLAG, MIMUX, MODE, OUT ); |
|
input BCLK; |
input START; |
input [31:0] SRC1,SRC2; |
input SRCFLAG; |
input MIMUX; |
input [3:0] MODE; |
output [69:0] OUT; |
|
reg [69:0] OUT; |
reg [63:0] daten; |
|
wire [10:0] scalb_l; |
wire nan,zero,sign; |
wire [12:0] lexpo,sexpo; |
wire [69:0] scalb_res,logb_res,fl_lf; |
|
always @(posedge BCLK) if (START) daten <= {(MIMUX ? {daten[31],scalb_l,daten[19:0]}: SRC1),SRC2}; |
|
assign nan = MODE[0] ? (daten[62:55] == 8'hFF) : (daten[62:52] == 11'h7FF); |
assign zero = MODE[0] ? (daten[62:55] == 8'h00) : (daten[62:52] == 11'h000); |
assign sign = daten[63] & ~zero; |
|
assign lexpo = {5'b0,daten[62:55]} + 13'h0380; // -7F + 3FF |
|
assign sexpo = (daten[62:52] > 11'h47E) ? 13'h0FFF |
: ((daten[62:52] < 11'h381) ? 13'h0 : {2'b0,{4{daten[62]}},daten[58:52]}); |
|
assign fl_lf = MODE[0] ? {nan,zero,sign,lexpo,daten[54:32],31'h0} // MOVFL |
: {nan,zero,sign,sexpo,daten[51:29],28'h0,daten[29:28],(daten[27:0] != 28'h0)}; // MOVLF |
|
// +++++++++++++++++++++++++++ LOGBf +++++++++++++++++++++++++++++++++++ |
|
wire logb_null; |
wire [9:0] sel_data,unbiased,shift_l8,shift_l4,shift_l2; |
wire [8:0] shift_l; |
wire posi_8,posi_4,posi_2,posi_1; |
wire [4:0] calc_exp; |
wire [6:0] logb_exp; |
|
assign logb_null = MODE[1] ? (daten[62:55] == 8'h7F) : (daten[62:52] == 11'h3FF); |
|
assign sel_data = MODE[1] ? {{3{~daten[62]}},daten[61:55]} : daten[61:52]; |
assign unbiased = daten[62] ? (sel_data + 10'h001) : ~sel_data; |
|
// detection of leading "1" |
assign posi_8 = (unbiased[9:2] == 8'h00); |
assign shift_l8 = posi_8 ? {unbiased[1:0],8'h00} : unbiased; |
assign posi_4 = (shift_l8[9:6] == 4'h0); |
assign shift_l4 = posi_4 ? {shift_l8[5:0],4'h0} : shift_l8; |
assign posi_2 = (shift_l4[9:8] == 2'b00); |
assign shift_l2 = posi_2 ? {shift_l4[7:0],2'b0} : shift_l4; |
assign posi_1 = ~shift_l2[9]; |
assign shift_l = posi_1 ? {shift_l2[7:0],1'b0} : shift_l2[8:0]; // top bit is hidden "1" |
|
assign calc_exp = 5'h08 - {1'b0,posi_8,posi_4,posi_2,posi_1}; // Minimum is "F" = for exponent +/-1 |
|
// exponent is set one level higher for F and L |
assign logb_exp = MODE[1] ? {{4{~calc_exp[4]}},{3{calc_exp[4]}}} : {~calc_exp[4],{6{calc_exp[4]}}}; |
|
assign logb_res = logb_null ? {70'h10_0000_0000_0000_0000} : {2'b00,~daten[62],2'b00,logb_exp,calc_ |
|
// ++++++++++++++++++++++++ SCALBf ++++++++++++++++++++++++++++++++++ |
|
wire [7:0] scalb_f; |
|
assign scalb_f = SRCFLAG ? 8'h00 : (daten[39:32] + daten[30:23]); |
assign scalb_l = SRCFLAG ? 11'h000 : (daten[42:32] + daten[30:20]); |
|
assign scalb_res = MODE[1] ? // no rounding of Single Data |
{2'b00,daten[31],5'b0,scalb_f,daten[22:0],daten[28:1],3'b000} |
: {2'b00,daten[63],2'b0,daten[62:0],2'b00}; |
|
// ++++++++++++++++++++++++ Output ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
always @(posedge BCLK) OUT <= MODE[3] ? (MODE[2] ? logb_res : scalb_res) : fl_lf ; // LOGB/SCALB : |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 6. DFPU_MUL Double precision floating point multiplier |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DFPU_MUL ( BCLK, SRC1, SRC2, START, MRESULT, SRCFLAGS, OUT ); |
|
input BCLK; |
input [31:0] SRC1,SRC2; |
input START; // that is START[0] |
input [105:0] MRESULT; |
input [5:0] SRCFLAGS; // NAN and ZERO flags |
output [69:0] OUT; // The result |
|
reg [69:0] OUT; |
reg [12:0] exponent; |
wire orlow; |
wire [12:0] expoh,expol; |
wire [1:0] restlow,resthigh; |
wire zero,nan,sign; |
|
assign zero = SRCFLAGS[2] | SRCFLAGS[0]; // one is NULL -> NULL is the result |
assign nan = SRCFLAGS[3] | SRCFLAGS[1]; // one is NAN -> error |
assign sign = (SRCFLAGS[5] ^ SRCFLAGS[4]) & ~zero; |
|
assign orlow = (MRESULT[50:0] != 51'b0); |
|
assign restlow = {MRESULT[51],orlow}; |
assign resthigh = {MRESULT[52],(MRESULT[51] | orlow)}; |
|
always @(posedge BCLK) if (START) exponent <= {2'b00,SRC1[30:20]} + {2'b00,SRC2[30:20]}; |
|
assign expoh = exponent - 13'h03FE; |
assign expol = exponent - 13'h03FF; // for MSB if MRESULT=0 |
|
always @(posedge BCLK) |
OUT <= MRESULT[105] ? {nan,zero,sign,expoh,MRESULT[104:53],resthigh} // 52 Bit Mantissa |
: {nan,zero,sign,expol,MRESULT[103:52],restlow}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 7. DIVI_PREP Prepare data for the divider |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DIVI_PREP (SRC, BWD, NOT_DEI, EXTDATA, DOUT, MSB, NULL, MINUS); |
|
input [31:0] SRC; |
input [1:0] BWD; |
input NOT_DEI; |
input EXTDATA; |
|
output [31:0] DOUT; |
output [4:0] MSB; |
output NULL; |
output MINUS; |
|
reg [31:0] double; |
|
wire [15:0] test_16; |
wire [7:0] test_8; |
wire [3:0] test_4; |
wire [1:0] test_2; |
wire bit_4,bit_3,bit_2,bit_1,bit_0; |
wire [1:0] modus; |
|
assign modus = (NOT_DEI | EXTDATA) ? BWD : {(BWD[1] | BWD[0]),1'b1}; |
|
always @(modus or SRC or NOT_DEI) |
casex (modus) |
2'b00 : double = {{24{SRC[7] & NOT_DEI}},SRC[7:0]}; |
2'b01 : double = {{16{SRC[15] & NOT_DEI}},SRC[15:0]}; |
2'b1x : double = SRC; |
endcase |
|
assign MINUS = double[31] & NOT_DEI; |
|
assign DOUT = ({32{MINUS}} ^ double) + {31'h0,MINUS}; // assign DOUT = MINUS ? (32'd0 - double) : d |
|
// now find most significant set bit : FFS |
|
assign bit_4 = (DOUT[31:16] != 16'h0); |
assign test_16 = bit_4 ? DOUT[31:16] : DOUT[15:0]; |
assign bit_3 = (test_16[15:8] != 8'h0); |
assign test_8 = bit_3 ? test_16[15:8] : test_16[7:0]; |
assign bit_2 = (test_8[7:4] != 4'h0); |
assign test_4 = bit_2 ? test_8[7:4] : test_8[3:0]; |
assign bit_1 = (test_4[3:2] != 2'b0); |
assign test_2 = bit_1 ? test_4[3:2] : test_4[1:0]; |
assign bit_0 = test_2[1]; |
assign NULL = (test_2 == 2'b00); |
|
assign MSB = {bit_4,bit_3,bit_2,bit_1,bit_0}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 8. DFPU_DIV The divider for all divide opcodes : double, single and integer |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DFPU_DIV ( BCLK, BRST, START, SRC1, SRC2, MAN1, MAN2, SRCFLAGS, FL, BWD, OPCODE, OUT, DONE, D |
|
// This version needs for Double 28+1 cycles if MAN1<MAN2 otherwise 28+2. |
// For Single it needs 13+1 cyckes or 13+2. |
|
input BCLK,BRST; |
input [3:0] START; // START & recognized Divider Operation |
input [31:0] SRC1,SRC2; // input data |
input [20:0] MAN1,MAN2; |
input [5:0] SRCFLAGS; // NAN and ZERO |
input FL; |
input [1:0] BWD; |
input [2:0] OPCODE; // for all DIVi variants |
|
output [69:0] OUT; // the result |
output reg DONE; // Pipeline-Flag |
output [63:0] DIVI_OUT; // for Integer Division |
output DVZ_TRAP; // Divide by Zero Trap |
output [1:0] DEI_OVF; // DEI Overflow |
|
// ++++++++++++++ for Integer Division ++++++++++++++ |
reg run_divi; |
reg divi_pipe1,divi_pipe2,divi_pipe3,divi_pipe4; |
reg neg_src1,neg_src2,nul_src2; |
reg [4:0] msb_src1; |
reg [5:0] msb_src2; |
reg [31:0] ivalue,src2_reg,pipe_reg; |
reg [4:0] divi_counter; |
reg sub_case; |
reg negativ; |
reg [32:0] divi_result; |
reg [63:0] DIVI_OUT; |
reg DVZ_TRAP,dvz_pipe; |
reg sel_in; |
reg [62:0] din_mux; |
reg dei_pipe; |
reg extdata; // extended data : 2 data packets, only apply to DEI |
reg [2:0] addoff; |
reg next_msb2; |
reg [31:0] dei_result; |
reg [1:0] DEI_OVF; |
|
wire [31:0] i_in; |
wire [37:0] i_out; |
wire [6:0] diff_msb; |
wire [5:1] shift_r; |
wire [62:0] shift_2; |
wire [62:0] shift_4; |
wire [62:0] shift_8; |
wire [62:0] shift_16; |
wire [64:0] shift_32; |
wire stop_divi,neg_flag; |
wire rest_null,plus_1,ist_null; |
wire not_dei; |
wire valdata; // Data <> 0 at DEI |
|
// ++++++++++++++ Floating Point & calculation path ++++++++ |
reg [69:0] OUT; |
reg [32:0] save1; |
reg runflag; |
reg [55:0] dreimal; |
reg [56:0] divreg,divsr; |
reg [31:0] divreg_ext; |
reg [12:0] exponent; |
|
wire load_src1,load_src2; |
wire [56:0] sub1,sub2,sub3; |
wire [32:0] src_1; |
wire [20:0] man_1; |
wire [12:0] expoh,expol,offset; |
wire restlsb,restlow,resthigh; |
wire zero,nan,sign,ende; |
wire orlow_s,orlow_d; |
wire short; |
|
// +++++++++++++++++++++++++++ Integer Division, DEI +++++++++++++++++++++++++++ |
|
assign not_dei = OPCODE[2]; // 0 = DEI |
always @(posedge BCLK) if (START[3]) extdata <= ~START[1]; // during START[0] for SRC1 not valid |
|
always @(posedge BCLK or negedge BRST) |
if (!BRST) run_divi <= 1'b0; |
else |
run_divi <= (START[3] & ~ist_null) | (~divi_pipe4 & run_divi); // Abort at DVZ Trap |
|
always @(posedge BCLK) divi_pipe1 <= START[3] & ~ist_null; // no start if SRC1 = 0 : DVZ Trap |
always @(posedge BCLK) dei_pipe <= divi_pipe1 & extdata; |
always @(posedge BCLK) divi_pipe2 <= extdata ? dei_pipe : divi_pipe1; |
|
always @(posedge BCLK) src2_reg <= SRC2; |
|
always @(posedge BCLK) sel_in <= START[3] | divi_pipe1; // two times data for DEI |
assign i_in = sel_in ? src2_reg : SRC1; |
|
DIVI_PREP prep_inst ( .SRC(i_in), .BWD(BWD), .NOT_DEI(not_dei), .EXTDATA(extdata | START[0]), |
.DOUT(i_out[31:0]), .MSB(i_out[36:32]), .NULL(ist_null), .MINUS(i_out[37]) ); |
|
always @(posedge BCLK) dvz_pipe <= START[3] & ist_null; // Pulse 1 cycle long |
always @(posedge BCLK) DVZ_TRAP <= dvz_pipe; // one cycle later if DEI with extdata |
|
always @(posedge BCLK) |
if (START[3]) |
begin |
neg_src1 <= i_out[37]; |
msb_src1 <= i_out[36:32]; |
end |
|
always @(posedge BCLK) |
if (divi_pipe1) |
begin |
nul_src2 <= ist_null; |
neg_src2 <= i_out[37]; |
end |
|
always @(posedge BCLK) ivalue <= i_out[31:0]; |
|
// The following is only for DEI : |
always @(posedge BCLK) pipe_reg <= {32{extdata}} & ivalue; // Register must be 0 if not used |
|
assign valdata = extdata & ~ist_null; |
always @(BWD or valdata) |
casex (BWD) |
2'b00 : addoff = { 1'b0, 1'b0,valdata}; |
2'b01 : addoff = { 1'b0,valdata, 1'b0}; |
default : addoff = {valdata, 1'b0, 1'b0}; |
endcase |
|
always @(posedge BCLK) next_msb2 <= extdata & ist_null & divi_pipe1; // Special case at DEI : MSD = |
|
always @(posedge BCLK) |
if (divi_pipe1) msb_src2 <= {addoff[2],(addoff[1:0] | i_out[36:35]),i_out[34:32]}; |
else |
if (next_msb2) msb_src2 <= {1'b0,i_out[36:32]}; |
|
// Shifter for Source2 |
|
assign diff_msb = {1'b0,msb_src2} - {2'b0,msb_src1}; |
|
// negativ shift limited to 0 : Source2=0 calculated without special handling, result always 0 |
assign shift_r = diff_msb[6] ? 5'd0 : diff_msb[5:1]; // LSB does not count |
|
always @(BWD or extdata or ivalue or pipe_reg) |
casex ({BWD,extdata}) |
3'b0x0 : din_mux = {31'b0,ivalue}; // the normal case for all except DEI |
3'b001 : din_mux = {23'b0,pipe_reg,ivalue[7:0]}; |
3'b011 : din_mux = {15'b0,pipe_reg,ivalue[15:0]}; |
default : din_mux = {pipe_reg[30:0],ivalue}; // 63 Bit wide |
endcase |
|
assign shift_2 = shift_r[1] ? din_mux : {din_mux[60:0], 2'b0}; |
assign shift_4 = shift_r[2] ? shift_2 : {shift_2[58:0], 4'b0}; |
assign shift_8 = shift_r[3] ? shift_4 : {shift_4[54:0], 8'b0}; |
assign shift_16 = shift_r[4] ? shift_8 : {shift_8[46:0],16'b0}; // Result is 63 Bit wide |
|
// 65 Bit result because of DEI |
assign shift_32 = shift_r[5] ? {1'b0,pipe_reg,ivalue} : {shift_16,2'b00}; // special case DEI : 32 |
|
always @(posedge BCLK or negedge BRST) // Flag for rounding, only if DEST <>0 |
if (!BRST) divi_pipe3 <= 1'b0; |
else |
divi_pipe3 <= divi_pipe2 | (divi_pipe3 & ~stop_divi); |
|
always @(posedge BCLK) |
if (divi_pipe2) divi_counter <= shift_r; |
else divi_counter <= divi_counter - {4'b000,~stop_divi}; // should stop at 0 |
|
assign stop_divi = (divi_counter == 5'h0); // caclulation ready |
|
always @(posedge BCLK) divi_pipe4 <= divi_pipe3 & stop_divi; |
|
assign neg_flag = neg_src1 ^ neg_src2; |
assign rest_null = (divreg[33:2] == 32'h0); |
|
always @(posedge BCLK) sub_case <= neg_flag & ~nul_src2; // little help for MODi opcode |
|
// Result preparation : |
// DEST SRC QUO REM / DIV MOD |
// +33 +13 : 2 7 / 2 7 |
// +33 -13 : -2 7 / -3 -6 |
// -33 +13 : -2 -7 / -3 6 |
// -33 -13 : 2 -7 / 2 -7 |
always @(*) |
case (OPCODE[1:0]) |
2'b00 : divi_result = {neg_flag,divsr[31:0]}; // QUO |
2'b01 : divi_result = {neg_src2,divreg[33:2]}; // REM |
2'b10 : divi_result = {neg_src1,((sub_case & ~rest_null) ? (save1[31:0] - divreg[33:2]) : divreg |
2'b11 : divi_result = {neg_flag,divsr[31:0]}; // DIV |
endcase |
|
always @(posedge BCLK) negativ <= divi_result[32]; |
|
assign plus_1 = (OPCODE[1:0] == 2'b11) ? (negativ & rest_null) : negativ; // Special case Rest=0 at |
|
always @(posedge BCLK) |
if (divi_pipe4) DIVI_OUT[63:32] <= not_dei ? (({32{negativ}} ^ divi_result[31:0]) + {31'd0,plus_1} |
|
always @(posedge BCLK) if (divi_pipe4) DIVI_OUT[31:0] <= divreg[33:2]; |
|
always @(extdata or BWD or divsr or divreg) |
casex ({extdata,BWD}) |
3'b000 : dei_result = {16'hxxxx,divsr[7:0],divreg[9:2]}; |
3'b001 : dei_result = {divsr[15:0],divreg[17:2]}; |
default : dei_result = divsr[31:0]; |
endcase |
|
// +++++++++++++++++++++++++++ Calculation path for Division ++++++++++++++++++++++++++++ |
|
always @(posedge BCLK or negedge BRST) |
if (!BRST) runflag <= 1'b0; |
else |
runflag <= START[2] | (~ende & runflag); |
|
always @(posedge BCLK) DONE <= (ende & runflag) | divi_pipe4; |
|
assign man_1 = (FL | run_divi) ? 21'h0 : MAN1; |
assign src_1 = run_divi ? {1'b0,ivalue} : ( FL ? {10'h001,SRC1[22:0]} : {SRC1,1'b0}); |
|
assign load_src1 = START[2] | divi_pipe1; |
|
// *2 + *1 |
always @(posedge BCLK) if (load_src1) dreimal <= {1'b0,man_1,src_1,1'b0} + {2'b00,man_1,src_1}; // |
|
always @(posedge BCLK) if (load_src1) save1 <= src_1; |
|
assign sub1 = divreg - {3'b000, man_1,save1 }; |
assign sub2 = divreg - {2'b00 ,man_1,save1,1'b0}; |
assign sub3 = divreg - {1'b0, dreimal }; |
|
assign load_src2 = START[2] | divi_pipe2; |
|
always @(posedge BCLK) |
if (load_src2) divreg <= divi_pipe2 ? {23'h0,shift_32[64:32]} : ( FL ? {34'h0_0000_0001,SRC2[22:0] |
else |
begin |
casex ({sub3[56],sub2[56],sub1[56]}) |
3'b0xx : divreg <= {sub3[54:0],divreg_ext[31:30]}; |
3'b10x : divreg <= {sub2[54:0],divreg_ext[31:30]}; |
3'b110 : divreg <= {sub1[54:0],divreg_ext[31:30]}; |
default : divreg <= {divreg[54:0],divreg_ext[31:30]}; |
endcase |
end |
|
always @(posedge BCLK) // Extension Register for Integer Division |
if (load_src2) divreg_ext <= divi_pipe2 ? shift_32[31:0] : 32'd0; |
else |
divreg_ext <= {divreg_ext[29:0],2'b0}; |
|
always @(posedge BCLK) |
if (load_src2) divsr <= 57'h0; |
else |
begin |
casex ({sub3[56],sub2[56],sub1[56]}) |
3'b0xx : divsr <= {divsr[54:0],2'b11}; |
3'b10x : divsr <= {divsr[54:0],2'b10}; |
3'b110 : divsr <= {divsr[54:0],2'b01}; |
default : divsr <= {divsr[54:0],2'b00}; |
endcase |
end |
|
// Overflow Detection for DEI : serial calculation |
always @(posedge BCLK) |
if (load_src2) DEI_OVF[0] <= 1'b0; |
else DEI_OVF[0] <= DEI_OVF[0] | (BWD[1] ? |divsr[33:32] : (BWD[0] ? |divsr[17:16] : |divsr[9:8]) |
|
always @(posedge BCLK) DEI_OVF[1] <= divi_pipe4; // Timing pulse for OVF inclusiv for DIV and QUO |
|
assign short = (SRCFLAGS[3:0] != 4'h0) & runflag; |
|
assign ende = ((FL ? (divsr[26] | divsr[25]) : (divsr[56] | divsr[55])) & runflag) | short; |
|
assign sign = (SRCFLAGS[4] ^ SRCFLAGS[5]) & ~zero; |
assign zero = SRCFLAGS[2] & ~SRCFLAGS[0]; // SRC2 = NULL -> NULL as result |
assign nan = SRCFLAGS[3] | SRCFLAGS[1] | (SRCFLAGS[2] & SRCFLAGS[0]); |
// one of both NAN or both 0 -> invalid Operation |
|
assign orlow_d = (divreg[56:27] != 29'b0) & ~zero & ~FL; // is there Rest ? [1:0] are always 0. |
assign orlow_s = (divreg[26:2] != 25'b0) & ~zero; |
|
assign restlsb = divsr[0] | orlow_s; |
assign restlow = (divsr[1:0] != 2'b00) | orlow_s | orlow_d; |
assign resthigh = divsr[2] | restlow; |
|
always @(posedge BCLK) if (START[0]) exponent <= FL ? ({5'b00,SRC2[30:23]} - {5'b00,SRC1[30:23]}) |
: ({2'b00,SRC2[30:20]} - {2'b00,SRC1[30:20]}); |
assign offset = FL ? 13'h007E : 13'h03FE; |
assign expoh = exponent + {offset[12:1],1'b1}; // Double = 3FF/3FE Single = 7F/7E |
assign expol = exponent + offset; // in case of normalizing |
|
always @(posedge BCLK) |
if (ende && runflag) |
casex ({FL,divsr[26],divsr[56]}) |
3'b11x : OUT <= {nan,zero,sign,expoh[9:8],expoh[7],expoh[7],expoh[7],expoh[7:0],divsr[25:3],28'b |
3'b10x : OUT <= {nan,zero,sign,expol[9:8],expol[7],expol[7],expol[7],expol[7:0],divsr[24:2],28'b |
3'b0x1 : OUT <= {nan,zero,sign,expoh,divsr[55:3],resthigh}; |
3'b0x0 : OUT <= {nan,zero,sign,expol,divsr[54:2],restlow}; |
endcase |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 9. DP_LOGIK Control logic and result path for different functions |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DP_LOGIK ( BCLK, BRESET, OPCODE, SRC1, SRC2, FSR, START, MRESULT, BWD, FL, MAN1, MAN2, WR_REG |
COP_DONE, COP_OP, COP_IN, |
DOUT, TT_DP, DP_CMP, OVF_BCD, MEI, DFLOAT, DONE, UP_DP, CLR_LSB, WREN_L, LD_OUT_L, DVZ_TRAP, C |
|
// Definition of output word OUT of sub-moduls : the hidden-bit of the mantissa is already gone |
// |
// N Z S Exponent Mantissa Round |
// A E I Double : 13 Bit 52 Bit 2 Bit |
// N R G Single : 10 Bit 23 Bit 2 Bit |
// O N -mmmm.mmmm.mmmm.mmmm.mmmm.mmm-.-- -m. |
// -F-F-F-E.EEEE.EEEE.EEEE-MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.MMMM.RR |
// |
// 6 6 6 6 6666 6655 5555 5555 4444 4444 4433 3333 3333 2222 2222 2211 1111 1111 0000 0000 00 |
// 9 8 7 6 5432 1098 7654 3210 9876 5432 1098 7654 3210 9876 5432 1098 7654 3210 9876 5432 10 |
// |
// Single FP delivers the exponent in a way, that it is identical for rounding : |
// |
// Exponent 61 - 54 => kept |
// Bits 64 - 62 are filled with bit 61 , carry should come through |
// Exponent 62 => Bit 65 , Overflow |
// Exponent 63 => Bit 66 , Underflow |
|
input BCLK,BRESET; |
input [7:0] OPCODE; |
input [31:0] SRC1,SRC2; // the input data |
input [20:0] MAN1,MAN2; // the MSB of mantissa |
input [8:3] FSR; // Floating Point Status Register |
input [1:0] START; |
input [105:0] MRESULT; // Result of multiplier |
input [1:0] BWD; // Size of integer |
input FL; |
input WR_REG; // from DECODER |
input CY_IN; |
input COP_DONE; // Coprozessor Interface |
input [23:0] COP_OP; |
input [63:0] COP_IN; |
|
output [63:0] DOUT; |
output [4:0] TT_DP; // Trap-Info to FSR |
output [2:0] DP_CMP; // CMPL result |
output [3:0] OVF_BCD; // Integer Division Overflow + BCD Carry update |
output MEI,DFLOAT; |
output DONE,UP_DP; |
output CLR_LSB,WREN_L,LD_OUT_L; |
output DVZ_TRAP; |
output reg COP_GO; |
|
reg [63:0] DOUT; |
reg CLR_LSB; |
reg [2:0] DP_CMP; |
reg [5:0] preflags; |
reg [5:0] srcflags; |
reg [69:0] fpout; |
reg [2:0] tt; |
reg [6:0] select; |
reg [4:0] wctrl; |
reg [2:1] sequ; |
reg misc_op; |
reg misc_mux; |
reg car_ry; |
reg wr_part2; |
reg up_flag; |
reg ovf_div; |
|
wire zexp2,zman2,zexp1,zman1,znan1; |
wire make_i; |
wire scalbl,go_misc; |
wire op_cmp; |
wire [69:0] mulout,addout,divout,miscout; |
wire go_divf,go_divi,divi_ops,div_done; |
wire bcd_ops,man_ops; |
wire [31:0] i_out; |
wire [63:0] divi_out; |
wire [66:2] rund,cy_val; // Indexnumber like in xxxout |
wire div_zero,overflow,underflow,inexact; |
wire [1:0] cmpres; |
wire [63:0] fp_out,fp_res; |
wire wr_part1; |
wire done_i; |
wire [31:0] bcd_q; |
wire bcd_done; |
wire bcd_carry; |
wire [1:0] dei_ovf; |
wire quo_div; |
wire copop; |
wire copwr; |
|
// Control of datapath : together with START the Double Unit becomes activ |
|
always @(OPCODE or FL) |
casex (OPCODE) |
8'b1001_000x : select = 7'b00_01010; // 0 1 0 : MOViL |
8'b1001_010x : select = 7'b10_11000; // MOVLF |
8'b1001_011x : select = 7'b01_11000; // MOVFL |
8'b1001_100x : select = 7'b10_01011; // 0 1 1 : ROUNDLi |
8'b1001_101x : select = 7'b10_01011; // 0 1 1 : TRUNCLi |
8'b1001_111x : select = 7'b10_01011; // 0 1 1 : FLOORLi |
8'b1011_0000 : select = 7'bxx_01000; // 0 0 0 : ADDL |
8'b1011_0010 : select = 7'bxx_01001; // 0 0 1 : CMPL |
8'b1011_0100 : select = 7'bxx_01001; // 0 0 1 : SUBL |
8'b1011_1000 : select = 7'b11_01100; // 1 0 1 : DIVf , Default Float for srcflags |
8'b1011_1100 : select = 7'bxx_01100; // 1 0 0 : MULL |
8'b1011_0110 : select = 7'b11_11000; // SCALBf , Default Float for srcflags |
8'b1011_0111 : select = {~FL,FL,5'b11000}; // LOGBf |
default : select = 7'b0; |
endcase |
|
assign MEI = (OPCODE == 8'h79); |
assign divi_ops = (OPCODE[7:2] == 6'b0111_11) | (OPCODE == 8'h7B); // QUO/REM/MOD/DIV & DEI |
assign go_divf = (OPCODE == 8'hB8) & START[1]; // because of runflag in DIV Unit |
assign go_divi = divi_ops & (OPCODE[2] ? START[1] : START[0]); // DEI starts with START[0] |
assign bcd_ops = (OPCODE == 8'h6F) | (OPCODE == 8'h6B); // ADDP , SUBP |
|
assign man_ops = (OPCODE == 8'hB1) | (OPCODE == 8'hB5) | (OPCODE == 8'hB9) | (OPCODE == 8'hBD); // |
|
assign DFLOAT = (select[3] | copop) & ~FL; // all Double Floating Point Operations for PREPDATA |
assign make_i = (select[2:0] == 3'b011) | divi_ops | bcd_ops; // ROUND/TRUNC/FLOOR for output mul |
assign op_cmp = (OPCODE == 8'hB2) & ~FL; |
always @(posedge BCLK) misc_op <= select[4]; // for OUT-Multiplexer |
|
assign copop = (OPCODE == 8'hDD); |
assign copwr = (COP_OP[18:17] == 2'd0) & (COP_OP[13:11] == 3'b111) & (COP_OP[7:5] == 3'b001); // Cu |
|
// very special solution for SCALBL |
assign scalbl = START[0] & ~FL & (OPCODE == 8'hB6); |
assign go_misc = START[1] | scalbl; |
always @(posedge BCLK) misc_mux <= scalbl; // switches at START[1] the input multiplexer |
|
// SRCFLAGS : special handling for operands is done locally |
|
assign zexp2 = (SRC2[30:20] == 11'd0); |
assign zman2 = (SRC2[19:0] == 20'd0); |
assign zexp1 = (SRC1[30:20] == 11'd0); |
assign zman1 = (SRC1[19:0] == 20'd0); |
assign znan1 = (SRC1[30:20] == 11'h7FF); |
|
always @(posedge BCLK) |
if (START[0]) |
begin |
srcflags[5] <= SRC2[31]; |
srcflags[4] <= SRC1[31]; |
preflags <= {(SRC2[30:20] == 11'h7FF),zexp2,zman2,znan1,zexp1,zman1}; |
end |
|
// case Definition : 00 : 0 , if START[i]=0 then there are always 2 long operands |
// 01 : 1 Float Operand SCR1 |
// 10 : 1 Long Operand SRC1+SRC2 |
// 11 : 2 Float Operands SRC1 , SRC2 |
|
always @(posedge BCLK) // NaN |
if (START[1]) |
casex ({START[0],select[6:5]}) |
3'b0xx : srcflags[3] <= preflags[5] | (preflags[4] & (~preflags[3] | SRC2[31] | ~zexp2 | ~zman |
3'b111 : srcflags[3] <= (SRC2[30:23] == 8'hFF) | ((SRC2[30:23] == 8'd0) & ((SRC2[22:20] != 3'd |
default : srcflags[3] <= 1'b0; |
endcase |
|
always @(posedge BCLK) // Zero : only exponent ! If denormalized => NaN ! |
if (START[0]) |
casex ({START[1],select[6:5]}) |
3'b0xx : srcflags[2] <= zexp2; // L:(SRC1,SRC2) = Zero , SRC1 = MSB |
3'b111 : srcflags[2] <= (SRC2[30:23] == 8'd0); // F:SRC2 = Zero |
default : srcflags[2] <= 1'b0; |
endcase |
|
always @(posedge BCLK) // NaN |
if (START[1]) |
casex ({START[0],select[6:5]}) |
3'b0xx : srcflags[1] <= preflags[2] | (preflags[1] & (~preflags[0] | SRC1[31] | ~zexp1 | ~zman |
3'b1x1 : srcflags[1] <= (SRC1[30:23] == 8'hFF) | ((SRC1[30:23] == 8'd0) & ((SRC1[22:20] != 3'd |
3'b110 : srcflags[1] <= znan1 | (zexp1 & (~zman1 | SRC2[31] | ~zexp2 | ~zman2)); // L:(SRC1,SR |
default : srcflags[1] <= 1'b0; |
endcase |
|
always @(posedge BCLK) // Zero : only exponent ! If denormalized => NaN ! |
if (START[0]) |
casex ({START[1],select[6:5]}) |
3'b0xx : srcflags[0] <= zexp1; // L:(SRC1,SRC2) = Zero , SRC1 = MSB |
3'b1x1 : srcflags[0] <= (SRC1[30:23] == 8'd0); // F:SRC1 = Zero |
3'b110 : srcflags[0] <= zexp1; // L:(SRC1,SRC2) = Zero , SRC1 = MSB |
default : srcflags[0] <= 1'b0; |
endcase |
|
// The Sub-moduls : |
|
DFPU_ADDSUB as_inst ( .BCLK(BCLK), .START(START), .SRC1(SRC1), .SRC2(SRC2), |
.MAN1({~srcflags[0],MAN1[19:0]}), .MAN2({~srcflags[2],MAN2[19:0]}), |
.SRCFLAGS(srcflags), .BWD(BWD), .SELECT({OPCODE[2:1],select[1:0]}), |
.OUT(addout), .IOUT(i_out), .CMPRES(cmpres) ); |
|
DFPU_MUL mul_inst ( .BCLK(BCLK), .SRC1(SRC1), .SRC2(SRC2), .START(START[0]), .MRESULT(MRESULT), |
.OUT(mulout), .SRCFLAGS(srcflags) ); |
|
DFPU_DIV div_inst ( .BCLK(BCLK), .BRST(BRESET), .START({go_divi,go_divf,START}), .SRC1(SRC1), .SRC2 |
.MAN1(MAN1), .MAN2(MAN2), .SRCFLAGS(srcflags), .FL(FL), .OUT(divout), .DONE(div_done), |
.BWD(BWD), .OPCODE(OPCODE[2:0]), .DIVI_OUT(divi_out), .DVZ_TRAP(DVZ_TRAP), .DEI_OVF(dei_ovf) |
|
DFPU_MISC misc_inst ( .BCLK(BCLK), .START(go_misc), .SRC1(SRC1), .SRC2(SRC2), .SRCFLAG(srcflags[2]) |
.MIMUX(misc_mux), .MODE({OPCODE[5],OPCODE[0],FL,OPCODE[1]}), .OUT(miscout) ); |
|
DFPU_BCD bcd_inst ( .BCLK(BCLK), .BRESET(BRESET), .START(START[1]), .DO_BCD(bcd_ops), .BWD(BWD), .S |
.CY_IN(CY_IN), .SUBP(~OPCODE[2]), .BCD_Q(bcd_q), .CY_OUT(bcd_carry), .BCD_DONE(bcd_done) ); |
|
// FP - path : selection of result and rounding : |
|
always @(misc_op or OPCODE or mulout or addout or divout or miscout) |
casex ({misc_op,OPCODE[5],OPCODE[3:2]}) //OPCODE[5] only for Flags i.e. NAN |
4'b1xxx : fpout = miscout; // for MOVLF,MOVFL,SCALB & LOGB |
4'b0110 : fpout = divout; |
4'b0111 : fpout = mulout; |
default : fpout = addout; |
endcase |
|
always @(FSR or fpout) // Calculation of Carry according to rounding mode, fpout[67] = sign bit |
casex (FSR[8:7]) |
2'b00 : car_ry = ((fpout[1:0] == 2'b10) & fpout[2]) | (fpout[1:0] == 2'b11); // round to nearest |
2'b10 : car_ry = ~fpout[67] & (fpout[1:0] != 2'b00); // round to positiv infinity |
2'b11 : car_ry = fpout[67] & (fpout[1:0] != 2'b00); // round to negativ infinity |
default : car_ry = 1'b0; // round to zero |
endcase |
|
assign cy_val = {35'h0,(FL & car_ry),28'h0,(~FL & car_ry)}; |
|
assign rund = {fpout[66:2]} + cy_val; |
|
// Detection of Div-by-0, Overflow, Underflow and Inexact : Epxonent from [66:54] = 13 Bits |
assign div_zero = (srcflags[3:0] == 4'h1) & (OPCODE == 8'hB8); // true FPU Divide by Zero |
assign overflow = ~rund[66] & (rund[65] | (rund[64:54] == 11'h7FF)); |
assign underflow = (rund[66] | (rund[65:54] == 12'h0)) & ~fpout[68]; // Zero-Flag |
assign inexact = (fpout[1:0] != 2'b00); |
|
always @(fpout or op_cmp or div_zero or overflow or underflow or inexact or FSR) |
casex ({fpout[69],op_cmp,div_zero,overflow,FSR[3],underflow,FSR[5],inexact}) // [69] = NAN |
8'b1xxxxxxx : tt = 3'b101; // Invalid operation |
8'b001xxxxx : tt = 3'b011; // Divide by Zero |
8'b0001xxxx : tt = 3'b010; // Overflow |
8'b000011xx : tt = 3'b001; // Underflow |
8'b00000011 : tt = 3'b110; // Inexact Result |
default : tt = 3'b000; // no error |
endcase |
|
assign TT_DP = man_ops ? 5'd0 : {(inexact & ~op_cmp),(underflow & ~op_cmp),tt}; // at ABSf/NEGf no |
|
assign fp_res = FL ? {fpout[67],rund[61:31],rund[33:2]} |
: {fpout[67],rund[64:2]}; // lower 32 bits identical |
|
// Underflow special case and get ZERO |
assign fp_out = (underflow | fpout[68]) ? 64'h0 : fp_res; |
|
// 63..32 goes to memory if Word or Byte ! Also in ODD Register , 31..0 goes in EVEN Register |
// DEI comes without WR_REG information |
always @(make_i or copop or MEI or BWD or WR_REG or MRESULT or COP_IN or i_out or fp_out or divi_op |
casex ({make_i,copop,MEI,BWD}) |
5'b00100 : DOUT = {MRESULT[31:8], (WR_REG ? MRESULT[15:8] : MRESULT[7:0]), MRESULT[31:0]}; // L |
5'b00101 : DOUT = {MRESULT[31:16],(WR_REG ? MRESULT[31:16] : MRESULT[15:0]),MRESULT[31:0]}; |
5'b0011x : DOUT = MRESULT[63:0]; |
5'b01xxx : DOUT = COP_IN; // true alignment in Coprocessor |
5'b1xxxx : DOUT = divi_ops ? divi_out : {(bcd_ops ? bcd_q : i_out),fp_out[31:0]}; // MSD is writ |
default : DOUT = fp_out; |
endcase |
|
always @(posedge BCLK) DP_CMP <= {(srcflags[3] | srcflags[1]),cmpres}; // Only valid if not NaN |
|
// Pipeline Control + Registerfile write control |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) sequ <= 2'b00; |
else |
sequ <= {(sequ[1] & ~DONE),START[1]}; |
|
always @(FL or OPCODE or copwr) |
casex ({FL,OPCODE}) // WRITE Control : [2] = clr_lsb, [1] = wr_part2, [0] = wr_part1 |
9'bx_1001_000x : wctrl = 5'b01_111; // MOViL |
9'bx_1001_010x : wctrl = 5'b00_010; // MOVLF |
9'bx_1001_011x : wctrl = 5'b01_111; // MOVFL |
9'bx_1001_100x : wctrl = 5'b00_010; // ROUNDLi - DONE is one cycle earlier for this opcodes |
9'bx_1001_101x : wctrl = 5'b00_010; // TRUNCLi |
9'bx_1001_111x : wctrl = 5'b00_010; // FLOORLi |
9'bx_1011_0000 : wctrl = 5'b01_111; // ADDL |
9'bx_1011_0010 : wctrl = 5'b00_000; // CMPL - via LD one cycle later in PSR |
9'bx_1011_0100 : wctrl = 5'b01_111; // SUBL |
9'b1_1011_1000 : wctrl = 5'b10_001; // DIVF - measured 18 cycles Reg-Reg |
9'b0_1011_1000 : wctrl = 5'b10_111; // DIVL - measured 34 cycles Reg-Reg |
9'bx_1011_1100 : wctrl = 5'b01_111; // MULL |
9'bx_0110_1x11 : wctrl = 5'b10_001; // ADDP,SUBP |
9'bx_0111_1001 : wctrl = 5'b00_111; // MEIi |
9'bx_0111_1011 : wctrl = 5'b10_111; // DEIi |
9'bx_0111_11xx : wctrl = 5'b10_001; // QUOi,REMi,MODi,DIVi |
9'b1_1011_011x : wctrl = 5'b00_010; // SCALBF/LOGBF |
9'b0_1011_011x : wctrl = 5'b01_111; // SCALBL/LOGBL |
9'bx_1101_1101 : wctrl = {4'b10_00,copwr}; // execute coprocessor opcode |
default : wctrl = 5'b0; |
endcase |
|
assign done_i = wctrl[4] ? (div_done | bcd_done | COP_DONE) : ( (wctrl[3] | ~WR_REG) ? sequ[2] : se |
assign DONE = ~START[1] & done_i; // DONE is valid for all opcodes |
|
assign wr_part1 = DONE & WR_REG & wctrl[0]; |
|
always @(posedge BCLK) CLR_LSB <= DONE & WR_REG & wctrl[2]; |
always @(posedge BCLK) wr_part2 <= DONE & WR_REG & wctrl[1]; |
|
assign WREN_L = wr_part1 | wr_part2; |
assign LD_OUT_L = DONE & ~WR_REG; // meaning is "Load Out-Reg from Long-Path" |
|
always @(posedge BCLK) up_flag <= DONE & ~wctrl[0]; // DONE one cycle later |
assign UP_DP = (select[3] & (wctrl[0] ? DONE : up_flag)) | man_ops; // Update FSR Trap etc. : al |
|
// Overflow Trap for Division : DEI, QUO, DIV |
assign quo_div = (OPCODE == 8'h7C) | (OPCODE == 8'h7F); |
always @(*) |
casex ({OPCODE[2],BWD}) |
3'b100 : ovf_div = (divi_out[39] & SRC1[7] & SRC2[7] ) & quo_div; |
3'b101 : ovf_div = (divi_out[47] & SRC1[15] & SRC2[15]) & quo_div; |
3'b11x : ovf_div = (divi_out[63] & SRC1[31] & SRC2[31]) & quo_div; |
default : ovf_div = dei_ovf[0] & (OPCODE == 8'h7B); // DEI |
endcase |
|
assign OVF_BCD = {dei_ovf[1],ovf_div,bcd_done,bcd_carry}; // to I_PFAD |
|
always @(posedge BCLK) COP_GO <= START[1] & copop; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 10. DP_FPU Top level of long operations datapath |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DP_FPU( BCLK, FL, BRESET, LD_LDQ, WR_REG, BWD, FSR, OPCODE, SRC1, SRC2, START, DONE, UP_DP, W |
CLR_LSB, LD_OUT_L, DVZ_TRAP, DP_CMP, DP_OUT, DP_Q, TT_DP, CY_IN, OVF_BCD, COP_GO, COP_OP, |
COP_IN, COP_DONE, COP_OUT ); |
|
input BCLK; |
input FL; |
input BRESET; |
input LD_LDQ; |
input WR_REG; |
input [1:0] BWD; |
input [8:3] FSR; |
input [7:0] OPCODE; |
input [31:0] SRC1; |
input [31:0] SRC2; |
input [1:0] START; |
input CY_IN; |
input COP_DONE; |
input [23:0] COP_OP; |
input [63:0] COP_IN; |
|
output DONE; |
output UP_DP; |
output WREN_L; |
output CLR_LSB; |
output LD_OUT_L; |
output DVZ_TRAP; |
output [2:0] DP_CMP; |
output [31:0] DP_OUT; |
output [31:0] DP_Q; |
output [4:0] TT_DP; |
output [3:0] OVF_BCD; |
output COP_GO; |
output [127:0] COP_OUT; |
|
reg [52:0] MDA; |
reg [52:0] MDB; |
reg [31:0] DP_Q; |
reg [31:20] RCOPA,RCOPB; |
|
wire [63:0] DOUT; |
wire [105:0] MRESULT; |
wire MEI; |
wire DFLOAT; |
wire LOAD_MSD; |
wire LOAD_LSD1; |
wire LOAD_LSD2; |
wire [31:0] LSD_1; |
wire [31:0] LSD_2; |
wire [52:32] MSD_1; |
wire [52:32] MSD_2; |
|
|
DP_LOGIK DOUBLE_U( |
.FL(FL), |
.BRESET(BRESET), |
.BCLK(BCLK), |
.WR_REG(WR_REG), |
.BWD(BWD), |
.FSR(FSR), |
.MAN1(MDA[52:32]), |
.MAN2(MDB[52:32]), |
.MRESULT(MRESULT), |
.OPCODE(OPCODE), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.START(START), |
.MEI(MEI), |
.DFLOAT(DFLOAT), |
.DONE(DONE), |
.UP_DP(UP_DP), |
.CLR_LSB(CLR_LSB), |
.WREN_L(WREN_L), |
.LD_OUT_L(LD_OUT_L), |
.DVZ_TRAP(DVZ_TRAP), |
.DOUT(DOUT), |
.DP_CMP(DP_CMP), |
.TT_DP(TT_DP), |
.CY_IN(CY_IN), |
.OVF_BCD(OVF_BCD), |
.COP_DONE(COP_DONE), |
.COP_OP(COP_OP), |
.COP_IN(COP_IN), |
.COP_GO(COP_GO)); |
|
PREPDATA DP_PREP( |
.MEI(MEI), |
.DFLOAT(DFLOAT), |
.BWD(BWD), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.START(START), |
.LOAD_LSD1(LOAD_LSD1), |
.LOAD_LSD2(LOAD_LSD2), |
.LOAD_MSD(LOAD_MSD), |
.LSD_1(LSD_1), |
.LSD_2(LSD_2), |
.MSD_1(MSD_1), |
.MSD_2(MSD_2)); |
|
assign MRESULT = MDA * MDB; // unsigned multiplier 53 * 53 bits = 106 bits |
|
assign DP_OUT = CLR_LSB ? DP_Q : DOUT[63:32]; |
|
always@(posedge BCLK) if (LD_OUT_L || LD_LDQ || WREN_L) DP_Q <= LD_LDQ ? SRC2 : DOUT[31:0]; |
|
always@(posedge BCLK) if (LOAD_LSD1) MDA[31:0] <= LSD_1; |
|
always@(posedge BCLK) if (LOAD_LSD2) MDB[31:0] <= LSD_2; |
|
always@(posedge BCLK) |
if (LOAD_MSD) |
begin |
MDA[52:32] <= MSD_1; |
MDB[52:32] <= MSD_2; |
RCOPA <= SRC1[31:20]; |
RCOPB <= SRC2[31:20]; |
end |
|
assign COP_OUT = {RCOPA,MDA[51:32],SRC1,RCOPB,MDB[51:32],SRC2}; |
|
endmodule |
/trunk/rtl/TOP_MISC.v
0,0 → 1,164
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: TOP_MISC.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. IO_SWITCH Switch between ICACHE and DCACHE to IO Path |
// 2. MAKE_STAT Generate Statistic Signals |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. IO_SWITCH Switch between ICACHE and DCACHE to IO Path |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module IO_SWITCH ( BCLK, BRESET, I_IOA, D_IOA, I_IORD, D_IORD, D_IOWR, IO_READY, GENSTAT, D_IOBE, IL |
IO_A, IO_RD, IO_WR, IO_BE, I_IORDY, D_IORDY, STATUS, ILO ); |
|
input BCLK,BRESET; |
input [31:0] I_IOA,D_IOA; |
input I_IORD; |
input D_IORD,D_IOWR; |
input [3:0] D_IOBE; |
input IO_READY; |
input [2:0] GENSTAT; |
input ILO_SIG; |
input [1:0] DCWACC; |
|
output [31:0] IO_A; |
output IO_RD,IO_WR; |
output [3:0] IO_BE; |
output I_IORDY; |
output D_IORDY; |
output [3:0] STATUS; |
output ILO; |
|
reg [3:0] STATUS; |
reg [1:0] select; |
reg ilo_flag; |
|
wire daten; |
wire sel_dp; |
wire interrupt; |
wire ilo_keep; |
|
assign daten = D_IORD | D_IOWR; |
|
// DCACHE has priority. |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) select <= 2'b0; |
else |
casex ({I_IORD,D_IORD,D_IOWR,IO_READY,ilo_keep,select}) |
7'b000xx_00 : select <= 2'b00; |
7'b1000x_00 : select <= 2'b11; |
7'bx100x_00 : select <= 2'b10; |
7'bxx10x_00 : select <= 2'b10; |
// the access has in the same cycle a READY ! |
7'b1001x_00 : select <= 2'b00; |
7'bx101x_00 : select <= 2'b00; |
7'bxx11x_00 : select <= 2'b00; |
// Datea Access |
7'bxxx0x_10 : select <= 2'b10; |
7'bxxx11_10 : select <= 2'b10; // keep because of Interlocked |
7'bxxx10_10 : select <= 2'b00; |
// Instruction Access |
7'bxxx0x_11 : select <= 2'b11; |
7'bxxx1x_11 : select <= 2'b00; |
default : select <= 2'b00; |
endcase |
|
assign sel_dp = (select == 2'b10) | ((select == 2'b00) & daten); |
|
assign IO_RD = sel_dp ? D_IORD : I_IORD; |
assign IO_WR = sel_dp ? D_IOWR : 1'b0; |
assign IO_A = sel_dp ? D_IOA : I_IOA; |
assign IO_BE = sel_dp ? D_IOBE : 4'b1111; // Instruction read always 32 Bit |
|
assign D_IORDY = sel_dp & IO_READY; |
assign I_IORDY = ~sel_dp & IO_READY; |
|
assign interrupt = GENSTAT[1] | GENSTAT[0]; |
|
always @(*) |
casex ({sel_dp,daten,interrupt,I_IORD}) |
4'b110x : STATUS = 4'hA; // Daten |
4'b111x : STATUS = GENSTAT[1] ? 4'h4 : 4'h6; // Int Ack. : End of Int |
4'b0xx1 : STATUS = 4'h8; // Programm |
default : STATUS = {3'd0,GENSTAT[2]}; // WAIT or Inactive |
endcase |
|
// +++++++++++ ILO Control ++++++++++++++++++ |
|
always @(posedge BCLK) |
if (!ILO_SIG) ilo_flag <= 1'b0; // Flag is set at read and cleared with write |
else ilo_flag <= (D_IORD & sel_dp) | DCWACC[0] | ilo_keep; |
|
assign ilo_keep = ilo_flag & ~D_IOWR & ~DCWACC[1]; |
|
assign ILO = ILO_SIG & ((D_IORD & sel_dp) | DCWACC[0] | ilo_flag | D_IOWR | DCWACC[1]); |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. MAKE_STAT Generate Statistic Signals |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module MAKE_STAT ( BCLK, READ, DACC_OK, DC_ACC, DPTE_ACC, DC_MDONE, DRAM_WR, IC_READ, IACC_OK, DATA_ |
IC_ACC, IPTE_ACC, IC_MDONE, KOLLISION, STATSIGS ); |
|
input BCLK; |
input READ,DACC_OK; |
input DC_ACC,DPTE_ACC,DC_MDONE; |
input DRAM_WR; |
input IC_READ,IACC_OK,DATA_HOLD; |
input IC_ACC,IPTE_ACC,IC_MDONE; |
input KOLLISION; |
|
output reg [7:0] STATSIGS; |
|
always @(posedge BCLK) |
begin |
STATSIGS[7] <= KOLLISION; // 7 : from ICACHE : collisions |
STATSIGS[6] <= IPTE_ACC; // 6 : Instruction PTE access |
STATSIGS[5] <= IC_ACC & IC_MDONE; // 5 : Instruction Memory read |
STATSIGS[4] <= IC_READ & IACC_OK & ~DATA_HOLD; // 4 : Instruction read , can be IO-Port too ! |
STATSIGS[3] <= DRAM_WR; // 3 : Data write |
STATSIGS[2] <= DPTE_ACC; // 2 : Data PTE access |
STATSIGS[1] <= DC_ACC & DC_MDONE; // 1 : Data Memory read |
STATSIGS[0] <= READ & DACC_OK; // 0 : Data read , can be IO-Port too ! |
end |
|
endmodule |
|
/trunk/rtl/ALIGNER.v
0,0 → 1,354
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: ALIGNER.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. WR_ALINGER alignes write data to cache and external devices |
// 2. RD_ALINGER alignes read data for the data path |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. WR_ALINGER alignes write data to cache and external devices |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module WR_ALIGNER ( PACKET, DP_Q, SIZE, WRDATA, ENBYTE ); |
|
input [3:0] PACKET; // [3:2] Paketnumber , [1:0] Startaddress |
input [63:0] DP_Q; |
input [1:0] SIZE; |
output [31:0] WRDATA; |
output [3:0] ENBYTE; |
|
reg [3:0] ENBYTE; |
reg [7:0] dbyte0,dbyte1,dbyte2,dbyte3; |
wire switch; |
|
// Data packet [ B7 ],[ B6 ],[ B5 ],[ B4 ],[ B3 ],[ B2 ],[ B1 ],[ B0 ] |
// Address , i.e. 001 : one DWORD |
// gives 2 packets : 1. packet [-B6-----B5-----B4-] |
// 2. packet, Address + 4 [-B7-] |
// Addresse , i.e. 010 : one QWORD |
// gives 3 packets : 1. packet [-B1-----B0-] |
// 2. packet, Address + 4 [-B5-----B4-----B3-----B2-] |
// 3. packet, Address + 8 [-B7-----B6-] |
|
// SIZE PACKET ADR : Outputbus |
// 00 00 00 x x x B4 |
// 00 00 01 x x B4 x |
// 00 00 10 x B4 x x |
// 00 00 11 B4 x x x |
|
// 01 00 00 x x B5 B4 |
// 01 00 01 x B5 B4 x |
// 01 00 10 B5 B4 x x |
// 01 00 11 B4 x x x |
// 01 10 11 x x x B5 |
|
// 10 00 00 B7 B6 B5 B4 |
// 10 00 01 B6 B5 B4 x |
// 10 10 01 x x x B7 |
// 10 00 10 B5 B4 x x |
// 10 10 10 x x B7 B6 |
// 10 00 11 B4 x x x |
// 10 10 11 x B7 B6 B5 |
|
// 11 00 00 B3 B2 B1 B0 |
// 11 10 00 B7 B6 B5 B4 |
// 11 00 01 B2 B1 B0 x |
// 11 01 01 B6 B5 B4 B3 |
// 11 10 01 x x x B7 |
// 11 00 10 B1 B0 x x |
// 11 01 10 B5 B4 B3 B2 |
// 11 10 10 x x B7 B6 |
// 11 00 11 B0 x x x |
// 11 01 11 B4 B3 B2 B1 |
// 11 10 11 x B7 B6 B5 |
|
assign switch = (SIZE == 2'b11) & (PACKET[3:2] == 2'b00); |
|
always @(DP_Q or switch or PACKET) |
case (PACKET[1:0]) |
2'b00 : dbyte0 = switch ? DP_Q[7:0] : DP_Q[39:32]; |
2'b01 : dbyte0 = PACKET[3] ? DP_Q[63:56] : DP_Q[31:24]; |
2'b10 : dbyte0 = PACKET[3] ? DP_Q[55:48] : DP_Q[23:16]; |
2'b11 : dbyte0 = PACKET[3] ? DP_Q[47:40] : DP_Q[15:8]; |
endcase |
|
always @(DP_Q or switch or PACKET) |
case (PACKET[1:0]) |
2'b00 : dbyte1 = switch ? DP_Q[15:8] : DP_Q[47:40]; |
2'b01 : dbyte1 = switch ? DP_Q[7:0] : DP_Q[39:32]; |
2'b10 : dbyte1 = PACKET[3] ? DP_Q[63:56] : DP_Q[31:24]; |
2'b11 : dbyte1 = PACKET[3] ? DP_Q[55:48] : DP_Q[23:16]; |
endcase |
|
always @(DP_Q or switch or PACKET) |
case (PACKET[1:0]) |
2'b00 : dbyte2 = switch ? DP_Q[23:16] : DP_Q[55:48]; |
2'b01 : dbyte2 = switch ? DP_Q[15:8] : DP_Q[47:40]; |
2'b10 : dbyte2 = switch ? DP_Q[7:0] : DP_Q[39:32]; |
2'b11 : dbyte2 = PACKET[3] ? DP_Q[63:56] : DP_Q[31:24]; |
endcase |
|
always @(DP_Q or switch or PACKET) |
case (PACKET[1:0]) |
2'b00 : dbyte3 = switch ? DP_Q[31:24] : DP_Q[63:56]; |
2'b01 : dbyte3 = switch ? DP_Q[23:16] : DP_Q[55:48]; |
2'b10 : dbyte3 = switch ? DP_Q[15:8] : DP_Q[47:40]; |
2'b11 : dbyte3 = switch ? DP_Q[7:0] : DP_Q[39:32]; |
endcase |
|
assign WRDATA = {dbyte3,dbyte2,dbyte1,dbyte0}; |
|
always @(SIZE or PACKET) |
casex ({SIZE,PACKET}) |
6'b00_xx_00 : ENBYTE = 4'b0001; // BYTE |
6'b00_xx_01 : ENBYTE = 4'b0010; |
6'b00_xx_10 : ENBYTE = 4'b0100; |
6'b00_xx_11 : ENBYTE = 4'b1000; |
// |
6'b01_xx_00 : ENBYTE = 4'b0011; // WORD |
6'b01_xx_01 : ENBYTE = 4'b0110; |
6'b01_xx_10 : ENBYTE = 4'b1100; |
6'b01_0x_11 : ENBYTE = 4'b1000; |
6'b01_1x_11 : ENBYTE = 4'b0001; |
// |
6'b11_xx_00 : ENBYTE = 4'b1111; // QWORD |
6'b11_00_01 : ENBYTE = 4'b1110; |
6'b11_01_01 : ENBYTE = 4'b1111; |
6'b11_1x_01 : ENBYTE = 4'b0001; |
6'b11_00_10 : ENBYTE = 4'b1100; |
6'b11_01_10 : ENBYTE = 4'b1111; |
6'b11_1x_10 : ENBYTE = 4'b0011; |
6'b11_00_11 : ENBYTE = 4'b1000; |
6'b11_01_11 : ENBYTE = 4'b1111; |
6'b11_1x_11 : ENBYTE = 4'b0111; |
// |
6'b10_xx_00 : ENBYTE = 4'b1111; // DWORD |
6'b10_0x_01 : ENBYTE = 4'b1110; |
6'b10_1x_01 : ENBYTE = 4'b0001; |
6'b10_0x_10 : ENBYTE = 4'b1100; |
6'b10_1x_10 : ENBYTE = 4'b0011; |
6'b10_0x_11 : ENBYTE = 4'b1000; |
6'b10_1x_11 : ENBYTE = 4'b0111; |
endcase |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. RD_ALINGER alignes read data for the data path |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module RD_ALIGNER ( BCLK, ACC_OK, PACKET, SIZE, REG_OUT, RDDATA, CA_HIT, DP_DI, AUX_QW ); |
|
input BCLK; |
input ACC_OK; |
input [3:0] PACKET; // [3:2] Paketnumber , [1:0] Startaddress |
input [1:0] SIZE; |
input REG_OUT; |
input [31:0] RDDATA; |
input CA_HIT; |
|
output [31:0] DP_DI; |
output reg AUX_QW; |
|
reg [6:0] enable; |
reg [7:0] dreg_0,dreg_1,dreg_2,dreg_3,dreg_4,dreg_5,dreg_6; |
reg [7:0] out_0,out_1,out_2,out_3; |
|
// RD_ALIGNER principal working : 10 is last packet , 01 is packet in between |
|
// Not aligned QWORD : ADR[1:0] = 3 i.e. |
// Bytes to datapath : . - . - 4 - 4 |
// Bytes from memory : 1 - 4 - 3 - . |
// ACC_DONE : _______/----\__ |
// + 1 cycle ____/-- |
// at the end 2 cycles lost. ACC_DONE informs the Op-Dec that data is available and sent one clock c |
// the LSD of QWORD access. (ACC_DONE -> REG_OUT is happening in ADDR_UNIT.) |
// |
// SIZE PACKET ADR : Output data ACC_OK |
// 00 -- 00 x x x B0 Byte 1 |
// 00 -- 01 x x x B1 1 |
// 00 -- 10 x x x B2 1 |
// 00 -- 11 x x x B3 1 |
|
// 01 00 00 x x B1 B0 Word 1 |
// 01 00 01 x x B2 B1 1 |
// 01 00 10 x x B3 B2 1 |
// 01 00 11 B3 x x x -> Reg : R4 - - - 0 |
// 01 10 11 x x B0 R4 1 |
|
// 10 00 00 B3 B2 B1 B0 DWORD 1 |
// 10 00 01 B3 B2 B1 x -> Reg : R6 R5 R4 - 0 |
// 10 10 01 B0 R6 R5 R4 1 |
// 10 00 10 B3 B2 x x -> Reg : R5 R4 - - 0 |
// 10 10 10 B1 B0 R5 R4 1 |
// 10 00 11 B3 x x x -> Reg : R4 - - - 0 |
// 10 10 11 B2 B1 B0 R4 1 |
|
// 11 00 00 B3 B2 B1 B0 QWORD 1 MSD |
// 11 01 00 B3 B2 B1 B0 not out of Reg! 0 LSD |
// 11 00 01 B3 B2 B1 x -> Reg : R2 R1 R0 - 0 |
// 11 01 01 B3 B2 B1 B0 -> Reg : R6 R5 R4 R3 0 |
// 11 10 01 B0 R6 R5 R4 1 MSD |
// next cycle: R3 R2 R1 R0 LSD |
// 11 00 10 B3 B2 x x -> Reg : R1 R0 - - 0 |
// 11 01 10 B3 B2 B1 B0 -> Reg : R5 R4 R3 R2 0 |
// 11 10 10 B1 B0 R5 R4 1 MSD |
// next cycle: R3 R2 R1 R0 LSD |
// 11 00 11 B3 x x x -> Reg : R0 - - - 0 |
// 11 01 11 B3 B2 B1 B0 -> Reg : R4 R3 R2 R1 0 |
// 11 10 11 B2 B1 B0 R4 1 MSD |
// next cycle: R3 R2 R1 R0 LSD |
|
// IO_ACCESS QWORD : |
// 11 00 00 B3 B2 B1 B0 -> Reg : R3 R2 R1 R0 0 |
// 11 01 00 R3 R2 R1 R0 -> Reg : R3 R2 R1 R0 1 MSD |
// next cycle: R3 R2 R1 R0 LSD |
|
always @(ACC_OK or SIZE or PACKET) |
casex ({ACC_OK,SIZE,PACKET}) |
7'b1_xx_0x_00 : enable = 7'b000_1111; |
7'b1_01_0x_11 : enable = 7'b001_0000; |
7'b1_10_0x_01 : enable = 7'b111_0000; |
7'b1_10_0x_10 : enable = 7'b011_0000; |
7'b1_10_0x_11 : enable = 7'b001_0000; |
7'b1_11_00_01 : enable = 7'b000_0111; // QWORD |
7'b1_11_01_01 : enable = 7'b111_1000; |
7'b1_11_00_10 : enable = 7'b000_0011; |
7'b1_11_01_10 : enable = 7'b011_1100; |
7'b1_11_00_11 : enable = 7'b000_0001; |
7'b1_11_01_11 : enable = 7'b001_1110; |
default : enable = 7'b000_0000; |
endcase |
|
// Register for inbetween data: simple multiplexer |
|
always @(posedge BCLK) |
if (enable[0]) |
case (PACKET[1:0]) |
2'b01 : dreg_0 <= RDDATA[15:8]; |
2'b10 : dreg_0 <= RDDATA[23:16]; |
2'b11 : dreg_0 <= RDDATA[31:24]; |
default : dreg_0 <= RDDATA[7:0]; |
endcase |
|
always @(posedge BCLK) |
if (enable[1]) |
case (PACKET[1:0]) |
2'b01 : dreg_1 <= RDDATA[23:16]; |
2'b10 : dreg_1 <= RDDATA[31:24]; |
2'b11 : dreg_1 <= RDDATA[7:0]; |
default : dreg_1 <= RDDATA[15:8]; |
endcase |
|
always @(posedge BCLK) |
if (enable[2]) |
case (PACKET[1:0]) |
2'b01 : dreg_2 <= RDDATA[31:24]; |
2'b10 : dreg_2 <= RDDATA[7:0]; |
2'b11 : dreg_2 <= RDDATA[15:8]; |
default : dreg_2 <= RDDATA[23:16]; |
endcase |
|
always @(posedge BCLK) |
if (enable[3]) |
case (PACKET[1:0]) |
2'b01 : dreg_3 <= RDDATA[7:0]; |
2'b10 : dreg_3 <= RDDATA[15:8]; |
2'b11 : dreg_3 <= RDDATA[23:16]; |
default : dreg_3 <= RDDATA[31:24]; |
endcase |
|
always @(posedge BCLK) |
if (enable[4]) |
case (PACKET[1:0]) |
2'b01 : dreg_4 <= RDDATA[15:8]; |
2'b10 : dreg_4 <= RDDATA[23:16]; |
2'b11 : dreg_4 <= RDDATA[31:24]; |
default : dreg_4 <= dreg_4; |
endcase |
|
always @(posedge BCLK) if (enable[5]) dreg_5 <= PACKET[1] ? RDDATA[31:24] : RDDATA[23:16]; |
|
always @(posedge BCLK) if (enable[6]) dreg_6 <= RDDATA[31:24]; |
|
// +++++++++++++++++++++++ |
|
always @(SIZE or PACKET or RDDATA or dreg_0 or dreg_4) |
casex ({SIZE,PACKET[3],PACKET[1:0]}) |
5'b0x_0_01 : out_0 = RDDATA[15:8]; |
5'b0x_0_10 : out_0 = RDDATA[23:16]; |
5'b00_0_11 : out_0 = RDDATA[31:24]; |
5'b01_1_11 : out_0 = dreg_4; |
5'b1x_1_01 : out_0 = dreg_4; |
5'b1x_1_1x : out_0 = dreg_4; |
default : out_0 = RDDATA[7:0]; |
endcase |
|
always @(SIZE or PACKET or RDDATA or dreg_1 or dreg_5) |
casex ({SIZE,PACKET[3],PACKET[1:0]}) |
5'b01_0_01 : out_1 = RDDATA[23:16]; |
5'b01_0_10 : out_1 = RDDATA[31:24]; |
5'bxx_x_11 : out_1 = RDDATA[7:0]; |
5'b1x_1_01 : out_1 = dreg_5; |
5'b1x_1_10 : out_1 = dreg_5; |
default : out_1 = RDDATA[15:8]; |
endcase |
|
always @(SIZE or PACKET or RDDATA or dreg_2 or dreg_6) |
case ({SIZE[1],PACKET[3],PACKET[1:0]}) |
4'b1_1_01 : out_2 = dreg_6; |
4'b1_1_10 : out_2 = RDDATA[7:0]; |
4'b1_1_11 : out_2 = RDDATA[15:8]; |
default : out_2 = RDDATA[23:16]; |
endcase |
|
always @(SIZE or PACKET or RDDATA or dreg_3) |
case ({SIZE[1],PACKET[3],PACKET[1:0]}) |
4'b1_1_01 : out_3 = RDDATA[7:0]; |
4'b1_1_10 : out_3 = RDDATA[15:8]; |
4'b1_1_11 : out_3 = RDDATA[23:16]; |
default : out_3 = RDDATA[31:24]; |
endcase |
|
assign DP_DI = REG_OUT ? {dreg_3,dreg_2,dreg_1,dreg_0} : {out_3,out_2,out_1,out_0}; |
|
// ++++++++++++++++ Special case QWord if cache switched off +++++++++++++++++++ |
|
always @(posedge BCLK) AUX_QW <= ACC_OK & ~CA_HIT & (SIZE == 2'b11) & PACKET[3]; |
|
endmodule |
/trunk/rtl/STEUERUNG.v
0,0 → 1,220
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: STEUERUNG.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// STEUERUNG The control logic of M32632 |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module STEUERUNG( BCLK, BRESET, DC_ACC_DONE, ACB_ZERO, DONE, INT_N, NMI_N, DC_ABORT, IC_INIT, DC_INI |
IACC_STAT, PROT_ERROR, IC_DIN, PC_NEW, PSR, STRING, TRAPS, IC_READ, DATA_HOLD, LD_DIN, LD_IMME |
WREN, WR_REG, GENSTAT, ILO, COP_OP, IC_USER, ACC_FELD, DISP, IC_TEX, IMME_Q, INFO_AU, LD_OUT, |
DETOIP, MMU_UPDATE, OPER, PC_ARCHI, PC_ICACHE, RDAA, RDAB, START, WMASKE, WRADR, RWVAL, Y_INIT |
ENA_HK, STOP_CINV ); |
|
input BCLK; |
input BRESET; |
input DC_ACC_DONE; |
input ACB_ZERO; |
input DONE; |
input INT_N; |
input NMI_N; |
input DC_ABORT; |
input IC_INIT; |
input DC_INIT; |
input SAVE_PC; |
input Y_INIT; |
input [8:0] CFG; |
input [3:0] IACC_STAT; |
input PROT_ERROR; |
input [31:0] IC_DIN; |
input [31:0] PC_NEW; |
input [11:0] PSR; |
input [4:0] STRING; |
input [5:0] TRAPS; |
input STOP_CINV; |
|
output IC_READ; |
output DATA_HOLD; |
output LD_DIN; |
output LD_IMME; |
output WREN; |
output WR_REG; |
output [2:0] GENSTAT; |
output IC_USER; |
output [14:0] ACC_FELD; |
output [31:0] DISP; |
output [2:0] IC_TEX; |
output [31:0] IMME_Q; |
output [6:0] INFO_AU; |
output [1:0] LD_OUT; |
output [12:0] DETOIP; |
output [1:0] MMU_UPDATE; |
output [10:0] OPER; |
output [31:0] PC_ARCHI; |
output [31:0] PC_ICACHE; |
output [7:0] RDAA; |
output [7:0] RDAB; |
output [1:0] START; |
output [1:0] WMASKE; |
output [5:0] WRADR; |
output [2:0] RWVAL; |
output ENA_HK; |
output ILO; |
output [23:0] COP_OP; |
|
wire [55:0] OPREG; |
wire IC_ABORT; |
wire INIT_DONE; |
wire UNDEF; |
wire ILLEGAL; |
wire [2:0] ANZ_VAL; |
wire [31:0] PC_SAVE; |
wire NEW; |
wire RESTART; |
wire STOP_IC; |
wire [1:0] ALSB; |
wire [2:0] USED; |
wire NEXT_ADR; |
wire NEW_PC; |
wire NEXT_PCA; |
wire LOAD_PC; |
wire [31:0] DISP_BR; |
|
DECODER BEFEHLS_DEC( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.ACC_DONE(DC_ACC_DONE), |
.ACB_ZERO(ACB_ZERO), |
.DONE(DONE), |
.NMI_N(NMI_N), |
.INT_N(INT_N), |
.DC_ABORT(DC_ABORT), |
.IC_ABORT(IC_ABORT), |
.INIT_DONE(INIT_DONE), |
.UNDEF(UNDEF), |
.ILL(ILLEGAL), |
.IC_READ(IC_READ), |
.ANZ_VAL(ANZ_VAL), |
.CFG(CFG), |
.OPREG(OPREG), |
.PC_SAVE(PC_SAVE), |
.PSR(PSR), |
.STRING(STRING), |
.TRAPS(TRAPS), |
.NEW(NEW), |
.WREN(WREN), |
.LD_DIN(LD_DIN), |
.LD_IMME(LD_IMME), |
.NEXT_PCA(NEXT_PCA), |
.WR_REG(WR_REG), |
.LOAD_PC(LOAD_PC), |
.GENSTAT(GENSTAT), |
.RESTART(RESTART), |
.STOP_IC(STOP_IC), |
.ACC_FELD(ACC_FELD), |
.DISP(DISP), |
.DISP_BR(DISP_BR), |
.IMME_Q(IMME_Q), |
.INFO_AU(INFO_AU), |
.LD_OUT(LD_OUT), |
.DETOIP(DETOIP), |
.MMU_UPDATE(MMU_UPDATE), |
.OPER(OPER), |
.RDAA(RDAA), |
.RDAB(RDAB), |
.START(START), |
.USED(USED), |
.WMASKE(WMASKE), |
.WRADR(WRADR), |
.RWVAL(RWVAL), |
.ENA_HK(ENA_HK), |
.ILO(ILO), |
.COP_OP(COP_OP), |
.STOP_CINV(STOP_CINV) ); |
|
ILL_UNDEF CHECKER( |
.USER(PSR[8]), |
.ANZ_VAL(ANZ_VAL), |
.CFG(CFG[3:1]), |
.OPREG(OPREG[23:0]), |
.ILL(ILLEGAL), |
.UNDEF(UNDEF)); |
|
OPDEC_REG OPC_REG( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.NEW(NEW), |
.DC_INIT(DC_INIT), |
.IC_INIT(IC_INIT), |
.Y_INIT(Y_INIT), |
.RESTART(RESTART), |
.STOP_IC(STOP_IC), |
.ACC_STAT(IACC_STAT), |
.PROT_ERROR(PROT_ERROR), |
.ALSB(ALSB), |
.IC_DIN(IC_DIN), |
.USED(USED), |
.IC_READ(IC_READ), |
.NEXT_ADR(NEXT_ADR), |
.DATA_HOLD(DATA_HOLD), |
.NEW_PC(NEW_PC), |
.ABORT(IC_ABORT), |
.INIT_DONE(INIT_DONE), |
.ANZ_VAL(ANZ_VAL), |
.IC_TEX(IC_TEX), |
.OPREG(OPREG)); |
|
PROG_COUNTER PCS( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.NEXT_ADR(NEXT_ADR), |
.NEW_PC(NEW_PC), |
.NEXT_PCA(NEXT_PCA), |
.NEW(NEW), |
.LOAD_PC(LOAD_PC), |
.USER(PSR[8]), |
.SAVE_PC(SAVE_PC), |
.FPU_TRAP(TRAPS[0]), |
.ADIVAR(INFO_AU[3]), |
.DISP(DISP_BR), |
.PC_NEW(PC_NEW), |
.USED(USED), |
.IC_USER(IC_USER), |
.ALSB(ALSB), |
.PC_ARCHI(PC_ARCHI), |
.PC_ICACHE(PC_ICACHE), |
.PC_SAVE(PC_SAVE)); |
|
endmodule |
/trunk/rtl/I_PFAD.v
0,0 → 1,841
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: I_PFAD.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. BITMASK Mask Generator , was a ROM on falling edge in early days |
// 2. MULFILTER Filter for Multiplier Input Data |
// 3. SIGNMUL Signed Multiplier for Integer Multiplication |
// 4. SHIFTER Barrel Shifter for all Shift Opcodes |
// 5. FFS_LOGIK Logic for FFS opcode |
// 6. SCHALE Enclosure for Adder/Subtractor |
// 7. I_PFAD The Integer Datapath |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. BITMASK Mask Generator , was a ROM on falling edge in early days |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module BITMASK (AA, DOUT); |
|
// 0 : FFFFFFFF; Masktype 1 , Zero from right |
// 1 : FFFFFFFE; |
// 2 : FFFFFFFC; |
// 3 : FFFFFFF8; |
// . : ... |
// 32 : 00000001; Masktype 2 , Decoder |
// 33 : 00000002; |
// 34 : 00000004; |
// 35 : 00000008; |
// .. : ... |
// 64 : 00000001; Masktyte 3 , One from right |
// 65 : 00000003; |
// 66 : 00000007; |
// 67 : 0000000F; |
// .. : ... |
// 96 : FFFFFFFF; Masktype 4 , like Masktype 3 but AA-1 |
// 97 : 00000001; |
// 98 : 00000003; |
// 99 : 00000007; |
// .. : ... |
|
input [6:0] AA; |
|
output reg [31:0] DOUT; |
|
reg [7:0] dec_bit; |
|
wire [4:0] code; |
wire high,low; |
|
|
assign code = AA[4:0] - {4'd0,&AA[6:5]}; |
|
assign high = (AA[6:5] == 2'd0); |
assign low = AA[6]; |
|
always @(code or high or low) |
case (code[2:0]) |
3'b000 : dec_bit = {{7{high}},1'b1 }; |
3'b001 : dec_bit = {{6{high}},1'b1, low }; |
3'b010 : dec_bit = {{5{high}},1'b1,{2{low}}}; |
3'b011 : dec_bit = {{4{high}},1'b1,{3{low}}}; |
3'b100 : dec_bit = {{3{high}},1'b1,{4{low}}}; |
3'b101 : dec_bit = {{2{high}},1'b1,{5{low}}}; |
3'b110 : dec_bit = { high ,1'b1,{6{low}}}; |
3'b111 : dec_bit = { 1'b1,{7{low}}}; |
endcase |
|
always @(code or high or low or dec_bit) |
case (code[4:3]) |
2'b00 : DOUT = {{24{high}},dec_bit }; |
2'b01 : DOUT = {{16{high}},dec_bit,{ 8{low}}}; |
2'b10 : DOUT = {{ 8{high}},dec_bit,{16{low}}}; |
2'b11 : DOUT = { dec_bit,{24{low}}}; |
endcase |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. MULFILTER Filter for Multiplier Input Data |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module MULFILTER (BWD, FLOAT, SRC1, SRC2, DEST1, DEST2); |
|
input [1:0] BWD; |
input FLOAT; |
input [31:0] SRC1,SRC2; |
output [31:0] DEST1,DEST2; |
|
wire sign1,sign2; |
reg [31:0] DEST1,DEST2; |
|
assign sign1 = BWD[0] ? SRC1[15] : SRC1[7]; |
|
always @(FLOAT or BWD or SRC1 or sign1) |
casex ({FLOAT,BWD,sign1}) |
4'b0_00_0 : DEST1 = {24'h000000, SRC1[7:0]}; |
4'b0_00_1 : DEST1 = {24'hFFFFFF, SRC1[7:0]}; |
4'b0_01_0 : DEST1 = { 16'h0000,SRC1[15:0]}; |
4'b0_01_1 : DEST1 = { 16'hFFFF,SRC1[15:0]}; |
4'b1_xx_x : DEST1 = { 9'h001,SRC1[22:0]}; |
default : DEST1 = SRC1; |
endcase |
|
assign sign2 = BWD[0] ? SRC2[15] : SRC2[7]; |
|
always @(FLOAT or BWD or SRC2 or sign2) |
casex ({FLOAT,BWD,sign2}) |
4'b0_00_0 : DEST2 = {24'h000000, SRC2[7:0]}; |
4'b0_00_1 : DEST2 = {24'hFFFFFF, SRC2[7:0]}; |
4'b0_01_0 : DEST2 = { 16'h0000,SRC2[15:0]}; |
4'b0_01_1 : DEST2 = { 16'hFFFF,SRC2[15:0]}; |
4'b1_xx_x : DEST2 = { 9'h001,SRC2[22:0]}; |
default : DEST2 = SRC2; |
endcase |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. SIGNMUL Signed Multiplier for Integer Multiplication |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SIGNMUL (dataa, datab, result); |
|
input signed [31:0] dataa,datab; |
output signed [63:0] result; |
|
assign result = dataa * datab; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. SHIFTER Barrel Shifter for all Shift Opcodes |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SHIFTER ( MASKE,ROT,LSH,ASH,SIZE,SH_VAL,SH_DAT,SH_OUT,MASK_SEL); |
|
input [31:0] MASKE; |
input ROT,LSH,ASH; |
input [1:0] SIZE; |
input [7:0] SH_VAL; |
input [31:0] SH_DAT; |
output [31:0] SH_OUT; |
output [4:0] MASK_SEL; |
|
reg [31:0] sh_dat_in; |
wire [31:0] sh_dat_0,sh_dat_1,sh_dat_2,sh_dat_3,sh_dat_4; |
wire [4:0] shift; |
reg msb; |
wire [1:0] mask_code; |
reg [31:0] SH_OUT; |
reg [4:0] MASK_SEL; |
|
// Inputstage : prepare for ROT opcode : |
|
always @(ROT or SIZE or SH_DAT) |
casex ({ROT,SIZE}) |
3'b100 : sh_dat_in = {SH_DAT[31:16],SH_DAT[7:0],SH_DAT[7:0]}; // Byte copy to left |
3'b101 : sh_dat_in = {SH_DAT[15:0],SH_DAT[15:0]}; // Word copy to left |
default : sh_dat_in = SH_DAT; |
endcase |
|
// Special case for ROT and BYTE : this way less logic |
|
assign shift = (ROT & (SIZE == 2'b00)) ? {2'b11,SH_VAL[2:0]} : SH_VAL[4:0]; |
|
// Rotation logic |
|
assign sh_dat_0 = shift[0] ? {sh_dat_in[30:0],sh_dat_in[31]} : sh_dat_in; // Rotation of 1 bit posi |
assign sh_dat_1 = shift[1] ? {sh_dat_0[29:0],sh_dat_0[31:30]} : sh_dat_0; // 2 |
assign sh_dat_2 = shift[2] ? {sh_dat_1[27:0],sh_dat_1[31:28]} : sh_dat_1; // 4 |
assign sh_dat_3 = shift[3] ? {sh_dat_2[23:0],sh_dat_2[31:24]} : sh_dat_2; // 8 |
assign sh_dat_4 = shift[4] ? {sh_dat_3[15:0],sh_dat_3[31:16]} : sh_dat_3; // 16 |
|
// Detection of negativ data |
|
always @(SIZE or SH_DAT) |
casex (SIZE) |
2'b00 : msb = SH_DAT[7]; // Byte |
2'b01 : msb = SH_DAT[15]; // Word |
default : msb = SH_DAT[31]; // Double = 11 |
endcase |
|
// needs mask for output data : SH_VAL[7] says negativ number and "right" shift |
|
assign mask_code[1] = ROT | (SH_VAL[7] & ASH & msb); |
assign mask_code[0] = ROT | (SH_VAL[7] & ((ASH & ~msb) | LSH)); |
|
always @(SH_VAL or SIZE) |
casex ({SH_VAL[7],SIZE}) |
3'b100 : MASK_SEL = {2'b00,SH_VAL[2:0]}; // special mask for Byte at right-shift |
3'b101 : MASK_SEL = {1'b0,SH_VAL[3:0]}; // special mask for Word at right-shift |
default : MASK_SEL = SH_VAL[4:0]; |
endcase |
|
always @(mask_code or sh_dat_4 or MASKE) // top bits of MASKE are "1", lower bits are "0" |
casex (mask_code) |
2'b00 : SH_OUT = sh_dat_4 & MASKE; // LSH and ASH with positiv shift count |
2'b01 : SH_OUT = sh_dat_4 & ~MASKE; // Negativ shift count : LSH or ASH with positiv data |
2'b10 : SH_OUT = sh_dat_4 | MASKE; // ASH with negativ shift count and negativ input data |
default : SH_OUT = sh_dat_4; // ROT |
endcase |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 5. FFS_LOGIK Logic for FFS opcode |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module FFS_LOGIK (SRC1, SRC2, BWD, FLAG, DOUT); |
|
input [31:0] SRC1; |
input [4:0] SRC2; |
input [1:0] BWD; |
output reg FLAG; |
output [4:0] DOUT; |
|
reg [6:0] maske; |
reg [7:0] byte_1,byte_2; |
|
wire [7:0] byte_0,byte_3; |
wire [15:0] mdat_0; |
wire [7:0] mdat_1; |
wire [3:0] mdat_2; |
wire [1:0] mdat_3; |
wire [4:0] obits; |
|
always @(*) |
case (SRC2[2:0]) |
3'd0 : maske = 7'h7F; |
3'd1 : maske = 7'h7E; |
3'd2 : maske = 7'h7C; |
3'd3 : maske = 7'h78; |
3'd4 : maske = 7'h70; |
3'd5 : maske = 7'h60; |
3'd6 : maske = 7'h40; |
3'd7 : maske = 7'h00; |
endcase |
|
assign byte_0 = (SRC2[4:3] == 2'b00) ? {SRC1[7],(SRC1[6:0] & maske)} : 8'h00; |
|
always @(*) |
casex (SRC2[4:3]) |
2'b00 : byte_1 = SRC1[15:8]; |
2'b01 : byte_1 = {SRC1[15],(SRC1[14:8] & maske)}; |
2'b1x : byte_1 = 8'h00; |
endcase |
|
always @(*) |
casex (SRC2[4:3]) |
2'b0x : byte_2 = SRC1[23:16]; |
2'b10 : byte_2 = {SRC1[23],(SRC1[22:16] & maske)}; |
2'b11 : byte_2 = 8'h00; |
endcase |
|
assign byte_3 = (SRC2[4:3] == 2'b11) ? {SRC1[31],(SRC1[30:24] & maske)} : SRC1[31:24]; |
|
assign obits[4] = ({byte_1,byte_0} == 16'h0); |
assign mdat_0 = obits[4] ? {byte_3,byte_2} : {byte_1,byte_0}; // 16 Bit |
|
assign obits[3] = (mdat_0[7:0] == 8'h0); |
assign mdat_1 = obits[3] ? mdat_0[15:8] : mdat_0[7:0]; |
|
assign obits[2] = (mdat_1[3:0] == 4'h0); |
assign mdat_2 = obits[2] ? mdat_1[7:4] : mdat_1[3:0]; |
|
assign obits[1] = (mdat_2[1:0] == 2'b0); |
assign mdat_3 = obits[1] ? mdat_2[3:2] : mdat_2[1:0]; |
|
assign obits[0] = ~mdat_3[0]; |
|
always @(BWD or obits or mdat_3) |
casex ({BWD,obits[4:3]}) |
4'b00_x1 : FLAG = 1; // Byte Overflow => nothing found |
4'b00_10 : FLAG = 1; // Byte Overflow => nothing found |
4'b01_1x : FLAG = 1; // Word Overflow => nothing found |
default : FLAG = (mdat_3 == 2'b00); |
endcase |
|
assign DOUT = FLAG ? 5'h0 : obits; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 6. SCHALE Enclosure for Adder/Subtractor |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SCHALE (dataa, datab, cin, add_sub, bwd, result, cout, overflow); |
|
input [31:0] dataa,datab; |
input cin; |
input add_sub; // 1 = Addition , 0 = Subtraction |
input [1:0] bwd; |
|
output [31:0] result; |
output cout,overflow; |
|
reg [2:0] seldat; |
reg overflow; |
|
wire [32:0] summe; |
|
assign summe = {1'b0,dataa} + {1'b0,(add_sub ? datab : ~datab)} + {32'd0,cin}; |
|
always @(bwd or dataa or datab or summe) |
case (bwd) |
2'b00 : seldat = {summe[7], dataa[7], datab[7]}; |
2'b01 : seldat = {summe[15],dataa[15],datab[15]}; |
default : seldat = {summe[31],dataa[31],datab[31]}; |
endcase |
|
always @(seldat or add_sub) |
case (seldat[1:0]) |
2'b00 : overflow = add_sub ? seldat[2] : 1'b0; |
2'b01 : overflow = add_sub ? 1'b0 : seldat[2]; |
2'b10 : overflow = add_sub ? 1'b0 : ~seldat[2]; |
2'b11 : overflow = add_sub ? ~seldat[2] : 1'b0; |
endcase |
|
assign cout = add_sub ? summe[32] : ~summe[32]; |
assign result = summe[31:0]; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 7. I_PFAD The Integer Datapath |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module I_PFAD ( BCLK, BRESET, SFP_DAT, FSR, DP_OUT, SRC1, SRC2, BMASKE, ADDR, MRESULT, OPCODE, BWD, |
WREN, WRADR, RDAA, DETOIP, BITSEL, OVF_BCD, DISP, RWVFLAG, DSR, I_OUT, PSR, BMCODE, OV_FLAG, ACB |
|
input BCLK,BRESET; |
input [31:0] SFP_DAT,FSR,DP_OUT; |
input [31:0] SRC1,SRC2; |
input [31:0] BMASKE; |
input [31:0] ADDR; |
input [63:0] MRESULT; |
input [7:0] OPCODE; |
input [1:0] BWD; |
input FL; |
input [2:0] SP_CMP; |
input [2:0] DP_CMP; |
input LD_OUT; |
input WREN; |
input [5:0] WRADR; |
input [7:0] RDAA; |
input [11:0] DETOIP; |
input [2:0] BITSEL; |
input [3:0] OVF_BCD; |
input [4:0] DISP; |
input RWVFLAG; |
input [3:0] DSR; |
|
output [31:0] I_OUT; |
output [11:0] PSR; |
output [6:0] BMCODE; // ROM Address for BITMASK |
output reg OV_FLAG; |
output ACB_ZERO; |
output [4:0] STRING; |
|
reg [31:0] I_OUT; |
reg [31:0] pfad_7,pfad_6,pfad_8,pfad_4a; |
wire [31:0] pfad_4,pfad_5,pfad_11; |
|
reg [31:0] bwd_daten1,bwd_daten2; |
wire [31:0] addsub_q; |
|
// +++++++++++++ Global Output Multiplexer ++++++++++++++++++++++++++++ |
|
always @(OPCODE or pfad_4 or pfad_5 or pfad_6 or pfad_7 or pfad_8 or DP_OUT or FL or SFP_DAT or FSR |
casex (OPCODE[7:3]) |
5'b0100_x : I_OUT = pfad_4; |
5'b0101_x : I_OUT = pfad_5; // String opcodes |
5'b0110_x : I_OUT = pfad_6; |
5'b0111_x : I_OUT = pfad_7; |
5'b1000_x : I_OUT = pfad_8; |
5'b1001_0 : I_OUT = DP_OUT; // SP_FPU has higher priority ! LFSR has no output |
// SFSR : ROUND,TRUNC,FLOOR Integer Data : SP or DP Block |
5'b1001_1 : I_OUT = (OPCODE[2:1] == 2'b10) ? FSR : (FL ? SFP_DAT : DP_OUT); |
5'b1011_x : I_OUT = pfad_11; |
5'b1101_x : I_OUT = DP_OUT; // Coprocessor |
default : I_OUT = 32'hxxxx_xxxx; // don't care |
endcase |
|
// ++++++++++++++ PSR Register : I P S U / N Z F V - L T C |
// 11 10 9 8 7 6 5 4 3 2 1 0 |
|
reg [3:0] psr_high; |
reg [7:0] psr_low,psr_new; |
reg [11:0] push_psr; // true Register |
reg [11:0] calc_psr; // only verilog case |
reg [1:0] nl_int; |
|
wire ld_psr_l,ld_psr_h,up_psr; |
wire cmp_op,bit_op,ari_op,neg_op,ffs_op,str_op,chk_op,abs_op,rwv_op; |
wire [1:0] fp_nz; |
wire f_flag,z_flag; |
wire [1:0] nl_flags; |
wire over_flow,cy_out; |
wire ffs_flag; // FLAG result of FFS |
wire chk_flag; // FLAG result of CHECK |
wire save_psr,pop_psr; |
wire [4:0] selbits; |
// Bits from DETOIP; |
wire cmps_op,ph_match,until,kill_opt,inss_op,exin_cmd,extract,bit_reg,kurz_st,dw_info,acb_reg,t2p |
wire bcd_op,bcd_carry; |
|
assign cmps_op = DETOIP[11]; // for CMPS |
assign ph_match = DETOIP[10]; // MATCH phase |
assign until = DETOIP[9]; // UNITL Flag for String |
assign kill_opt = DETOIP[8]; // optimized execution of MOVS/MOVM |
assign inss_op = DETOIP[7]; // 1=INSS |
assign exin_cmd = DETOIP[6]; // for EXT/INS |
assign extract = DETOIP[5] & exin_cmd; // 1=EXT |
assign bit_reg = DETOIP[4]; // for Bit opcodes |
assign kurz_st = DETOIP[3]; // for MOVM/CMPM |
assign dw_info = DETOIP[2]; // at ADJSPi is SP=SRC2 always 32 Bit |
assign acb_reg = DETOIP[1]; // suppresses Carry-Set at ACB |
assign t2p = DETOIP[0]; // Pulse to Load Trace-Bit to Pending-Trace-Bit |
|
assign bcd_op = OVF_BCD[1]; // ADDPi,SUBPi - from DP_FPU |
assign bcd_carry = OVF_BCD[0]; |
|
assign ld_psr_l = ((WRADR == 6'h1D) | (WRADR == 6'h10)) & WREN; // Register PSR & UPSR |
assign ld_psr_h = (WRADR == 6'h1D) & (BWD != 2'b00) & WREN; // Register PSR |
// LD_OUT[1] is coming out of DECODER for this purpose |
assign up_psr = bcd_op | ((cmp_op | bit_op | ari_op | neg_op | ffs_op | chk_op) & LD_OUT); |
|
assign cmp_op = (OPCODE == 8'h41) | ((OPCODE == 8'hB2) & (FL ? ~SP_CMP[2] : ~DP_CMP[2])); // CMPi o |
assign bit_op = ((OPCODE[7:4] == 4'h6) & ((~OPCODE[3] & OPCODE[1]) | OPCODE[3:0] == 4'hE)) // the |
| (OPCODE == 8'h4D) | str_op | rwv_op; // TBIT or CMPS or RDVAL/WRVAL |
assign ari_op = (OPCODE[7:4] == 4'h4) & (OPCODE[1:0] == 2'b0) & ~dw_info; // ADDi,ADDCi,SUBi,SUBCi |
assign neg_op = (OPCODE[7:4] == 4'h6) & (OPCODE[3] & (OPCODE[1:0] == 2'b0)); // ABSi,NEGi |
assign ffs_op = (OPCODE == 8'h85); // FFS |
assign chk_op = (OPCODE == 8'h83); // CHECK |
assign str_op = (OPCODE[7:4] == 4'h5) & (OPCODE[3:2] == 2'b0) & ~kurz_st; // String-"S" opcodes : F |
assign abs_op = (OPCODE == 8'h6C); // ABSi : Carry is not affected ! |
assign rwv_op = (OPCODE[7:4] == 4'hE) & (OPCODE[3:1] == 3'b0); // RDVAL + WRVAL |
|
always @(bwd_daten1 or bwd_daten2 or addsub_q) // SRC1 > SRC2 ? |
case ({bwd_daten2[31],bwd_daten1[31]}) |
2'b00 : nl_int = {addsub_q[31],addsub_q[31]}; // MSB = N , LSB = L |
2'b01 : nl_int = { 1'b0 , 1'b1 }; |
2'b10 : nl_int = { 1'b1 , 1'b0 }; |
2'b11 : nl_int = {addsub_q[31],addsub_q[31]}; |
endcase |
|
assign ACB_ZERO = (addsub_q == 32'h0); // is used for ACBi opcode too |
assign f_flag = str_op ? 1'b0 : (rwv_op ? RWVFLAG : (bit_op ? SRC2[selbits] : (acb_reg ? PSR[5] : o |
assign fp_nz = FL ? SP_CMP[1:0] : DP_CMP[1:0]; |
assign z_flag = OPCODE[1] ? fp_nz[0] : ACB_ZERO; |
assign nl_flags = OPCODE[1] ? {fp_nz[1],1'b0} : nl_int; |
|
always @(*) // Bits : N Z F V - L T C |
casex ({cmp_op,bcd_op,bit_op,(ffs_op | chk_op)}) |
4'b0000 : psr_new = {PSR[7:6], f_flag,PSR[4:1],((acb_reg | abs_op) ? PSR[0] : cy_out)}; |
4'b0001 : psr_new = {PSR[7:6],(ffs_op ? ffs_flag : chk_flag),PSR[4:0]}; // FFS or CHECK |
4'b001x : psr_new = (cmps_op & str_op) ? |
{2'b01, f_flag,PSR[4:3],1'b0,PSR[1:0]} // Init CMPS |
: {PSR[7:6], f_flag,PSR[4:0]}; // Bit opcode |
4'b01xx : psr_new = {PSR[7:6], 1'b0, PSR[4:1],bcd_carry}; // BCD opcode |
4'b1xxx : psr_new = ph_match ? |
{PSR[7:6], ~(ACB_ZERO ^ until), PSR[4:0]} // Until/While Option at String-"S" opcodes |
: {nl_flags[1],z_flag,PSR[5:3], nl_flags[0],PSR[1:0]}; // CMP f or i |
endcase |
|
always @(save_psr or pop_psr or OPCODE or PSR or SRC1) |
casex ({save_psr,pop_psr,OPCODE[6],OPCODE[2]}) |
4'b10xx : calc_psr = PSR & {~OPCODE[0],11'h0ED}; // clear P S U V T and the I-Bit at Interrupt & |
4'b11xx : calc_psr = SRC1[27:16]; |
4'b0x00 : calc_psr = PSR & ~SRC1[11:0]; // BICPSR : Opcode = h32 |
4'b0x01 : calc_psr = PSR | SRC1[11:0]; // BISPSR h36 |
default : calc_psr = SRC1[11:0]; // LPR PSR h76 |
endcase |
|
// Special case Exception Handling : Code x'89-x'8F |
assign save_psr = (OPCODE[7:3] == 5'b1000_1); |
assign pop_psr = (OPCODE[2:0] == 3'b000); |
|
always @(posedge BCLK or negedge BRESET) // central memory for PSR low |
if (!BRESET) psr_low <= 8'h0; |
else |
begin |
if (ld_psr_l || save_psr) psr_low <= calc_psr[7:0]; |
else |
if (up_psr) psr_low <= psr_new; // the Status result of a normal opcode |
end |
|
always @(posedge BCLK or negedge BRESET) // central memory for PSR high |
if (!BRESET) psr_high <= 4'h0; |
else |
begin |
if (ld_psr_h || save_psr) psr_high <= calc_psr[11:8]; // only at WORD access |
else // t2p : copy T-Bit into P-Bit at the beginning of opcode |
if (t2p) psr_high <= {psr_high[3],psr_low[1],psr_high[1:0]}; |
end |
|
// Register for storage of PSR at Entry of Exception |
always @(posedge BCLK) if (save_psr) push_psr <= {PSR[11],(~OPCODE[1] & PSR[10]),PSR[9:0]}; // P-Fl |
|
assign PSR = {psr_high,psr_low}; |
|
// ++++++++++++++ Overflow Detection ++++++++++++++++++++++++++++++++++++++ |
|
reg ovf_mul,ovf_ash; |
wire [31:0] shdat; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) OV_FLAG <= 1'b0; |
else |
if (OVF_BCD[3]) OV_FLAG <= OVF_BCD[2]; // DEI,QUO,DIV |
else |
if (LD_OUT) |
case (OPCODE) |
8'h78 : OV_FLAG <= ovf_mul; |
8'h61 : OV_FLAG <= ovf_ash; |
8'h40 : OV_FLAG <= over_flow & acb_reg; // ADD Opcode at ACB |
default : OV_FLAG <= 1'b0; |
endcase |
|
always @(BWD or MRESULT) |
casex (BWD) |
2'b00 : ovf_mul = ~((MRESULT[15:7] == 9'd0) | (MRESULT[15:7] == 9'h1FF)); |
2'b01 : ovf_mul = ~((MRESULT[31:15] == 17'd0) | (MRESULT[31:15] == 17'h1FFFF)); |
default : ovf_mul = ~((MRESULT[63:31] == 33'd0) | (MRESULT[63:31] == 33'h1FFFFFFFF)); |
endcase |
|
always @(BWD or SRC2 or shdat) |
casex (BWD) |
2'b00 : ovf_ash = (SRC2[7] != shdat[7]); |
2'b01 : ovf_ash = (SRC2[15] != shdat[15]); |
default : ovf_ash = (SRC2[31] != shdat[31]); |
endcase |
|
// ++++++++++++++ Format 4 Opcodes : Basic Integer Opcodes, MOVi is special case +++++++++++++ |
|
reg cy_in; |
reg get_psr,rd_psr,rd_dsr; |
wire add_flag; |
|
always @(BWD or SRC1) |
casex (BWD) |
2'b00 : bwd_daten1 = {{24{SRC1[7]}}, SRC1[7:0]}; // Sign Extension |
2'b01 : bwd_daten1 = {{16{SRC1[15]}},SRC1[15:0]}; |
default : bwd_daten1 = SRC1; |
endcase |
|
assign add_flag = ~OPCODE[3] & ~OPCODE[1] & ~OPCODE[0]; // Only ADDi and ADDCi otherwise subtract i |
|
always @(PSR or OPCODE) // more effort due to ABSi und NEGi : Format 6 |
casex ({OPCODE[5],OPCODE[3:2]}) |
3'b000 : cy_in = OPCODE[0]; // ADD + CMP |
3'b001 : cy_in = PSR[0]; // ADDC |
3'b011 : cy_in = ~PSR[0]; // SUBC |
default : cy_in = 1'b1; // SUB + ABS + NEG : BORROW must be 1 for normal Adder |
endcase |
|
SCHALE addsub_ipfad (.dataa(bwd_daten2), .datab(bwd_daten1), .cin(cy_in), .add_sub(add_flag), |
.result(addsub_q), .cout(cy_out), .overflow(over_flow) ); |
|
always @(posedge BCLK) get_psr <= (RDAA == 8'h9D) | (RDAA == 8'h90) | (RDAA == 8'h93); // PSR or US |
always @(posedge BCLK) rd_psr <= (RDAA[1:0] == 2'b01); |
always @(posedge BCLK) rd_dsr <= (RDAA[1:0] == 2'b11); |
|
always @(OPCODE or SRC1 or SRC2 or get_psr or rd_psr or rd_dsr or DSR or PSR or ADDR) |
casex (OPCODE[3:1]) |
3'b001 : pfad_4a = SRC2 & ~SRC1; // BIC |
3'bx10 : pfad_4a = get_psr ? {({4{rd_dsr}} & DSR),16'd0,({4{rd_psr}} & PSR[11:8]),({8{~rd_dsr}} |
3'b011 : pfad_4a = SRC2 | SRC1; // OR |
3'b101 : pfad_4a = SRC2 & SRC1; // AND |
3'b111 : pfad_4a = SRC2 ^ SRC1; // XOR |
default : pfad_4a = ADDR; // ADDR, comes from ADDR_UNIT |
endcase |
|
assign pfad_4 = (OPCODE[1:0] == 2'b00) ? addsub_q : pfad_4a; // ADD,ADDC,SUB,SUBC have extra path |
|
// ++++++++++++++ Format 5 Opcodes : Strings MOVS , CMPS und SKPS +++++++++++++++++++++++++++++++ |
|
reg [11:0] spointer,dpointer; |
reg [9:0] todo; |
reg [9:4] todo_reg; |
wire [3:0] abzug; |
wire mehr,weiter,op_str,no_opt; |
|
assign op_str = (OPCODE[7:3] == 5'b0101_0); |
|
// This logic is for detection if an accelerated MOVS/MOVM inside a page is possible - Backward is |
always @(posedge BCLK) |
if (op_str) |
begin |
spointer <= OPCODE[2] ? SRC1[11:0] : (spointer + {8'h00,todo[3:0]}); // Source |
dpointer <= OPCODE[2] ? SRC2[11:0] : (dpointer + {8'h00,todo[3:0]}); // Destination |
end |
|
assign no_opt = OPCODE[1] | ((spointer[11:3] == 9'h1FF) & (spointer[2:0] != 3'b000)) |
| kill_opt | ((dpointer[11:3] == 9'h1FF) & (dpointer[2:0] != 3'b000)); |
|
assign abzug = OPCODE[0] ? todo_reg[7:4] : 4'h0 ; |
|
assign pfad_5 = SRC1 - {28'h0,abzug}; |
|
assign mehr = (pfad_5[31:4] != 28'h0); |
|
always @(no_opt or BWD or mehr or pfad_5) |
casex ({no_opt,BWD,mehr,pfad_5[3:0]}) |
8'b000_1xxxx : todo = 10'h388; // Byte |
8'b000_01xxx : todo = 10'h388; |
8'b000_001xx : todo = 10'h244; |
8'b000_0001x : todo = 10'h122; |
8'b000_00001 : todo = 10'h011; |
// |
8'b001_1xxxx : todo = 10'h348; // Word |
8'b001_01xxx : todo = 10'h348; |
8'b001_001xx : todo = 10'h348; |
8'b001_0001x : todo = 10'h224; |
8'b001_00001 : todo = 10'h112; |
// |
8'b01x_1xxxx : todo = 10'h328; // DWord |
8'b01x_01xxx : todo = 10'h328; |
8'b01x_001xx : todo = 10'h328; |
8'b01x_0001x : todo = 10'h328; |
8'b01x_00001 : todo = 10'h214; |
// |
8'b100_xxxxx : todo = 10'h011; // the opcodes CMPS and SKPS work on a single element |
8'b101_xxxxx : todo = 10'h112; |
8'b11x_xxxxx : todo = 10'h214; |
default : todo = 10'hxxx; |
endcase |
|
always @(posedge BCLK) if (op_str) todo_reg <= todo[9:4]; // store for next phase 51 |
|
assign weiter = mehr | (pfad_5[3:0] != 4'h0); |
|
assign STRING = {1'b0,ACB_ZERO,weiter,( op_str ? todo[9:8] : todo_reg[9:8] )}; // ACB_ZERO is delay |
|
// +++++++++++++ Format 6 opcodes : ADDP + SUBP are done in DP_FPU ++++++++++++++++++++ |
|
wire rot,ash,lsh,eis_op; |
wire [7:0] sh_count; |
wire [4:0] shcode; // comes from SHIFTER |
|
reg [4:0] disp_reg; // for EXT/INS |
reg [2:0] offs_reg; // for INSS |
wire exin_op,exin_op2; |
wire [4:0] shval_ei; |
wire [7:0] sh_exin; |
|
assign rot = (OPCODE[3:0] == 4'h0); |
assign ash = (OPCODE[3:0] == 4'h1); |
assign lsh = (OPCODE[3:1] == 3'b010); // 5 is LSH , but 4 is Trap(UND) and is used for right-shift |
|
assign eis_op = (OPCODE == 8'h73) | (OPCODE[7] & ~OPCODE[1] & inss_op); // EXTSi | INSSi at OPCODE= |
assign exin_op = exin_cmd & (OPCODE[7:4] == 4'h8); // identifies EXT/INS |
assign exin_op2 = (exin_cmd | inss_op) & (OPCODE[7:4] == 4'h6); // identifies LSH |
|
always @(posedge BCLK) disp_reg <= DISP; // at EXT the path via ADDR is already used for DEST !!! |
always @(posedge BCLK) if (OPCODE[7]) offs_reg <= SRC1[7:5]; // for INSS , OPCODE=80h |
|
// Byte for external Bit source, Double for Register |
assign selbits = (bit_reg | eis_op | exin_op) ? (exin_op ? disp_reg : SRC1[4:0]) : {2'b00,BITSEL}; |
|
assign shval_ei = inss_op ? {2'b00,offs_reg} : (bit_reg ? SRC1[4:0] : {2'b00,SRC1[2:0]}); |
assign sh_exin[4:0] = extract ? (5'd0 - shval_ei) : shval_ei; // EXT : right shift, INS : left shi |
assign sh_exin[7:5] = (shval_ei == 5'd0) ? 3'b000 : {3{extract}}; // Special case : 0 has no negati |
|
// LSH shift by 16 bit to right |
assign sh_count = (OPCODE[3:0] == 4'h4) ? 8'hF0 : (exin_op2 ? sh_exin : SRC1[7:0]); |
|
assign BMCODE = (bit_op | eis_op | exin_op) ? {(eis_op | exin_op),(bit_op | exin_op),selbits} : {2' |
|
SHIFTER shift_inst (.MASKE(BMASKE), .ROT(rot), .ASH(ash), .LSH(lsh), .SH_DAT(SRC2), .SH_VAL(sh_cou |
.MASK_SEL(shcode), .SIZE(BWD), .SH_OUT(shdat) ); |
|
always @(BWD or SRC2 or neg_op or dw_info) |
casex ({neg_op,(dw_info | BWD[1]),BWD[0]}) // special case ADJSPi |
3'b000 : bwd_daten2 = {{24{SRC2[7]}}, SRC2[7:0]}; // Sign Extension |
3'b001 : bwd_daten2 = {{16{SRC2[15]}},SRC2[15:0]}; |
3'b1xx : bwd_daten2 = 32'h0; // is used for ABSi and NEGi |
default : bwd_daten2 = SRC2; |
endcase |
|
always @(OPCODE or SRC2 or BMASKE or addsub_q or bwd_daten1 or SRC1 or shdat or DP_OUT) |
casex (OPCODE[3:0]) |
4'b001x : pfad_6 = SRC2 & ~BMASKE; // CBIT & CBITI |
4'b011x : pfad_6 = SRC2 | BMASKE; // SBIT & SBITI |
4'b1000 : pfad_6 = addsub_q; // NEG |
4'b1001 : pfad_6 = {SRC1[31:1],~SRC1[0]}; // NOT |
4'b1010 : pfad_6 = SRC1; // Special case 6A : not used normal -> op_lmr ! |
4'b1100 : pfad_6 = bwd_daten1[31] ? addsub_q : SRC1; // ABS |
4'b1101 : pfad_6 = ~SRC1; // COM |
4'b1110 : pfad_6 = SRC2 ^ BMASKE; // IBIT |
4'b1x11_: pfad_6 = DP_OUT; // ADDP + SUBP |
default : pfad_6 = shdat; // Result of Barrelshifter |
endcase |
|
// ++++++++++++++ Format 7 : MUL +++++++++++++++++++++++ |
|
// This Condition-Code Decoder is written twice ... see DECODER |
|
reg sc_bit; |
wire sc_negativ,sc_zero,sc_flag,sc_larger,sc_carry_psr; |
|
assign sc_negativ = PSR[7]; |
assign sc_zero = PSR[6]; |
assign sc_flag = PSR[5]; |
assign sc_larger = PSR[2]; |
assign sc_carry_psr = PSR[0]; |
|
always @(SRC1 or sc_zero or sc_carry_psr or sc_larger or sc_negativ or sc_flag) |
case (SRC1[3:0]) |
4'h0 : sc_bit = sc_zero; // EQual |
4'h1 : sc_bit = ~sc_zero; // Not Equal |
4'h2 : sc_bit = sc_carry_psr; // Carry Set |
4'h3 : sc_bit = ~sc_carry_psr; // Carry Clear |
4'h4 : sc_bit = sc_larger; // Higher |
4'h5 : sc_bit = ~sc_larger; // Lower or Same |
4'h6 : sc_bit = sc_negativ; // Greater Than |
4'h7 : sc_bit = ~sc_negativ; // Less or Equal |
4'h8 : sc_bit = sc_flag; // Flag Set |
4'h9 : sc_bit = ~sc_flag; // Flag Clear |
4'hA : sc_bit = ~sc_larger & ~sc_zero; // LOwer |
4'hB : sc_bit = sc_larger | sc_zero; // Higher or Same |
4'hC : sc_bit = ~sc_negativ & ~sc_zero; // Less Than |
4'hD : sc_bit = sc_negativ | sc_zero; // Greater or Equal |
4'hE : sc_bit = 1'b1; // True |
4'hF : sc_bit = 1'b0; // False |
endcase |
|
reg [3:0] bytes2anz; |
wire [23:0] and_src1; |
wire [31:0] movxz_dat; |
wire [4:0] kurz_anz; |
wire [31:0] ext_sh4,ext_sh2; |
|
assign and_src1 = {{16{BWD[1]}},{8{BWD[0]}}} & SRC1[31:8]; // for MOVZ |
|
assign movxz_dat = (OPCODE[1] ^ OPCODE[0]) ? {and_src1,SRC1[7:0]} : bwd_daten1; // MOVZ.. ? |
|
always @(ADDR or BWD) |
casex (BWD[1:0]) |
2'b00 : bytes2anz = ADDR[3:0]; |
2'b01 : bytes2anz = {1'b0,ADDR[3:1]}; |
2'b1x : bytes2anz = {2'b0,ADDR[3:2]}; |
endcase |
|
assign kurz_anz = {1'b0,bytes2anz} + 5'h01; // count for MOVM/CMPM |
|
assign ext_sh4 = SRC1[7] ? {4'h0,SRC2[31:4]} : SRC2; // EXTSi |
assign ext_sh2 = SRC1[6] ? {2'b0,ext_sh4[31:2]} : ext_sh4; |
|
always @(*) |
casex (OPCODE[3:0]) |
4'b0011 : pfad_7 = (SRC1[5] ? {1'b0,ext_sh2[31:1]} : ext_sh2) & BMASKE; // EXTSi |
4'b01xx : pfad_7 = movxz_dat; // MOVXBW, MOVZBW, MOVZiD, MOVXiD |
4'b1000 : pfad_7 = MRESULT[31:0]; // MULi |
4'b1010 : pfad_7 = {27'h0,(kurz_st ? kurz_anz : {4'h0,sc_bit})}; // SCond or start of MOVM/CMPM |
default : pfad_7 = DP_OUT; // DIV etc. |
endcase |
|
// ++++++++++++++ Format 8 : multiple opcodes +++++++++++++++++++++++ |
|
reg chk_p1; |
reg [31:0] ins_maske; |
|
wire [4:0] ffs_out; |
wire [15:0] low_bou,upp_bou,zeiger,chk_upp,chk_low; |
wire flag_up,flag_lo; |
|
FFS_LOGIK ffs_unit (.SRC1(SRC1), .SRC2(SRC2[4:0]), .BWD(BWD), .FLAG(ffs_flag), .DOUT(ffs_out) ); |
|
// CHECK : SRC1 are the Bounds |
assign low_bou = BWD[0] ? SRC1[31:16] : {{8{SRC1[15]}},SRC1[15:8]}; |
assign upp_bou = BWD[0] ? SRC1[15:0] : {{8{SRC1[7]}}, SRC1[7:0]}; |
assign zeiger = BWD[0] ? SRC2[15:0] : {{8{SRC2[7]}}, SRC2[7:0]}; |
|
assign chk_upp = upp_bou - zeiger; // F=1 if upp_bou < zeiger |
assign chk_low = zeiger - low_bou; // F=1 if zeiger < low_bou |
|
assign flag_up = (upp_bou[15] == zeiger[15]) ? chk_upp[15] : upp_bou[15]; // See NL Definition |
assign flag_lo = (low_bou[15] == zeiger[15]) ? chk_low[15] : zeiger[15]; |
|
always @(posedge BCLK) chk_p1 <= chk_op & BWD[1]; // CHECKD needs 2 cycles to execute |
|
assign chk_flag = BWD[1] ? (chk_p1 ? (nl_int[1] | psr_low[5]) : nl_int[1]) : (flag_up | flag_lo); |
|
always @(posedge BCLK) ins_maske <= shdat; // expensive solution in terms of LEs ! |
|
always @(*) |
casex (OPCODE[3:0]) // CVTP (81) has no OPCODE ! |
4'b000x : pfad_8 = (extract ? SRC2 : 32'hFFFF_FFFF) & BMASKE; // EXT, the other form is for INS |
4'b0010 : pfad_8 = (SRC1 & ins_maske) | (SRC2 & ~ins_maske); // INS ins_maske[] ? SRC1[] : SRC2[ |
4'b0011 : pfad_8 = BWD[1] ? addsub_q : {16'h0,chk_low}; |
4'b0101 : pfad_8 = {24'hxx_xxxx,3'b000,ffs_out}; |
default : pfad_8 = {4'hx,push_psr,SRC1[15:0]}; // Opcode x'87-x'8F is used at CXP and therefore |
endcase |
|
// ++++++++++++++ Format 11 : Floating-Point Datapath +++++++++++++++++++++++++++++++ |
|
assign pfad_11 = (OPCODE[1:0] == 2'b01) ? |
{((OPCODE[3:2] == 2'b11) ? 1'b0 : (SRC1[31] ^ OPCODE[2])),SRC1[30:0]} // ABSf , NEGf + MOVf |
: DP_OUT; |
|
endmodule |
/trunk/rtl/STEUER_MISC.v
0,0 → 1,957
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: STEUER_MISC.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. OPDEC_REG Central Instruction Register |
// 2. PROG_COUNTER Program Counters |
// 3. REG_LIST Register List Evaluation |
// 4. ILL_UNDEF Illegal and Undefined Opcodes Detection |
// 5. GRUPPE_2 Decoder and State Machine for GRUPPE_2 Opcodes |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. OPDEC_REG Central Instruction Register |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module OPDEC_REG ( BCLK, BRESET, NEW, ACC_STAT, PROT_ERROR, ALSB, USED, IC_DIN, IC_INIT, DC_INIT, Y_ |
OPREG, ANZ_VAL, IC_READ, NEW_PC, NEXT_ADR, DATA_HOLD, ABORT, IC_TEX, INIT_DONE); |
|
input BCLK,BRESET; |
input NEW; // a program jump took place |
input [3:0] ACC_STAT; // ICACHE signals data is available or Abort |
input PROT_ERROR; // comes direct from ICACHE |
input [1:0] ALSB; // lower addressbits of access address to ICACHE |
input [2:0] USED; // Message from DECODER how many bytes were used |
input [31:0] IC_DIN; // ICACHE Data |
input IC_INIT,DC_INIT,Y_INIT; // Initialising or new setting is running |
input RESTART; // "Break" of Instruction Pipeline - set up new i.e. after load of PSR |
input STOP_IC; // For LMR and CINV |
|
output [55:0] OPREG; // this is the Central Opcode Decode Register, length = 7 bytes |
output [2:0] ANZ_VAL; |
output IC_READ; |
output NEW_PC; |
output NEXT_ADR; |
output DATA_HOLD; |
output ABORT; |
output [2:0] IC_TEX; |
output INIT_DONE; |
|
reg [55:0] OPREG; |
reg [2:0] ANZ_VAL; |
reg IC_READ; |
reg ABORT; |
reg abort_flag; |
reg [2:0] IC_TEX; |
reg [55:0] data_to_ri; |
reg old_init; |
reg pre_new; |
reg new_reg; |
reg nseq_flag; |
reg stop_init; |
|
wire [2:0] new_anz; |
wire new_restart; |
wire acc_err,acc_ok,acc_ende; |
|
// ++++++++++++++++++++ Evaluation of ACC_STAT from Instructioncache ++++++++++++++++++++++++++++ |
|
// ACC_STAT[3:0] : PROT_ERROR , ABO_LEVEL1 , ABORT , ACC_OK |
|
assign acc_err = ACC_STAT[3] | ACC_STAT[1] | PROT_ERROR; |
assign acc_ok = ACC_STAT[0]; |
|
always @(posedge BCLK or negedge BRESET) // is kept until DECODER really needs the data ! |
if (!BRESET) ABORT <= 1'b0; |
else ABORT <= (acc_err & ~(new_restart | pre_new)) | (ABORT & ~NEW_PC); |
|
always @(posedge BCLK) if (acc_err) IC_TEX <= (ACC_STAT[3] | PROT_ERROR) ? {nseq_flag,2'b11} : {nse |
|
always @(posedge BCLK) nseq_flag <= NEW_PC | (nseq_flag & ~acc_ok); // for MMU Status Register |
|
always @(posedge BCLK) abort_flag <= acc_err; |
assign acc_ende = ~IC_READ | acc_ok | abort_flag; // abort_flag one cycle later is ok ! If no ICach |
|
assign new_restart = NEW | RESTART; // They are pulses |
|
// Branch work out : NEW/RESTART notice if access still not ended |
always @(posedge BCLK) pre_new <= (new_restart & ~acc_ende) | (pre_new & ~acc_ende & BRESET); |
|
assign NEW_PC = (new_restart | pre_new) & acc_ende; // At the end of access geenerate new address ! |
|
// There are 2 "NEW/RESTART" : "new_restart" combinatorical out of DECODER, "pre_new" out of Regist |
always @(posedge BCLK) new_reg <= new_restart | pre_new | (new_reg & ~acc_ende & BRESET); |
|
always @(USED or OPREG) // Data first shift to the right |
case (USED) |
3'b000 : data_to_ri = OPREG; |
3'b001 : data_to_ri = { 8'hxx, OPREG[55:8]}; |
3'b010 : data_to_ri = {16'hxxxx,OPREG[55:16]}; |
3'b011 : data_to_ri = {24'hxx_xxxx,OPREG[55:24]}; |
3'b100 : data_to_ri = {32'hxxxx_xxxx,OPREG[55:32]}; |
3'b101 : data_to_ri = {40'hxx_xxxx_xxxx,OPREG[55:40]}; |
3'b110 : data_to_ri = {48'hxxxx_xxxx_xxxx,OPREG[55:48]}; |
3'b111 : data_to_ri = 56'hxx_xxxx_xxxx_xxxx; |
endcase |
|
assign new_anz = ANZ_VAL - USED; |
|
always @(posedge BCLK) |
casex ({new_reg,acc_ok,ALSB,new_anz}) |
7'b1_100_xxx : OPREG <= {24'hxx_xxxx,IC_DIN}; |
7'b1_101_xxx : OPREG <= {32'hxxxx_xxxx,IC_DIN[31:8]}; |
7'b1_110_xxx : OPREG <= {40'hxx_xxxx_xxxx,IC_DIN[31:16]}; |
7'b1_111_xxx : OPREG <= {48'hxxxx_xxxx_xxxx,IC_DIN[31:24]}; |
7'b0_0xx_xxx : OPREG <= data_to_ri; |
7'b0_1xx_000 : OPREG <= {24'hxx_xxxx,IC_DIN}; |
7'b0_1xx_001 : OPREG <= { 16'hxxxx,IC_DIN, data_to_ri[7:0]}; |
7'b0_1xx_010 : OPREG <= { 8'hxx,IC_DIN,data_to_ri[15:0]}; |
7'b0_1xx_011 : OPREG <= { IC_DIN,data_to_ri[23:0]}; |
7'b0_1xx_1xx : OPREG <= data_to_ri; |
endcase |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) ANZ_VAL <= 3'b000; |
else |
casex ({new_restart,new_reg,acc_ok,new_anz[2]}) |
4'b1x_x_x : ANZ_VAL <= 3'b000; // hard setting to 0 |
4'b01_0_x : ANZ_VAL <= 3'b000; |
4'b01_1_x : ANZ_VAL <= pre_new ? 3'b000 : 3'b100 - {1'b0,ALSB}; |
4'b00_0_x : ANZ_VAL <= new_anz; |
4'b00_1_0 : ANZ_VAL <= new_anz + 3'b100; |
4'b00_1_1 : ANZ_VAL <= new_anz; |
endcase |
|
assign NEXT_ADR = new_reg ? (acc_ok & ~pre_new) : (acc_ok & ~new_anz[2]); // switches MUX at PC res |
|
// Instruction CACHE Control : READ is coming after all INITs are done |
|
always @(posedge BCLK) old_init <= IC_INIT | DC_INIT | Y_INIT; |
|
assign INIT_DONE = old_init & ~IC_INIT & ~DC_INIT; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) stop_init <= 1'b0; |
else stop_init <= stop_init | IC_READ; |
|
// The INIT_DONE should come after Reset. But it comes too at LMR PTB therefore extra enable after |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) IC_READ <= 1'b0; |
else IC_READ <= (IC_READ & ~acc_err & ~(STOP_IC & acc_ok)) | NEW_PC | (INIT_DONE & ~stop_init); |
|
// The Opcode-Register can not store the data : keep them in ICACHE at IO-access |
assign DATA_HOLD = ~new_restart & ~new_reg & acc_ok & new_anz[2]; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. PROG_COUNTER Program Counters |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module PROG_COUNTER ( BCLK, BRESET, NEW, LOAD_PC, NEW_PC, NEXT_ADR, NEXT_PCA, DISP, PC_NEW, USED, US |
ADIVAR, PC_ARCHI, PC_ICACHE, PC_SAVE, ALSB, IC_USER); |
|
input BCLK,BRESET; |
input NEW; |
input LOAD_PC; |
input NEW_PC; |
input NEXT_ADR; |
input NEXT_PCA; |
input [31:0] DISP; |
input [31:0] PC_NEW; |
input [2:0] USED; |
input USER; |
input SAVE_PC; |
input FPU_TRAP; |
input ADIVAR; |
|
output [31:0] PC_ARCHI; // goes to Datapath |
output [31:0] PC_ICACHE; |
output [31:0] PC_SAVE; // is the return address |
output [1:0] ALSB; |
output IC_USER; |
|
reg [31:0] PC_ARCHI; |
reg [31:0] pc_adduse; |
reg [31:0] pc_ic_reg; |
reg [31:0] fpu_trap_pc; |
reg IC_USER; |
|
wire [31:0] branch,pc_jump,next_pc,pc_icache_i; |
|
assign PC_SAVE = pc_adduse + {29'h0,USED}; |
assign branch = PC_ARCHI + DISP; |
|
assign pc_jump = LOAD_PC ? PC_NEW : branch; |
|
assign next_pc = NEW ? pc_jump : PC_SAVE; // Only at NEW is the DISP correct ! |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) pc_adduse <= 32'h0; |
else |
pc_adduse <= next_pc; |
|
// The Architectur - PC : Address mode "Programm Memory"-relativ |
// no BRESET because NEXT_PCA is immediately valid |
always @(posedge BCLK) |
if (FPU_TRAP) PC_ARCHI <= fpu_trap_pc; // go back ! |
else |
if (NEXT_PCA) PC_ARCHI <= pc_adduse; |
|
always @(posedge BCLK) if (SAVE_PC) fpu_trap_pc <= PC_ARCHI; // Special storage for PC for FPU Trap |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) pc_ic_reg <= 32'h0; |
else |
pc_ic_reg <= pc_icache_i; |
|
// NEW is only one cycle long - but in pc_adduse is the PC stored when ACC_OK is not there and ther |
// is used to initiate a new access in ICACHE |
assign pc_icache_i = NEW_PC ? (NEW ? pc_jump : pc_adduse) : (NEXT_ADR ? ({pc_ic_reg[31:2],2'b00} + |
|
// This MUX is extra for LMR IVAR,... and CINV build in |
assign PC_ICACHE = {(ADIVAR ? PC_NEW[31:4] : pc_icache_i[31:4]),pc_icache_i[3:0]}; |
|
assign ALSB = pc_ic_reg[1:0]; // for OPDEC_REG |
|
// The IC_USER flag is allowed to switch synchronously with one cycle delay to PC_ICACHE |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) IC_USER <= 1'b0; |
else |
if (NEW_PC) IC_USER <= USER; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. REG_LIST Register List Evaluation |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module REG_LIST ( DIN, IPOS, INIT, OPOS, VALID); |
|
// Detects set bits in register list for SAVE/RESTORE & ENTER/EXIT |
|
input [7:0] DIN; |
input [2:0] IPOS; |
input INIT; |
output [2:0] OPOS; |
output VALID; |
|
reg [7:1] filter; |
wire [7:0] mdat_0; |
wire [3:0] mdat_1; |
wire [1:0] mdat_2; |
|
always @(IPOS or DIN) |
case (IPOS) |
3'd0 : filter = DIN[7:1]; |
3'd1 : filter = {DIN[7:2],1'b0}; |
3'd2 : filter = {DIN[7:3],2'b0}; |
3'd3 : filter = {DIN[7:4],3'b0}; |
3'd4 : filter = {DIN[7:5],4'b0}; |
3'd5 : filter = {DIN[7:6],5'b0}; |
3'd6 : filter = {DIN[7] ,6'b0}; |
3'd7 : filter = 7'b0; |
endcase |
|
assign mdat_0 = INIT ? DIN : {filter,1'b0}; |
assign OPOS[2] = (mdat_0[3:0] == 4'h0); |
assign mdat_1 = OPOS[2] ? mdat_0[7:4] : mdat_0[3:0]; |
assign OPOS[1] = (mdat_1[1:0] == 2'b00); |
assign mdat_2 = OPOS[1] ? mdat_1[3:2] : mdat_1[1:0]; |
assign OPOS[0] = ~mdat_2[0]; |
assign VALID = (mdat_2 != 2'b00); |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. ILL_UNDEF Illegal and Undefined Opcodes Detection |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ILL_UNDEF (OPREG, ANZ_VAL, USER, CFG, ILL, UNDEF ); |
|
input [23:0] OPREG; |
input [2:0] ANZ_VAL; |
input [3:1] CFG; // 3=CUSTOM,2=MMU,1=FPU |
input USER; |
|
output reg ILL; |
output UNDEF; |
|
reg undef_opc; |
reg undef_am; |
reg undef_im; |
|
wire [2:0] valid; |
wire gen12,gen22,gen13,gen23; |
wire igen12,igen22,igen13,igen23; |
wire lsbes; |
|
parameter udef_amode = 5'b10011; // Undefined Addressing Mode |
parameter imode = 5'b10100; // Immediate Addressing Mode |
|
// [2]= minimum 3, [1]= minimum 2, [0]=minimum 1 |
assign valid = {(ANZ_VAL[2] | (ANZ_VAL[1:0] == 2'b11)),(ANZ_VAL[2:1] != 2'b00),(ANZ_VAL != 3'b000)} |
assign lsbes = (OPREG[1:0] == 2'b10); // Tag of all 3 Byte opcodes |
|
// +++++++++++++++++++++++++ Detect illegale opcodes +++++++++++++++++++ |
|
always @(OPREG or lsbes or valid or USER) |
casex ({valid[2:1],OPREG[13:2],lsbes}) |
15'bx1_xx_x000_1x10_11_0 : ILL = USER; // SPRi/LPRi DCR |
15'bx1_xx_x001_xx10_11_0 : ILL = USER; // SPRi/LPRi BPC/DSR |
15'bx1_xx_xx10_xx10_11_0 : ILL = USER; // SPRi/LPRi CAR/CFG/PSR |
15'bx1_xx_x101_1x10_11_0 : ILL = USER; // SPRi/LPRi USP |
15'bx1_xx_x111_0x10_11_0 : ILL = USER; // SPRi/LPRi INTBASE |
15'bx1_xx_x0x1_0111_11_x : ILL = USER & OPREG[0]; // BICPSRW,BISPSRW |
15'bx1_00_10xx_0000_11_1 : ILL = USER; // SETCFG - Achtung : is coded as 2 Byte Opcode |
15'b1x_00_xxxx_0001_11_1 : ILL = USER; // LMR/SMR/RDVAL/WRVAL |
15'b1x_10_01xx_0001_11_1 : ILL = USER; // CINV |
default : ILL = 1'b0; |
endcase |
|
// ++++++++++++++++++++++++ Detect Undefined opcodes +++++++++++++++ |
|
always @(OPREG or lsbes or valid or CFG) |
casex ({valid,OPREG[13:2],lsbes}) |
16'bx1x_xx_xxxx_1111_110 : undef_opc = 1'b1; // Format 3 : xxx1 |
16'bx1x_xx_x100_0111_110 : undef_opc = 1'b1; // Format 3 : 1000 |
16'b1xx_1x_xxxx_0000_111 : undef_opc = 1'b1; // Format 5 : 1xxx |
16'b1xx_01_xxxx_0000_111 : undef_opc = 1'b1; // Format 5 : 01xx |
16'b1xx_01_00xx_0100_111 : undef_opc = 1'b1; // Format 6 : 0100 |
16'b1xx_10_10xx_x100_111 : undef_opc = 1'b1; // Format 6/7 : 1010 |
16'b1xx_xx_xxxx_x011_111 : undef_opc = ~CFG[1]; // Format 9/11 : FPU Befehle wie MOVif etc. und |
16'b1xx_xx_xxxx_1111_111 : undef_opc = ~CFG[1]; // Format 12 : FPU Befehle wie POLYf etc. |
16'b1xx_x1_xxxx_0001_111 : undef_opc = 1'b1; // Format 14 : x1xx |
16'b1xx_10_00xx_0001_111 : undef_opc = 1'b1; // Format 14 : 1000 |
16'b1xx_10_1xxx_0001_111 : undef_opc = 1'b1; // Format 14 : 101x |
16'b1xx_00_1xxx_0001_111 : undef_opc = ~CFG[2] | ~OPREG[18]; // Format 14 : LMR/SMR |
16'b1xx_xx_xxxx_x011_011 : undef_opc = ~CFG[3]; // Format 15.1/15.5 : CUSTOM CCV0, CCAL0 etc. |
16'b1xx_xx_xxxx_0001_011 : undef_opc = 1'b1; // Format 15.0 - not yet in, requires HW change |
16'b1xx_xx_xxxx_x1x1_011 : undef_opc = 1'b1; // Format 15 : rest |
16'b1xx_xx_xxxx_1001_011 : undef_opc = 1'b1; // Format 15.4 |
// completely undefined : |
16'bxx1_xx_xxxx_0111_111 : undef_opc = 1'b1; // Format 10 |
16'bxx1_xx_xxxx_100x_111 : undef_opc = 1'b1; // Format 13/18 |
16'bxx1_xx_xxxx_x101_111 : undef_opc = 1'b1; // Format 16/17 |
16'bxx1_xx_xxxx_xxx0_011 : undef_opc = 1'b1; // Format 19 |
default : undef_opc = 1'b0; |
endcase |
|
// 2. Undefined Addressing mode 5'b10011 |
|
assign gen12 = (OPREG[15:11] == udef_amode); |
assign gen22 = (OPREG[10:6] == udef_amode); |
assign gen13 = (OPREG[23:19] == udef_amode); |
assign gen23 = (OPREG[18:14] == udef_amode); |
|
always @(OPREG or valid or gen12 or gen22 or gen13 or gen23) |
if (valid[2] && (OPREG[7:5] != 3'b000) && (OPREG[3:0] == 4'b1110)) undef_am = gen13 | gen23; // ne |
else |
undef_am = valid[1] & gen12 & (OPREG[1:0] != 2'b10) & ((OPREG[3:2] != 2'b11) & gen22); // all |
|
// 3. When is Immediate not allowed ? |
|
assign igen12 = (OPREG[15:11] == imode); |
assign igen22 = (OPREG[10:6] == imode); |
assign igen13 = (OPREG[23:19] == imode); |
assign igen23 = (OPREG[18:14] == imode); |
|
always @(*) |
casex ({valid[2:1],OPREG[13:2],lsbes}) |
15'bx1_xxxxxx_x0xx11_0 : undef_im = igen12 & (OPREG[5:4] != 2'b01); // Format 2 : ADDQD,SPR,Sco |
15'bx1_xxxxxx_x10111_0 : undef_im = igen12; // Format 2 : ACB,MOVQ |
15'bx1_xxxxx0_011111_0 : undef_im = igen12; // Format 3 : CXPD,JUMP,JSR |
15'bx1_xxxxxx_xxxxx0_0 : undef_im = igen22; // Format 4 |
15'bx1_xxxxxx_xxxx01_0 : undef_im = (igen12 & (OPREG[5:4] == 2'b10)) // Format 4 : SRC1 - not AD |
|(igen22 & (OPREG[5:4] != 2'b00)); // Format 4 : SRC2 - CMP |
15'b1x_xxxxxx_x10011_1 : undef_im = igen23; // Format 6+7 |
15'b1x_xxx0xx_0x1011_1 : undef_im = igen13 | igen23; // Format 8 EXT,CVTP |
15'b1x_xxx0xx_101011_1 : undef_im = igen23; // Format 8 : INS |
15'b1x_xxx0xx_111011_1 : undef_im = igen13; // Format 8 : CHECK |
15'b1x_xxx1xx_101011_1 : undef_im = igen13 | igen23; // Format 8 MOVUS,MOVSU |
15'b1x_xxx1xx_011011_1 : undef_im = igen23; // Format 8 : FFS |
15'b1x_xxxxxx_001111_1 : undef_im = igen23; // Format 9 |
15'b1x_xxxxxx_101111_1 : undef_im = igen23 & (OPREG[13:10] != 4'h2); // Format 10 without CMPf |
15'b1x_010xxx_111111_1 : undef_im = igen23; // Format 12 SCALB+LOGB |
15'b1x_000xxx_000111_1 : undef_im = igen13; // Format 14 RDVAL+WRVAL |
15'b1x_0011xx_000111_1 : undef_im = igen13; // Format 14 SMR |
default : undef_im = 1'b0; |
endcase |
|
// Final Message : |
|
assign UNDEF = undef_opc | undef_am | undef_im; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 5. GRUPPE_2 Decoder and State Machine for GRUPPE_2 Opcodes |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module GRUPPE_2 ( BCLK, PHASE_0, OPREG, PHASE, SRC_1, SRC_2, REGA1, REGA2, IRRW1, IRRW2, ADRD1, ADRD |
PHRD1, PHRD2, NXRD1, NXRW2, ACCA, OPERA, |
STATE_0, STATE_GROUP_50, STATE_GROUP_60 ); |
|
|
input BCLK,PHASE_0; |
input [13:0] OPREG; |
input [3:0] PHASE; // nur die 4 LSBs |
// Source 1 & 2 Inputs |
input [6:0] SRC_1,SRC_2,REGA1,REGA2,IRRW1,IRRW2; |
input [18:0] ADRD1,ADRD2,EXR12,EXR22; |
input [3:0] PHRD1,PHRD2; |
input [3:0] NXRD1,NXRW2; |
input [3:0] ACCA; // ACCA = Access type : 0x Register |
// [3:2] or [1:0] 10 Memory |
// 11 Memory + Index |
input [10:0] OPERA; |
|
output [66:0] STATE_0; |
output [66:0] STATE_GROUP_50,STATE_GROUP_60; |
|
reg [66:0] STATE_GROUP_50,STATE_GROUP_60; |
reg [66:0] STATE_0,state_50,state_53,state_54,state_55,state_58,state_59,state_5A; |
reg [4:0] op_code,op_reg_reg; |
reg [7:0] phsrc1,phsrc2; |
reg [5:0] chkreg; |
reg [1:0] bwdreg; |
reg tbit_flag,size_dw; |
reg inss_flag; |
|
wire [18:0] exoffset,re_wr; |
wire [10:0] op_kust,op_bwd; |
wire [7:0] phchk; |
wire [4:0] op_reg; |
wire [6:0] src_1l,src_2l; |
wire [5:0] dest_2; |
wire [3:0] get8b_s,get8b_d; |
wire [6:0] rd_reg; |
wire [10:0] op_zext; |
wire [3:0] imdi; |
|
parameter dont_care = 67'hx_xxxx_xxxx_xxxx_xxxx; |
// Address-Field : Size:2 RD WR LDEA FULLACC INDEX:4 SPUPD disp_val:4 POST CLRMSW SRC2SEL:2 |
parameter addr_nop = 19'h0; // alle Parameter auf 0 |
parameter disp2ea = 19'bxx_0010_0000_0_0000_0010; // pass DISP |
parameter case_op = 19'bxx_0010_1000_0_0000_0001; // SRC1 add to PC_ARCHI |
parameter read_byb = 19'b00_1011_11xx_0_0000_0011; // read of SRC2 for Bit opcodes |
parameter exr11 = {2'b10 ,4'b1011,4'h0 ,9'h080}; // 2. access External with Mem.-Pointer + 4* Dis |
parameter adrcvtp = 19'bxx_0010_0111_0_0000_0000; // for CVTP |
parameter addone = 19'bxx_0010_0100_0_0000_0000; // for INDEX : SRC1 + SRC2 , simple Add without Fl |
parameter addind = 19'bxx_0010_0100_0_0000_0011; // for INDEX : SRC1 + EA |
parameter src_x = 7'hxx; |
parameter dest_x = 6'hxx; |
parameter imme = {1'b1,6'hxx}; |
parameter F0 = 7'h20; |
parameter F0_h = 7'h21; |
parameter w_F0 = 6'h20; |
parameter w_F0_h = 6'h21; |
parameter temp_l = 6'h3C; |
parameter temp_h = 6'h3D; // Second last place for 8B TEMP Register |
parameter temp_1 = 6'h3E; |
parameter rtmpl = 7'h3C; |
parameter rtmph = 7'h3D; |
parameter rtmp1 = 7'h3E; |
parameter op_mov = {3'bxxx,8'h45}; |
parameter op_adr = {3'bxxx,8'h49}; |
parameter op_addl = {3'b0xx,8'hB0}; |
parameter op_addf = {3'b1xx,8'hB0}; |
parameter op_mull = {3'b0xx,8'hBC}; |
parameter op_mulf = {3'b1xx,8'hBC}; |
parameter op_truf = {3'b101,8'h9A}; // TRUNCFW for SCALBF |
parameter op_trul = {3'b001,8'h9A}; // TRUNCLW for SCALBL |
parameter op_stpr = {3'b1xx,8'h54}; // Special-Op for String opcodes |
parameter op_lsh = {3'b011,8'h65}; // EXT : shift to right : DOUBLE ! |
parameter op_msk = {3'b011,8'h80}; // reuse of EXT Opcode at INS ! |
parameter op_mul = {3'b011,8'h78}; // INDEX |
parameter op_rwv = {3'bxxx,8'hE0}; // RDVAL+WRVAL |
|
always @(OPREG) // whether the Opcode is valid is decided in DECODER ! |
casex (OPREG) // [13:0] |
14'bxx_xxxx_1111_1110 : op_code = {2'b01,OPREG[11:10],OPREG[8]}; // DOT/POLY/SCALB |
14'b00_0xxx_0000_1110 : op_code = 5'b1_0000; // MOVS/CMPS |
14'b00_11xx_0000_1110 : op_code = 5'b1_0000; // SKPS |
14'b00_0xxx_1100_1110 : op_code = 5'b1_0001; // MOVM/CMPM |
14'bxx_xx10_0111_11xx : op_code = 5'b1_0010; // JUMP/JSR |
14'bxx_x111_0111_11xx : op_code = 5'b1_0011; // CASE |
14'bxx_xxxx_xx11_010x : op_code = 5'b1_0100; // TBIT |
14'bxx_xxxx_xx11_0111 : op_code = 5'b1_0100; // TBIT |
14'b0x_1xxx_0100_1110 : op_code = 5'b1_0100; // CBIT/SBIT |
14'b11_10xx_0100_1110 : op_code = 5'b1_0100; // IBIT |
14'b00_11xx_1100_1110 : op_code = 5'b1_0101; // EXTS |
14'b10_x1xx_1100_1110 : op_code = 5'b1_0111; // DEI/MEI |
14'bxx_x0xx_1110_1110 : op_code = 5'b1_1000; // CHECK |
14'bxx_x0xx_0010_1110 : op_code = 5'b1_1010; // EXT |
14'bxx_x0xx_1010_1110 : op_code = 5'b1_1011; // INS |
14'b00_10xx_1100_1110 : op_code = 5'b1_1011; // INSS, the same like INS ! |
14'bxx_x0xx_0110_1110 : op_code = 5'b1_1100; // CVTP |
14'bxx_x1xx_0010_1110 : op_code = 5'b1_1101; // INDEX |
14'bxx_x000_0111_11xx : op_code = 5'b1_1110; // CXPD |
14'b00_0xxx_0001_1110 : op_code = 5'b1_1111; // RDVAL+WRVAL |
default : op_code = 5'b00_xxx; |
endcase |
|
always @(posedge BCLK) if (PHASE_0) op_reg_reg <= op_code; |
assign op_reg = PHASE_0 ? op_code : op_reg_reg; |
|
always @(PHRD1) // recode of States |
casex (PHRD1) |
4'h5 : phsrc1 = 8'h51; |
4'h6 : phsrc1 = 8'h52; |
4'hB : phsrc1 = 8'h53; // ok, is in default ... |
default : phsrc1 = 8'h53; |
endcase |
|
assign get8b_s = (PHRD1 == 4'hB) ? 4'hC : 4'h0; // Special case 8B Immeadiate, is used in State 53 |
|
always @(PHRD2) // recode of States |
casex (PHRD2) |
4'h5 : phsrc2 = 8'h56; |
4'h6 : phsrc2 = 8'h57; |
4'hB : phsrc2 = 8'h58; // ok, is in default ... |
default : phsrc2 = 8'h58; |
endcase |
|
assign get8b_d = (PHRD2 == 4'hB) ? 4'hC : 4'h0; // Special case 8B Immeadiate, is used in State 58 |
|
assign src_1l = {SRC_1[6:1],1'b0}; |
assign src_2l = {SRC_2[6:1],1'b0}; |
assign dest_2 = SRC_2[5:0]; |
|
assign phchk = {7'b0101_010,size_dw}; // Phase 54 or 55 |
|
assign op_kust = {1'bx,OPERA[9:8],8'h7A}; // Special-Opcode for MOVM/CMPM |
assign op_bwd = {1'bx,OPERA[9:8],8'h45}; // for CASE and Bit opcodes |
|
assign re_wr = {EXR22[18:17],4'b0101,4'h0, 9'h003}; // REUSE Address : Write of rmw , top 2 Bits |
|
always @(posedge BCLK) tbit_flag <= ~OPERA[1]; // due to Timing ... |
always @(posedge BCLK) size_dw <= OPERA[9]; |
|
always @(posedge BCLK) if (PHASE_0) chkreg <= {3'b000,OPREG[13:11]}; // for CHECK |
assign rd_reg = (PHASE_0) ? {4'b0,OPREG[13:11]} : {1'b0,chkreg}; // for read operation at EXT/INS |
|
always @(posedge BCLK) if (PHASE_0) bwdreg <= OPREG[9:8]; // only for INS/INSS ! |
assign op_zext = {1'bx,(PHASE_0 ? OPREG[9:8] : bwdreg),8'h76}; |
|
always @(posedge BCLK) if (PHASE_0) inss_flag <= OPREG[6]; // Difference INSS to INS |
assign imdi = inss_flag ? 4'h8 : 4'hE; // read Immediate or Displacement |
assign exoffset = inss_flag ? 19'b10_1011_0000_0_0000_0011 // Read of SRC2 at INSS |
: 19'b10_1011_1100_0_0000_0011; // Read of SRC1+Offset at EXT, SRC2+Offset at INS |
|
always @(*) |
casex (op_reg) |
5'b1_0000 : // MOVS Phase 0 : Entry 1. Pointer "in Page"-test prepare, 2. test for R0=0 , then jum |
begin |
STATE_0 = { addr_nop,8'h67, 7'h01, 7'h02, 1'b0,dest_x,op_stpr, 2'b00,2'b00,4'h0 }; // String |
state_50 = dont_care; |
state_53 = dont_care; |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b1_0001 : // MOVM Phase 0 : Entry with test for R0=0 , then jump to x'C0 |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { ADRD2, phsrc2,IRRW2, REGA2, 1'b1,temp_h,op_adr, 2'b00,2'b00,NXRW2 }; |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = { disp2ea, 8'h65, src_x, src_x, 1'b1,temp_1,op_adr, 2'b00,2'b00,4'b1110 }; // Read |
state_59 = { addr_nop,8'h67, rtmph, rtmp1, 1'b0,dest_x,op_stpr, 2'b00,2'b00,4'h0 }; // String |
state_5A = dont_care; |
end |
5'b1_0010 : // JUMP/JSR |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { addr_nop,8'h66, src_x, src_x, 1'b1,temp_h,op_adr, 2'b00,2'b00,4'h0 }; |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b1_1110 : // CXPD |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { addr_nop,8'h6B, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b1_1111 : // RDVAL+WRVAL |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { addr_nop,8'h00, src_x, src_x, 1'b0,dest_x,op_rwv, 2'b00,2'b10,4'h0 }; // LD_OU |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b1_0011 : // CASE |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { case_op, 8'h54, SRC_1, src_x, 1'b0,dest_x,op_bwd, 2'b00,2'b00,4'h0 }; |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; // only |
state_53 = { case_op, 8'h54, imme, src_x, 1'b0,dest_x,op_bwd, 2'b00,2'b00,4'h0 }; |
state_54 = { addr_nop,8'h66, src_x, src_x, 1'b1,temp_h,op_adr, 2'b00,2'b00,4'h0 }; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b1_0100 : // all Bit opcodes with Bit in memory. RMW Test in Phase x'59 = Special case, otherwis |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_54 = { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; // here S |
state_55 = dont_care; |
state_58 = { read_byb,8'h59, rtmph, src_x, 1'b0,dest_x,op_bwd, 2'b00,2'b00,4'h1 }; // next re |
state_59 = tbit_flag ? |
{ addr_nop,8'h00, src_x, imme, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h0 } // TBIT end |
: { re_wr, 8'h27, src_x, imme, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h1 }; // CBIT/SBIT/IBIT |
state_5A = dont_care; |
end |
5'b1_0101 : // EXTS : BASE Operand => TEMP, calculate address of Destination |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } // here Adr(DEST) |
: { addr_nop,8'h59, src_x, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h8 }; // 1 Byte Immedi |
state_55 = dont_care; |
state_58 = { addr_nop,8'h59, src_x, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h8 }; // 1 Byte |
state_59 = ACCA[1] ? // _..M. |
{ re_wr, 8'h27, imme, rtmph, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h1 } // result in memory |
: { addr_nop,8'h00, imme, rtmph, 1'b1,dest_2,OPERA, 2'b00,2'b00,4'h0 }; // result in Regi |
state_5A = dont_care; |
end |
5'b1_1010 : // EXT : BASE Operand => TEMP, calculate address of Destination |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h55, src_x, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; // Addr = |
state_54 = ACCA[1] ? |
( ACCA[3] ? |
{addr_nop,8'h5A, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 } |
:{ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } ) // here Adr(DEST) |
: { addr_nop,8'h59, rd_reg,(ACCA[3] ? imme : rtmph), |
1'b1,temp_h,op_lsh, 2'b00,2'b00,4'hE }; // Displacement read |
state_55 = { exoffset,8'h54, rd_reg,src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h1 }; // Read S |
state_58 = { addr_nop,8'h59, rd_reg,rtmph, 1'b1,temp_h,op_lsh, 2'b00,2'b00,4'hE }; // Displac |
state_59 = ACCA[1] ? // _..M. |
{ re_wr, 8'h27, src_x, rtmph, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h1 } // result in memory |
: { addr_nop,8'h00, src_x, rtmph, 1'b1,dest_2,OPERA, 2'b00,2'b00,4'h0 }; // result in Regi |
state_5A = { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; // special |
end |
5'b1_1011 : // INS/INSS : BASE Operand => TEMP, SRC2 read as Double ! RMW not tested (Phase x'6A) |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; // zext( |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } // here Adr(DEST) = |
: { addr_nop,8'h5A, SRC_2, src_x, 1'b1,temp_l,op_mov, 2'b00,2'b00,imdi }; // Imme./Disp. r |
state_55 = { exoffset,8'h6A, rd_reg,src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h1 }; // Read S |
state_58 = { addr_nop,8'h55, src_x, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; // |
state_59 = ACCA[1] ? // _..M. |
{ re_wr, 8'h27, rtmph, rtmpl, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h1 } // result in memory |
: { addr_nop,8'h00, rtmph, rtmpl, 1'b1,dest_2,OPERA, 2'b00,2'b00,4'h0 }; // result in Regi |
state_5A = { addr_nop,8'h68, imme, src_x, 1'b1,temp_1,op_msk, 2'b00,2'b00,4'h0 }; // Mask ge |
end |
5'b1_1101 : // INDEX : |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_zext, 2'b00,2'b00,4'h0 }; // zext( |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } // zext(SRC2) => TE |
: { addr_nop,8'h55, SRC_2, src_x, 1'b1,temp_l,op_zext, 2'b00,2'b00,4'h0 }; |
state_55 = { addr_nop,8'h5A, rd_reg,rtmph, 1'b1,temp_h,op_mul, 2'b00,2'b00,4'h0 }; // Multip |
state_58 = { addr_nop,8'h55, imme, src_x, 1'b1,temp_l,op_zext, 2'b00,2'b00,4'h0 }; // |
state_59 = { addind, 8'h60, rtmpl, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; // Add of |
state_5A = { addone, 8'h59, rd_reg,rtmph, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; // Add of |
end |
5'b1_0111 : // DEI + MEI , both read 8B from DEST ! RMW critical ! |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } // here SRC1 => TE |
: { addr_nop,8'h59, rtmph, SRC_2, 1'b0,dest_x,OPERA, 2'b01,2'b00,4'h0 }; // 1. part of Reg |
state_55 = dont_care; |
state_58 = size_dw ? |
{ addr_nop,8'h59, rtmph, imme, 1'b0,dest_x,OPERA, 2'b01,2'b00,4'h0 } // D needs 2 accesse |
: { addr_nop,8'h1F, rtmph, imme, 1'b0,dest_x,OPERA, 2'b11,2'b00,4'h0 }; // B+W start at o |
state_59 = { addr_nop,8'h1F, src_x, (ACCA[1] ? imme : src_2l), // SRC2 = memory or Reg |
~ACCA[1],dest_2,OPERA, 2'b10,2'b00,4'h0 }; |
state_5A = dont_care; |
end |
5'b1_1000 : // CHECK |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; // No Re |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { addr_nop,phchk, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 }; // No Imm |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } |
: ( size_dw ? |
{addr_nop,8'h5A, SRC_2, rtmpl, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h0 } // Upper Bound - point |
: {addr_nop,8'h00, rtmph, SRC_2, 1'b1,chkreg,OPERA, 2'b00,2'b10,4'h0 } ); |
state_55 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_l,op_mov, 2'b00,2'b00,4'h0 }; |
state_58 = size_dw ? |
{ addr_nop,8'h59, imme, src_x, 1'b1,temp_1,op_mov, 2'b00,2'b00,4'h0 } // here SRC2 => TEM |
: { addr_nop,8'h00, rtmph, imme, 1'b1,chkreg,OPERA, 2'b00,2'b10,4'h0 }; |
state_59 = { addr_nop,8'h5A, rtmp1, rtmpl, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h0 }; // Upper Bo |
state_5A = { addr_nop,8'h00, rtmph, (ACCA[1] ? rtmp1 : SRC_2), |
1'b1,chkreg,OPERA, 2'b00,2'b10,4'h0 }; // pointer - Lower Bound |
end |
5'b1_1100 : // CVTP |
begin |
STATE_0 = { ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; // Addre |
state_50 = { ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 }; |
state_53 = { addr_nop,8'h54, src_x, src_x, 1'b1,temp_h,op_adr, 2'b00,2'b00,4'h0 }; |
state_54 = { adrcvtp, 8'h73, rtmph, rd_reg,1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; // 8*TEMP |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b01_000 : // SCALBL : RMW critical ! |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_1l,1'b1,temp_h,op_trul, 2'b11,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_1l,1'b1,temp_h,op_trul, 2'b11,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h55, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,get8b_s }; |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_trul, 2'b00,2'b00,NXRW2 } |
: { addr_nop,8'h5A, src_x, src_x, 1'b0,temp_h,op_trul, 2'b00,2'b00,4'h0 }; |
state_55 = { addr_nop,8'h54, rtmph, imme, 1'b1,temp_h,op_trul, 2'b11,2'b00,4'h0 }; // 2. hal |
state_58 = { addr_nop,8'h59, rtmph, imme, 1'b0,dest_2,OPERA, 2'b01,2'b00,4'h0 }; |
state_59 = { addr_nop,8'h1F, src_x, (ACCA[1] ? imme : src_2l), |
~ACCA[1],dest_2,OPERA, 2'b10,2'b00,4'h0 }; |
state_5A = { addr_nop,8'h59, rtmph, SRC_2, 1'b0,dest_2,OPERA, 2'b01,2'b00,4'h0 }; // empty cy |
end |
5'b01_001 : // SCALBF : RMW critical ! |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_truf, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, src_x, 1'b1,temp_h,op_truf, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_truf, 2'b00,2'b00,4'h0 }; |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } |
: { addr_nop,8'h1F, rtmph, SRC_2, 1'b1,dest_2,OPERA, 2'b11,2'b00,4'h0 }; |
state_55 = dont_care; |
state_58 = { addr_nop,8'h1F, rtmph, imme, 1'b0,dest_x,OPERA, 2'b11,2'b00,4'h0 }; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b01_100 : // POLYL |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, F0_h, 1'b0,temp_h,op_mull, 2'b01,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, F0_h, 1'b0,temp_h,op_mull, 2'b01,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, F0_h, 1'b0,temp_h,op_mull, 2'b01,2'b00,get8b_s }; |
state_54 = { addr_nop,8'h64, (ACCA[3] ? imme : src_1l), |
F0, 1'b1,temp_h,op_mull, 2'b10,2'b00,4'h0 }; |
state_55 = dont_care; |
state_58 = { addr_nop,8'h59, imme, rtmph, 1'b0,dest_x,op_addl, 2'b01,2'b00,get8b_d }; |
state_59 = { addr_nop,8'h62, (ACCA[1] ? imme : src_2l), |
rtmpl, 1'b1,w_F0_h,op_addl, 2'b10,2'b00,4'h0 }; |
state_5A = dont_care; |
end |
5'b01_101 : // POLYF |
begin |
STATE_0 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, F0, 1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 }; |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { addr_nop,8'h54, SRC_1, F0, 1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 }; |
state_53 = { addr_nop,8'h54, imme, F0, 1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 }; |
state_54 = ACCA[1] ? |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } |
: { addr_nop,8'h00, rtmph, SRC_2, 1'b1,w_F0 ,op_addf, 2'b00,2'b00,4'h0 }; |
state_55 = dont_care; |
state_58 = { addr_nop,8'h00, rtmph, imme, 1'b1,w_F0 ,op_addf, 2'b00,2'b00,4'h0 }; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
5'b01_110 : // DOTL |
begin |
STATE_0 = (~ACCA[3] & ~ACCA[1]) ? // _R.R. |
{ addr_nop,8'h59, SRC_1, SRC_2, 1'b0,dest_x,op_mull, 2'b01,2'b00,4'h0 } |
: ( ACCA[3] ? // _M... |
{ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: {ADRD2, phsrc2,src_x, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } ); |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; |
state_53 = ACCA[1] ? // _..M. |
{ addr_nop,8'h54, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,get8b_s } |
: { addr_nop,8'h59, imme, SRC_2, 1'b0,dest_x,op_mull, 2'b01,2'b00,get8b_s }; |
state_54 = { addr_nop,8'h55, imme, src_x, 1'b1,temp_l,op_mov, 2'b00,2'b00,4'h0 }; |
state_55 = { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; |
state_58 = { addr_nop,8'h59, (ACCA[3] ? rtmph : SRC_1), //_M... |
imme, 1'b0,dest_x,op_mull, 2'b01,2'b00,get8b_d }; |
state_59 = { addr_nop,8'h5A, (ACCA[3] ? (ACCA[1] ? rtmpl : imme) : src_1l), (ACCA[1] ? imme : |
1'b1,temp_h,op_mull, 2'b10,2'b00,4'h0 }; |
state_5A = { addr_nop,8'h61, rtmph, F0_h, 1'b0,temp_h,op_mull, 2'b01,2'b00,4'h0 }; |
end |
5'b01_111 : // DOTF |
begin |
STATE_0 = (~ACCA[3] & ~ACCA[1]) ? // _R.R. |
{ addr_nop,8'h63, SRC_1 ,SRC_2 ,1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 } // opera = MULF |
: ( ACCA[3] ? // _M... |
{ADRD1, phsrc1,src_x, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: {ADRD2, phsrc2,src_x, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 } ); |
state_50 = ACCA[3] ? // _M... |
{ ADRD1, phsrc1,IRRW1, REGA1, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRD1 } |
: { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; |
state_53 = ACCA[1] ? // _..M. |
{ addr_nop,8'h55, imme, src_x, 1'b1,temp_h,op_mov, 2'b00,2'b00,4'h0 } |
: { addr_nop,8'h63, imme, SRC_2 ,1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 }; |
state_54 = dont_care; |
state_55 = { ADRD2, phsrc2,IRRW2, REGA2, 1'b0,dest_x,op_mov, 2'b00,2'b00,NXRW2 }; |
state_58 = { addr_nop,8'h63, (ACCA[3] ? rtmph : SRC_1), //_M... |
imme, 1'b1,temp_h,op_mulf, 2'b00,2'b00,4'h0 }; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
default |
begin |
STATE_0 = dont_care; |
state_50 = dont_care; |
state_53 = dont_care; |
state_54 = dont_care; |
state_55 = dont_care; |
state_58 = dont_care; |
state_59 = dont_care; |
state_5A = dont_care; |
end |
endcase |
|
always @(*) |
casex (PHASE) |
4'h0 : STATE_GROUP_50 = state_50; |
// Phase 51 : wait for data and Disp2 for External Address mode : part 2 EA = (MOD+4)+4*DISP1 |
4'h1 : STATE_GROUP_50 = {exr11, 8'h52, src_x,imme , 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'b1111} |
// Phase 52 : Memory-Pointer for Memory Relative and last access External |
4'h2 : STATE_GROUP_50 = {EXR12, 8'h53, IRRW1,imme , 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'b1111} |
4'h3 : STATE_GROUP_50 = state_53; |
4'h4 : STATE_GROUP_50 = state_54; |
4'h5 : STATE_GROUP_50 = state_55; |
// Phase 56 : wait for data and Disp2 for External Address mode : part 2 EA = (MOD+4)+4*DISP1 |
4'h6 : STATE_GROUP_50 = {exr11, 8'h57, src_x,imme , 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'b1111} |
// Phase 57 : Memory-Pointer for Memory Relative and last access External |
4'h7 : STATE_GROUP_50 = {EXR22, 8'h58, IRRW2,imme , 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'b1111} |
4'h8 : STATE_GROUP_50 = state_58; |
4'h9 : STATE_GROUP_50 = state_59; |
4'hA : STATE_GROUP_50 = state_5A; |
default : STATE_GROUP_50 = dont_care; |
endcase |
|
always @(*) |
casex (PHASE) |
4'h0 : STATE_GROUP_60 = { addr_nop,8'h00, src_x, src_x, 1'b1,chkreg,op_adr, 2'b00,2'b00,4'h0 } |
4'h1 : STATE_GROUP_60 = { addr_nop,8'h62, rtmpl, F0, 1'b1,w_F0_h,op_addl, 2'b10,2'b00,4'h0 } |
4'h2 : STATE_GROUP_60 = { addr_nop,8'h00, src_x, src_x, 1'b0,w_F0_h,op_addl, 2'b00,2'b00,4'h0 } |
4'h3 : STATE_GROUP_60 = { addr_nop,8'h00, rtmph, F0, 1'b1,w_F0, op_addf, 2'b00,2'b00,4'h0 } |
4'h4 : STATE_GROUP_60 = ACCA[1] ? // ..M. |
{ ADRD2, phsrc2,IRRW2, REGA2, 1'b0,temp_h,op_mull, 2'b00,2'b00,NXRW2 } |
: { addr_nop,8'h59, SRC_2, rtmph, 1'b0,temp_h,op_addl, 2'b01,2'b00,4'h0 }; // for POLYL |
4'h5 : STATE_GROUP_60 = { addr_nop,8'h59, src_x, src_x, 1'b1,temp_l,op_kust, 2'b00,2'b00,4'h0 } |
4'h6 : STATE_GROUP_60 = { addr_nop,8'h01, rtmph, src_x, 1'b0,dest_x,op_mov, 2'b00,2'b00,4'h0 }; |
4'h7 : STATE_GROUP_60 = { addr_nop,8'hC0, (op_reg_reg[0] ? rtmpl : 7'h00), // Jump to Stri |
src_x, 1'b0,dest_x,OPERA, 2'b00,2'b10,4'h0 }; // LD_OUT set, CMPS F-Flag |
// for INS |
4'h8 : STATE_GROUP_60 = { addr_nop,8'h69, rd_reg,rtmph, 1'b1,temp_h,op_lsh, 2'b00,2'b00,4'h0 }; |
4'h9 : STATE_GROUP_60 = { addr_nop,8'h59, rd_reg,rtmp1, 1'b0,dest_x,op_lsh, 2'b00,2'b00,4'h0 }; |
4'hA : STATE_GROUP_60 = { addr_nop,8'h5A, imme, src_x, 1'b1,temp_l,op_mov, 2'b00,2'b00,imdi }; |
// for CXPD, this State is decoded explicitly in DECODER |
4'hB : STATE_GROUP_60 = { addr_nop,8'h39, imme, src_x, 1'b1,temp_l,op_mov, 2'b00,2'b00,4'h0 }; |
default : STATE_GROUP_60 = dont_care; |
endcase |
|
endmodule |
/trunk/rtl/DATENPFAD.v
0,0 → 1,401
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: DATENPFAD.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// DATENPFAD the data path of M32632 |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module DATENPFAD( BCLK, BRESET, WREN, IO_READY, LD_DIN, LD_IMME, WR_REG, IC_USER, ACC_FELD, ACC_STAT |
IMME_Q, INFO_AU, LD_OUT, DETOIP, MMU_UPDATE, OPER, PC_ARCHI, PC_ICACHE, RDAA, RDAB, START, WMA |
WRADR, DONE, Y_INIT, WRITE_OUT, READ_OUT, ZTEST, RMW, ACC_DONE, REG_OUT, PTB_SEL, PTB_WR, ACB_ |
ABORT, SAVE_PC, CFG, CINV, DP_Q, IVAR, MCR, PACKET, PC_NEW, PSR, SIZE, STRING, TRAPS, VADR, RW |
DBG_HIT, DBG_IN, COP_GO, COP_OP, COP_IN, COP_DONE, COP_OUT); |
|
input BCLK; |
input BRESET; |
input WREN; // write enable of the register file |
input IO_READY; |
input LD_DIN; |
input LD_IMME; |
input WR_REG; // write signal for the DP_FPU |
input IC_USER; |
input RWVFLAG; |
input [14:0] ACC_FELD; |
input [5:0] ACC_STAT; |
input [31:0] DIN; |
input [31:0] DISP; |
input [2:0] IC_TEX; |
input [31:0] IMME_Q; |
input [6:0] INFO_AU; |
input [1:0] LD_OUT; |
input [12:0] DETOIP; |
input [1:0] MMU_UPDATE; |
input [10:0] OPER; |
input [31:0] PC_ARCHI; |
input [31:0] PC_ICACHE; |
input [7:0] RDAA; |
input [7:0] RDAB; |
input [1:0] START; |
input [1:0] WMASKE; |
input [5:0] WRADR; |
input DBG_HIT; |
input COP_DONE; |
input [23:0] COP_OP; |
input [63:0] COP_IN; |
|
output DONE; |
output Y_INIT; |
output WRITE_OUT; |
output READ_OUT; |
output ZTEST; |
output RMW; |
output ACC_DONE; |
output REG_OUT; |
output PTB_SEL; |
output PTB_WR; |
output reg ACB_ZERO; |
output ABORT; |
output SAVE_PC; |
output [12:0] CFG; |
output [3:0] CINV; |
output [63:0] DP_Q; |
output [1:0] IVAR; |
output [3:0] MCR; |
output [3:0] PACKET; |
output [31:0] PC_NEW; |
output [11:0] PSR; |
output [1:0] SIZE; |
output [4:0] STRING; |
output [5:0] TRAPS; |
output [31:0] VADR; |
output [40:2] DBG_IN; |
output COP_GO; |
output [127:0] COP_OUT; |
|
reg [31:0] high_dq; |
reg [31:0] OUT_I; |
reg [31:0] BYDIN; // the bypass register |
|
wire [2:0] BITSEL; |
wire [1:0] BWD; |
wire CLR_LSB; |
wire [31:0] ERGEBNIS; // the result bus |
wire FL; |
wire [31:0] FSR; |
wire [63:0] MRESULT; |
wire [7:0] OPCODE; |
wire SELI_A; |
wire SELI_B; |
wire [2:0] SP_CMP; |
wire [31:0] SRC1; // the bus for the Source 1 operand |
wire [31:0] SRC2; // the bus for the Source 2 operand |
wire [4:0] TT_DP; |
wire TWREN; // active if FPU Trap occurs |
wire UP_DP; |
wire WRADR_0; |
wire WREN_L,WREN_LX; |
wire LD_FSR; |
wire UP_SP; |
wire [4:0] TT_SP; |
wire [31:0] addr_i; |
wire [2:0] DP_CMP; |
wire [31:0] DP_OUT; |
wire [31:0] SFP_DAT; |
wire ld_out_l; |
wire [6:0] BMCODE; |
wire [31:0] OUT_A,OUT_B; |
wire SP_MUX; |
wire [31:0] I_OUT; |
wire [31:0] FP_OUT; |
wire DOWR; |
wire [31:0] DEST1,DEST2; |
wire ENWR; |
wire [3:0] OVF_BCD; |
wire [3:0] DSR; |
wire acb_zero_i; |
wire [31:0] BMASKE; |
|
assign FL = OPER[10]; |
assign BWD = OPER[9:8]; |
assign OPCODE = OPER[7:0]; |
|
assign ERGEBNIS = SP_MUX ? FP_OUT : I_OUT; |
|
assign WRADR_0 = WRADR[0] & ~CLR_LSB; |
assign ENWR = WREN_L | WREN; |
assign DOWR = ENWR & TWREN; |
|
assign WREN_L = WREN_LX & ~TRAPS[0]; |
|
assign DP_Q[63:32] = high_dq; |
|
assign PC_NEW = SRC1; |
|
always @(posedge BCLK) if (LD_OUT[1] || WREN) ACB_ZERO <= acb_zero_i; |
|
always @(posedge BCLK) if (LD_OUT[1] || ld_out_l) high_dq <= ERGEBNIS; |
|
always @(posedge BCLK) if (LD_DIN) OUT_I <= LD_IMME ? IMME_Q : DIN; |
|
always @(posedge BCLK) if (RDAA[7]) BYDIN <= ERGEBNIS; |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// Register Set 1 => SRC1 |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
REGISTER REG_SET_A( |
.BCLK(BCLK), |
.ENWR(ENWR), |
.DOWR(DOWR), |
.DIN(ERGEBNIS), |
.BYDIN(BYDIN), |
.RADR(RDAA), |
.WADR({WRADR[5:1],WRADR_0}), |
.WMASKE(WMASKE), |
.SELI(SELI_A), |
.DOUT(OUT_A)); |
|
assign SRC1 = SELI_A ? OUT_I : OUT_A; |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// Register Set 2 => SRC2 |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
REGISTER REG_SET_B( |
.BCLK(BCLK), |
.ENWR(ENWR), |
.DOWR(DOWR), |
.DIN(ERGEBNIS), |
.BYDIN(BYDIN), |
.RADR(RDAB), |
.WADR({WRADR[5:1],WRADR_0}), |
.WMASKE(WMASKE), |
.SELI(SELI_B), |
.DOUT(OUT_B)); |
|
assign SRC2 = SELI_B ? OUT_I : OUT_B; |
|
MULFILTER M_FILTER( |
.FLOAT(OPCODE[2]), |
.BWD(BWD), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.DEST1(DEST1), |
.DEST2(DEST2)); |
|
SIGNMUL S_MULTI( // signed multiplier 32 * 32 bits = 64 bits |
.dataa(DEST1), |
.datab(DEST2), |
.result(MRESULT)); |
|
BITMASK BITM_U( |
.AA(BMCODE), |
.DOUT(BMASKE)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The integer data path |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
I_PFAD GANZ_U( |
.FL(FL), |
.BRESET(BRESET), |
.BCLK(BCLK), |
.WREN(WREN), |
.LD_OUT(LD_OUT[1]), |
.ADDR(addr_i), |
.BITSEL(BITSEL), |
.BMASKE(BMASKE), |
.BWD(BWD), |
.DP_CMP(DP_CMP), |
.DP_OUT(DP_OUT), |
.FSR(FSR), |
.DETOIP(DETOIP[11:0]), |
.MRESULT(MRESULT), |
.OPCODE(OPCODE), |
.RDAA(RDAA), |
.SFP_DAT(SFP_DAT), |
.SP_CMP(SP_CMP), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.WRADR(WRADR), |
.DSR(DSR), |
.OV_FLAG(TRAPS[2]), |
.ACB_ZERO(acb_zero_i), |
.BMCODE(BMCODE), |
.I_OUT(I_OUT), |
.PSR(PSR), |
.STRING(STRING), |
.OVF_BCD(OVF_BCD), |
.DISP(DISP[4:0]), |
.RWVFLAG(RWVFLAG)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The address unit |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
ADDR_UNIT ADDR_U( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.IO_READY(IO_READY), |
.READ(ACC_FELD[11]), |
.WRITE(ACC_FELD[10]), |
.CLRMSW(ACC_FELD[2]), |
.FULLACC(ACC_FELD[8]), |
.POST(ACC_FELD[3]), |
.DISP_OK(INFO_AU[0]), |
.LDEA(ACC_FELD[9]), |
.NEWACC(ACC_FELD[14]), |
.FPU_TRAP(TRAPS[0]), |
.ADIVAR(INFO_AU[2]), |
.RWVAL_1(INFO_AU[3]), |
.ABO_STAT({INFO_AU[1],IC_USER}), |
.ACC_STAT(ACC_STAT), |
.ASIZE(ACC_FELD[13:12]), |
.BWD(BWD), |
.DISP(DISP), |
.IC_TEX(IC_TEX), |
.INDEX(ACC_FELD[7:4]), |
.MMU_UPDATE(MMU_UPDATE), |
.PC_ARCHI(PC_ARCHI), |
.PC_ICACHE(PC_ICACHE), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.SRC2SEL(ACC_FELD[1:0]), |
.REG_OUT(REG_OUT), |
.ACC_DONE(ACC_DONE), |
.READ_OUT(READ_OUT), |
.WRITE_OUT(WRITE_OUT), |
.ABORT(ABORT), |
.ADDR(addr_i), |
.BITSEL(BITSEL), |
.PACKET(PACKET), |
.SIZE(SIZE), |
.VADR(VADR), |
.ZTEST(ZTEST), |
.RMW(RMW), |
.OP_RMW(INFO_AU[4]), |
.PHASE_17(INFO_AU[5]), |
.NO_TRAP(INFO_AU[6]) ); |
|
CONFIG_REGS CFG_DBG( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.WREN(WREN), |
.LD_OUT(LD_OUT[1]), |
.OPCODE(OPCODE), |
.SRC1(SRC1), |
.WRADR(WRADR), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.CFG(CFG), |
.CINV(CINV), |
.IVAR(IVAR), |
.Y_INIT(Y_INIT), |
.MCR(MCR), |
.DBG_TRAPS(TRAPS[5:3]), |
.PC_ARCHI(PC_ARCHI), |
.DSR(DSR), |
.USER(PSR[8]), |
.PCMATCH(DETOIP[12]), |
.DBG_IN(DBG_IN), |
.DBG_HIT(DBG_HIT), |
.READ(READ_OUT) ); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The long operation unit |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
DP_FPU DOUBLE_U( |
.BCLK(BCLK), |
.FL(FL), |
.BRESET(BRESET), |
.LD_LDQ(LD_OUT[0]), |
.WR_REG(WR_REG), |
.BWD(BWD), |
.FSR(FSR[8:3]), |
.OPCODE(OPCODE), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.START(START), |
.DONE(DONE), |
.UP_DP(UP_DP), |
.WREN_L(WREN_LX), |
.CLR_LSB(CLR_LSB), |
.LD_OUT_L(ld_out_l), |
.DVZ_TRAP(TRAPS[1]), |
.DP_CMP(DP_CMP), |
.DP_OUT(DP_OUT), |
.DP_Q(DP_Q[31:0]), |
.TT_DP(TT_DP), |
.CY_IN(PSR[0]), |
.OVF_BCD(OVF_BCD), |
.COP_DONE(COP_DONE), |
.COP_OP(COP_OP), |
.COP_IN(COP_IN), |
.COP_GO(COP_GO), |
.COP_OUT(COP_OUT)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The single precision floating point unit |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
SP_FPU SINGLE_U( |
.FL(FL), |
.BCLK(BCLK), |
.BWD(BWD), |
.FSR(FSR[8:3]), |
.MRESULT(MRESULT[47:0]), |
.OPCODE(OPCODE), |
.SRC1(SRC1), |
.SRC2(SRC2), |
.LD_FSR(LD_FSR), |
.SP_MUX(SP_MUX), |
.UP_SP(UP_SP), |
.FP_OUT(FP_OUT), |
.I_OUT(SFP_DAT), |
.SP_CMP(SP_CMP), |
.TT_SP(TT_SP)); |
|
FP_STAT_REG FPS_REG( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.LFSR(LD_FSR), |
.WREN(ENWR), |
.WRADR(WRADR[5:4]), |
.UP_DP(UP_DP), |
.UP_SP(UP_SP & LD_OUT[1]), |
.DIN(SRC1[16:0]), |
.TT_DP(TT_DP), |
.TT_SP(TT_SP), |
.FPU_TRAP(TRAPS[0]), |
.TWREN(TWREN), |
.SAVE_PC(SAVE_PC), |
.FSR(FSR)); |
|
endmodule |
/trunk/rtl/CACHE_LOGIK.v
0,0 → 1,781
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: CACHE_LOGIK.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. DEBUG_AE Debug unit for address compare in data cache |
// 2. MMU_UP MMU memory update and initalization controller |
// 3. DCA_CONTROL Data cache valid memory update and initalization controller |
// 4. MMU_MATCH MMU virtual address match detector |
// 5. CA_MATCH Cache tag match detector |
// 6. DCACHE_SM Data cache state machine |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. DEBUG_AE Debug unit for address compare in data cache |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DEBUG_AE ( DBG_IN, READ, WRITE, USER, VIRTUELL, ACC_OK, VADR_R, MMU_Q, ENBYTE, DBG_HIT ); |
|
input [40:2] DBG_IN; |
|
input READ,WRITE; |
input USER; |
input VIRTUELL; |
input ACC_OK; |
input [31:2] VADR_R; |
input [19:0] MMU_Q; |
input [3:0] ENBYTE; |
|
output DBG_HIT; |
|
wire sd,ud,crd,cwr,vnp; |
wire make; |
wire virt_adr,real_adr,page_adr; |
wire byte_en; |
|
assign sd = DBG_IN[40]; |
assign ud = DBG_IN[39]; |
assign crd = DBG_IN[38]; |
assign cwr = DBG_IN[37]; |
assign vnp = DBG_IN[36]; |
|
assign make = ((ud & USER) | (sd & ~USER)) // compare USER or SUPERVISOR |
& (VIRTUELL == vnp) // compare real or virtual address |
& ((cwr & WRITE) | (crd & READ)); // compare READ or WRITE |
|
assign virt_adr = (MMU_Q == DBG_IN[31:12]); |
assign real_adr = (VADR_R[31:12] == DBG_IN[31:12]); |
assign page_adr = (VADR_R[11:2] == DBG_IN[11:2]); |
|
assign byte_en = |(ENBYTE & DBG_IN[35:32]); |
|
assign DBG_HIT = ACC_OK // all valid |
& make // selection is valid |
& (VIRTUELL ? virt_adr : real_adr) & page_adr // address |
& byte_en; // Byte Enable |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. MMU_UP MMU memory update and initalization controller |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module MMU_UP ( BCLK, BRESET, NEW_PTB, PTB1, IVAR, WR_MRAM, VADR, VADR_R, MVALID, UPDATE, |
WE_MV, WADR_MV, RADR_MV, DAT_MV, NEW_PTB_RUN ); |
|
input BCLK; |
input BRESET; |
input NEW_PTB; // the MMU memory is cleared. Pulse of one BCLK cycle, Op-Dec is waiting |
input PTB1; // which one |
input IVAR; |
input WR_MRAM; // BCLK : update MRAM and MMU_VAL |
input [19:16] VADR,VADR_R; // For update |
input [31:0] MVALID,UPDATE; |
|
output WE_MV; // Write Enable MMU Valid |
output [3:0] WADR_MV,RADR_MV; |
output [31:0] DAT_MV; |
output NEW_PTB_RUN; |
|
reg neue_ptb,wr_flag,old_rst,run_over; |
reg [3:0] count; |
|
wire [15:0] new_val; |
|
assign WE_MV = wr_flag | WR_MRAM | IVAR; // write on falling edge BCLK |
assign RADR_MV = run_over ? count : VADR; |
assign WADR_MV = wr_flag ? (count - 4'b0001) : VADR_R; |
assign DAT_MV = wr_flag ? {MVALID[31:16],new_val} : UPDATE; // Only the matching entries are clear |
|
// [31:16] Address-Space memory, [15:0] Valid memory |
assign new_val = neue_ptb ? (PTB1 ? (MVALID[15:0] & ~MVALID[31:16]) : (MVALID[15:0] & MVALID[31:16] |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) neue_ptb <= 1'b0; |
else neue_ptb <= NEW_PTB | (neue_ptb & run_over); |
|
always @(posedge BCLK) old_rst <= BRESET; // after Reset all will be set to 0 |
|
always @(posedge BCLK) run_over <= ((~old_rst | NEW_PTB) | (run_over & (count != 4'hF))) & BRESET; |
|
always @(posedge BCLK) count <= run_over ? count + 4'h1 : 4'h0; |
|
always @(posedge BCLK) wr_flag <= run_over; |
|
assign NEW_PTB_RUN = wr_flag; // Info to Op-Dec |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. DCA_CONTROL Data cache valid memory update and initalization controller |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DCA_CONTROL ( BCLK, MCLK, BRESET, CUPDATE, DRAM_ACC, CA_SET, HIT_ALL, WRCFG, VADR_R, UPDATE, |
WCTRL, KILL, WRCRAM0, WRCRAM1, WE_CV, WADR_CV, DAT_CV, INIT_CA_RUN, WRSET0, WRSET1 ); |
|
input BCLK; |
input MCLK; |
input BRESET; |
input CUPDATE; // State CUPDATE : Cache is filled from DRAM |
input DRAM_ACC; |
input CA_SET; |
input HIT_ALL; // a complete cache hit ! |
input WRCFG; // static signal : GND or VDD |
input [11:7] VADR_R; |
input [23:0] UPDATE; |
input INVAL_A; |
input WRITE; |
input [1:0] WCTRL; // [1] : Read Burst Signal from DRAM controller, MCLK aligned. [0] : Cache inh |
input KILL; // valid Ram must be updated because of collision ... or CINV |
|
output WRCRAM0,WRCRAM1; |
output WE_CV; |
output [4:0] WADR_CV; |
output [23:0] DAT_CV; |
output INIT_CA_RUN; |
output WRSET0,WRSET1; |
|
reg [1:0] state; |
reg [4:0] acount; |
reg ca_set_d; |
|
reg dly_bclk,zero,wr_puls; |
reg [2:0] count,refer; |
|
wire countf; |
|
// physical address is stored in TAG-RAM |
|
assign WRCRAM0 = (CUPDATE & ~WCTRL[0]) & ~CA_SET; |
assign WRCRAM1 = (CUPDATE & ~WCTRL[0]) & CA_SET; |
|
// Load Valid RAM : |
|
assign WE_CV = state[1] | HIT_ALL | (CUPDATE & ~WCTRL[0]) | KILL; // Hit All for "Last" Update |
assign WADR_CV = state[1] ? acount : VADR_R; |
assign DAT_CV = state[1] ? 24'h0 : UPDATE; |
|
// Clear of Cache-Valid RAMs : 32 clocks of BCLK |
|
assign countf = (acount == 5'h1F); |
|
always @(posedge BCLK) |
casex ({BRESET,INVAL_A,countf,state[1:0]}) |
5'b0xx_xx : state <= 2'b01; |
5'b1xx_01 : state <= 2'b10; // start counter |
5'b10x_00 : state <= 2'b00; // wait ... |
5'b11x_00 : state <= 2'b10; |
5'b1x0_10 : state <= 2'b10; |
5'b1x1_10 : state <= 2'b00; |
default : state <= 2'b0; |
endcase |
|
always @(posedge BCLK) if (!state[1]) acount <= 5'h0; else acount <= acount + 5'h01; |
|
assign INIT_CA_RUN = state[1]; |
|
always @(posedge BCLK) if (DRAM_ACC) ca_set_d <= CA_SET; |
|
// WRITE Control in data RAMs |
assign WRSET0 = ( ~CA_SET & WRITE & HIT_ALL & wr_puls) | (WCTRL[1] & ~ca_set_d); |
assign WRSET1 = ( CA_SET & WRITE & HIT_ALL & wr_puls) | (WCTRL[1] & ca_set_d); |
|
// ++++++++++++ Special circuit for Timing of write pulse for data RAM of data cache +++++++++ |
|
always @(negedge MCLK) dly_bclk <= BCLK; |
|
always @(negedge MCLK) zero <= BCLK & ~dly_bclk; |
|
always @(posedge MCLK) if (zero) count <= 3'd0; else count <= count + 3'd1; |
|
// count at zero , ref Wert |
// 1 : --- always on 5 : 100 001 |
// 2 : 001 000 6 : 101 010 |
// 3 : 010 010 7 : 110 011 |
// 4 : 011 000 8 : 111 100 |
always @(posedge MCLK) if (zero) refer <= {(count == 3'd7),((count == 3'd5) | (count[1:0] == 2'b10) |
|
always @(posedge MCLK) wr_puls <= (count == refer) | WRCFG; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. MMU_MATCH MMU virtual address match detector |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module MMU_MATCH ( USER, READ, WRITE, RMW, MCR_FLAGS, MVALID, VADR_R, MMU_VA, IVAR, |
VIRTUELL, MMU_HIT , UPDATE, PROT_ERROR, CI, SEL_PTB1 ); |
|
input USER; |
input READ; |
input WRITE; |
input RMW; |
input [2:0] MCR_FLAGS; |
input [31:0] MVALID; |
input [31:12] VADR_R; |
input [31:16] MMU_VA; |
input [1:0] IVAR; // Invalidate Entry |
|
output VIRTUELL; // only for Adress-Mux |
output MMU_HIT; |
output [31:0] UPDATE; |
output reg PROT_ERROR; // if valid must suppress write in Write Buffer and cache |
output CI,SEL_PTB1; |
|
reg [15:0] maske; |
|
wire adr_space,as_sorte,match,alles_ok; |
wire [15:0] val_bits,as_bits; |
wire ena_prot; |
wire zugriff; |
|
assign zugriff = READ | WRITE; |
|
always @(VADR_R) |
case (VADR_R[15:12]) |
4'h0 : maske = 16'h0001; |
4'h1 : maske = 16'h0002; |
4'h2 : maske = 16'h0004; |
4'h3 : maske = 16'h0008; |
4'h4 : maske = 16'h0010; |
4'h5 : maske = 16'h0020; |
4'h6 : maske = 16'h0040; |
4'h7 : maske = 16'h0080; |
4'h8 : maske = 16'h0100; |
4'h9 : maske = 16'h0200; |
4'hA : maske = 16'h0400; |
4'hB : maske = 16'h0800; |
4'hC : maske = 16'h1000; |
4'hD : maske = 16'h2000; |
4'hE : maske = 16'h4000; |
4'hF : maske = 16'h8000; |
endcase |
|
assign VIRTUELL = USER ? MCR_FLAGS[0] : MCR_FLAGS[1]; |
|
assign adr_space = IVAR[1] ? IVAR[0] : (MCR_FLAGS[2] & USER); // adr_space = IVARx ? 1 or 0 : DualS |
|
assign as_sorte = ((MVALID[31:16] & maske) != 16'h0); |
|
assign match = (VADR_R[31:20] == MMU_VA[31:20]) & (adr_space == as_sorte) & ((MVALID[15:0] & maske) |
|
assign alles_ok = match & ( ~WRITE | MMU_VA[17] ) & ~PROT_ERROR; // Modified - Flag : reload the PT |
|
// if MMU_HIT = 0 then there is no Write-Buffer access abd no update of cache ! |
assign MMU_HIT = zugriff ? ( VIRTUELL ? alles_ok : 1'b1 ) : 1'b0 ; // MMU off : then always HIT |
|
assign val_bits = IVAR[1] ? (MVALID[15:0] & (match ? ~maske : 16'hFFFF)) : (MVALID[15:0] | maske); |
assign as_bits = IVAR[1] ? MVALID[31:16] : (adr_space ? (MVALID[31:16] | maske) : (MVALID[31:16] & |
|
assign UPDATE = {as_bits,val_bits}; |
|
assign ena_prot = zugriff & VIRTUELL & match; |
|
// A Protection error must suppress write in WB and cache |
always @(ena_prot or MMU_VA or USER or WRITE or RMW) |
case ({ena_prot,MMU_VA[19:18]}) |
3'b100 : PROT_ERROR = USER | WRITE | RMW; // Only Supervisor READ |
3'b101 : PROT_ERROR = USER; // no USER access |
3'b110 : PROT_ERROR = USER & (WRITE | RMW); // USER only READ |
default : PROT_ERROR = 1'b0; |
endcase |
|
assign CI = VIRTUELL & MMU_VA[16]; |
assign SEL_PTB1 = adr_space; // For PTE update |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 5. CA_MATCH Cache tag match detector |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module CA_MATCH ( CVALID, IOSEL, ADDR, TAG0, TAG1, CFG, WRITE, MMU_HIT, CI, INVAL_L, KDET, ENDRAM, D |
CA_HIT, CA_SET, UPDATE, IO_SPACE, USE_CA, WB_ACC, KILL ); |
|
input [23:0] CVALID; |
input [3:0] IOSEL; |
input [27:4] ADDR; |
input [27:12] TAG0,TAG1; |
input [1:0] CFG; // LDC , DC |
input WRITE; |
input MMU_HIT; |
input CI; |
input INVAL_L; // invalid cache line |
input KDET; |
input ENDRAM; |
input DC_ILO; // CBITI/SBITI special case |
|
output CA_HIT; |
output CA_SET; // if no Hit then says SET where to store |
output [23:0] UPDATE; // Update Information for CVALID memory |
output IO_SPACE; |
output USE_CA; |
output WB_ACC; |
output KILL; |
|
reg [7:0] maske; |
|
wire match_0,match_1; |
wire valid_0,valid_1; |
wire select; |
wire clear; |
wire [7:0] update_0,update_1,lastinfo; |
wire sel_dram; |
|
always @(ADDR) |
case (ADDR[6:4]) |
3'h0 : maske = 8'h01; |
3'h1 : maske = 8'h02; |
3'h2 : maske = 8'h04; |
3'h3 : maske = 8'h08; |
3'h4 : maske = 8'h10; |
3'h5 : maske = 8'h20; |
3'h6 : maske = 8'h40; |
3'h7 : maske = 8'h80; |
endcase |
|
assign valid_0 = (( CVALID[7:0] & maske) != 8'h00); |
assign valid_1 = ((CVALID[15:8] & maske) != 8'h00); |
|
assign match_0 = ( TAG0 == ADDR[27:12] ); // 4KB |
assign match_1 = ( TAG1 == ADDR[27:12] ); // 4KB |
|
assign CA_HIT = ((valid_0 & match_0) | (valid_1 & match_1)) & ~DC_ILO & CFG[0]; |
|
// which SET is written in cache miss ? If both are valid the last used is not taken |
assign select = (valid_1 & valid_0) ? ~((CVALID[23:16] & maske) != 8'h00) : valid_0; // Last-used f |
|
assign CA_SET = CA_HIT ? (valid_1 & match_1) : select; |
|
assign clear = INVAL_L | KDET; // INVAL_L is from CINV |
|
assign update_0 = CA_SET ? CVALID[7:0] : (clear ? (CVALID[7:0] & ~maske) : (CVALID[7:0] | maske)); |
assign update_1 = CA_SET ? (clear ? (CVALID[15:8] & ~maske) : (CVALID[15:8] | maske)) : CVALID[15:8 |
|
assign lastinfo = CA_HIT ? (CA_SET ? (CVALID[23:16] | maske) : (CVALID[23:16] & ~maske)) : CVALID[2 |
|
assign UPDATE = {lastinfo,update_1,update_0}; |
|
assign KILL = clear & CA_HIT & ~CFG[1]; // only if cache is not locked |
|
assign sel_dram = (IOSEL == 4'b0000) & ENDRAM; // at the moment the first 256 MB of memory |
assign IO_SPACE = ~sel_dram; // not DRAM or DRAM ist off |
assign USE_CA = ~CI & ~DC_ILO & CFG[0] & ~CFG[1]; // CI ? ILO ? Cache on ? Locked Cache ? |
assign WB_ACC = WRITE & MMU_HIT & sel_dram; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 6. DCACHE_SM Data cache state machine |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module DCACHE_SM ( BCLK, BRESET, IO_SPACE, MDONE, IO_READY, MMU_HIT, CA_HIT, READ, WRITE, ZTEST, RMW |
USE_CA, PTB_WR, PTB_SEL, SEL_PTB1, CPU_OUT, USER, PROT_ERROR, WB_ACC, ENWR, ADR_EQU, IC_PREQ, |
RWVAL, VIRTUELL, |
DRAM_ACC, DRAM_WR, IO_ACC, IO_RD, IO_WR, PTE_MUX, PD_MUX, PKEEP, PTE_ADR, PTE_DAT, HIT_ALL, A |
ABORT, PROTECT, IACC_STAT, ABO_LEVEL1, WR_MRAM, CUPDATE, AUX_DAT, NEW_PTB, PTB_ONE, MMU_DIN, |
KDET, DMA_MUX, HLDA, RWVFLAG, PTE_STAT ); |
|
input BCLK; |
input BRESET; |
input IO_SPACE; |
input MDONE; // Memory Done : feedback from DRAM Controller, BCLK aligned ! |
input IO_READY; |
input MMU_HIT,CA_HIT; |
input READ,WRITE,ZTEST,RMW; |
input [31:0] CAPDAT; |
input [31:12] VADR_R,IC_VA; |
input USE_CA; |
input PTB_WR,PTB_SEL; |
input SEL_PTB1; |
input [27:12] CPU_OUT; // used for PTB0/1 |
input USER; |
input PROT_ERROR; |
input WB_ACC; |
input ENWR; // Enable WRITE from DRAM |
input ADR_EQU; |
input IC_PREQ; |
input FILLRAM; |
input [3:0] ICTODC; // multiple signals from ICACHE, especially DMA |
input [1:0] RWVAL; // RDVAL+WRVAL Operation |
input VIRTUELL; // for RDVAL/WRVAL |
|
output reg DRAM_ACC,DRAM_WR; |
output IO_ACC,IO_RD,IO_WR; |
output PTE_MUX,PD_MUX,PKEEP; |
output [27:0] PTE_ADR; |
output [19:0] PTE_DAT; |
output HIT_ALL; |
output ACC_OK; |
output ABORT,PROTECT; |
output [3:1] IACC_STAT; |
output ABO_LEVEL1; |
output WR_MRAM; |
output CUPDATE; |
output AUX_DAT; |
output reg NEW_PTB; |
output reg PTB_ONE; |
output [23:0] MMU_DIN; |
output [1:0] IC_SIGS; |
output KOMUX; |
output KDET; // Signal for detection of collision |
output DMA_MUX; |
output HLDA; // active low |
output RWVFLAG; // RDVAL/WRVAL result |
output [1:0] PTE_STAT; |
|
reg IO_WR,IO_RD; |
reg [1:0] pl_dat; |
reg [6:0] new_state; |
reg [2:0] cap_dat; // only for analyse of timing |
reg mem_done; |
reg rd_done; |
reg [2:0] pstate; |
reg pte_run_wr; |
reg [1:0] prot_level1; |
reg card_flag; |
reg [27:12] ptb0,ptb1; |
reg write_ok; |
reg icp_acc; |
reg pte_modi; |
reg [2:0] ko_state; |
reg dma_run; |
reg dma_kdet; |
reg rwv_bit; |
reg prot_i; |
reg rd_rdy; |
|
wire [27:12] ptb10; |
wire [31:12] virtual_adr; |
wire io_busy; |
wire dram_go; |
wire pte_sel; |
wire pte_acc; |
wire do_ca_rd,pte_go,do_ic_p; |
wire valid,valid_a,refer,modi; |
wire level1,level2; |
wire rd_level2; |
wire wr_req; |
wire wr_dram; |
wire wr_icmram; |
wire rd_ende; |
wire pte_dat_8; |
wire pte_wr_sig; |
wire run_dc; |
wire kostart; |
wire dma; |
wire dma_go; |
wire zugriff; |
wire mmu_hit_i; |
wire do_zt; |
wire zt_ok; |
wire [1:0] acc_level; |
wire user_ptw,wr_ptw; |
wire pte_puls; |
|
always @(posedge BCLK) cap_dat <= CAPDAT[2:0]; |
|
// if USER not virtual then ZTEST is quickly done |
assign zugriff = READ | WRITE | (ZTEST & VIRTUELL); |
assign mmu_hit_i = MMU_HIT & ~ZTEST; |
|
// WB_ACC is a successful WRITE access, ICTODC[0] is coherent Logik release : >=3 entries in FIFO |
assign wr_req = WB_ACC & ((ENWR & ICTODC[0]) | (DRAM_WR & ADR_EQU)); // release done by DRAM signal |
|
assign rd_ende = CA_HIT | rd_rdy; // CA_HIT only when Cache activ ! |
|
always @( zugriff // READ or WRITE or ZTEST , global control |
or PROT_ERROR // must not be |
// |
or IO_SPACE // access of IO world |
or io_busy // is access already running ? |
// |
or mmu_hit_i // Hit in MMU , now only a READ can happen |
or READ |
or wr_req |
or rd_ende // Cache Hit |
// |
or DRAM_ACC // DRAM Access : shows an active state |
or pte_acc // PTE access is running |
// |
or IC_PREQ // PTE Request from ICACHE |
// |
or dma // DMA Request |
or dma_run ) // DMA running |
// #_# #_# #_# #_# |
casex ({zugriff,PROT_ERROR,IO_SPACE,io_busy,mmu_hit_i,READ,wr_req,rd_ende,DRAM_ACC,pte_acc,IC_PREQ |
// MMU Miss : PTE load from memory , valid too if WRITE and M=0 |
13'b10_xx_0xxx_x0_x_x0 : new_state = 7'b0001010; // start PTE access |
// IO-Address selected : external access starts if not busy because of WRITE |
13'b10_10_1xxx_x0_x_x0 : new_state = 7'b0000001; |
// DRAM access : Cache Miss at READ : |
13'b10_0x_1100_00_x_x0 : new_state = 7'b0010010; |
// DRAM access : WRITE |
13'b10_0x_101x_x0_x_x0 : new_state = 7'b0000100; |
// PTE Request ICACHE , IO access with WRITE is stored - parallel DRAM access possible |
13'b0x_xx_xxxx_x0_1_00 : new_state = 7'b0101010; // no access |
13'b10_0x_1101_x0_1_x0 : new_state = 7'b0101010; // if successful READ a PTE access can happen i |
// DMA access. Attention : no IO-Write access in background and no ICACHE PTE access ! |
13'b0x_x0_xxxx_xx_0_10 : new_state = 7'b1000000; // DMA access is started |
default : new_state = 7'b0; |
endcase |
|
assign IO_ACC = new_state[0]; // to load registers for data, addr und BE, signal one pulse |
assign dram_go = new_state[1] | rd_level2 ; |
assign wr_dram = new_state[2]; // pulse only |
assign pte_go = new_state[3]; |
assign do_ca_rd = new_state[4]; |
assign do_ic_p = new_state[5]; |
assign dma_go = new_state[6]; |
|
// ZTEST logic is for the special case when a write access is crossing page boundaries |
|
assign do_zt = ZTEST & ~icp_acc; |
|
// 0 is pass , 1 is blocked. RWVAL[0] is 1 if WRVAL. Level 1 can only be blocked, otherwise ABORT o |
always @(posedge BCLK) if (mem_done) rwv_bit <= level2 ? ~(cap_dat[2] & (~RWVAL[0] | cap_dat[1])) : |
|
assign RWVFLAG = VIRTUELL & rwv_bit; |
|
assign zt_ok = mem_done & (RWVAL[1] ? (~cap_dat[2] | (RWVAL[0] & ~cap_dat[1]) | level2) // Level 2 |
: (cap_dat[0] & ~prot_i & level2) ); // "normal" access |
|
// PTE access logic, normal state machine |
// Updates to the PTEs are normal WRITE request to DRAM, therefore no MDONE at Write |
|
assign modi = ~CAPDAT[8] & WRITE & write_ok & ~icp_acc; // is "1" if the Modified Bit must be set |
assign refer = CAPDAT[7] | do_zt; // Assumption "R" Bit is set if RDVAL/WRVAL and page border test |
assign valid = (do_zt & RWVAL[1]) ? (cap_dat[2] & (cap_dat[1] | ~RWVAL[0]) & cap_dat[0] & level1) |
: (cap_dat[0] & ~prot_i); |
|
always @(posedge BCLK) mem_done <= MDONE & pte_acc; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) pstate <= 3'h0; |
else |
casex ({pte_go,mem_done,valid,refer,modi,pte_run_wr,pstate}) |
9'b0x_xxxx_000 : pstate <= 3'd0; // nothing to do |
9'b1x_xxxx_000 : pstate <= 3'd4; // start |
9'bx0_xxxx_100 : pstate <= 3'd4; // wait for Level 1 |
9'bx1_0xxx_100 : pstate <= 3'd0; // THAT'S ABORT ! |
9'bx1_11xx_100 : pstate <= 3'd6; // PTE Level 1 was referenced , next is Level 2 |
9'bx1_10xx_100 : pstate <= 3'd5; // for writing of modified Level 1 : R=1 |
9'bxx_xxx0_101 : pstate <= 3'd5; // write must wait |
9'bxx_xxx1_101 : pstate <= 3'd6; // one wait cycle |
9'bx0_xxxx_110 : pstate <= 3'd6; // wait for Level 2 |
9'bx1_0xxx_110 : pstate <= 3'd0; // THAT'S ABORT ! |
9'bx1_10xx_110 : pstate <= 3'd7; // Update neccesary : R=0 |
9'bx1_110x_110 : pstate <= 3'd0; // all ok - end |
9'bx1_111x_110 : pstate <= 3'd7; // Update neccesary : M=0 |
9'bxx_xxx0_111 : pstate <= 3'd7; // write must wait |
9'bxx_xxx1_111 : pstate <= 3'd0; // continues to end of DRAM write |
default : pstate <= 3'd0; |
endcase |
|
assign pte_acc = pstate[2]; |
assign level1 = ~pstate[1]; |
assign level2 = pstate[1]; |
|
assign valid_a = (ZTEST & RWVAL[1]) ? (cap_dat[2] & (cap_dat[1] | ~RWVAL[0]) & ~cap_dat[0] & level1 |
: ~cap_dat[0]; // not do_zt because of icp_acc in ABORT |
|
assign ABORT = mem_done & valid_a & ~icp_acc; |
assign PROTECT = ((mem_done & prot_i & ~icp_acc) | PROT_ERROR) & ~(ZTEST & RWVAL[1]); // no Protec |
|
assign IACC_STAT[1] = mem_done & ~cap_dat[0] & icp_acc; |
assign IACC_STAT[2] = level1; |
assign IACC_STAT[3] = mem_done & prot_i & icp_acc; |
|
assign ABO_LEVEL1 = level1; // is stored in case of ABORT in ADDR_UNIT |
|
assign rd_level2 = (pstate == 3'd5) | (mem_done & (pstate == 3'd4) & refer & valid); |
|
assign WR_MRAM = mem_done & (pstate == 3'd6) & valid & ~icp_acc & ~ZTEST; |
assign wr_icmram = mem_done & (pstate == 3'd6) & valid & icp_acc; |
|
// Signals to the Instruction Cache |
// pte_acc combined with icp_acc for STATISTIK. |
assign IC_SIGS = {(pte_acc & icp_acc),wr_icmram}; |
|
assign PTE_MUX = pte_go | (pte_acc & ~pstate[1]); |
|
assign pte_puls = mem_done & pte_acc & ~pstate[1]; |
assign PTE_STAT = {(pte_puls & icp_acc),(pte_puls & ~icp_acc)}; // only for statistic |
|
assign PD_MUX = ((pstate == 3'd4) & mem_done & valid & ~refer) // switch data-MUX, write level 1 |
| ((pstate == 3'd6) & mem_done & valid & (~refer | modi)) // write level 2 |
| (((pstate == 3'd5) | (pstate == 3'd7)) & ~pte_run_wr); |
|
assign pte_wr_sig = ENWR & PD_MUX; |
|
always @(posedge BCLK) pte_run_wr <= pte_wr_sig; // Ok-Signal for pstate State-machine |
|
assign PKEEP = (pstate == 3'd6) | ((pstate == 3'd7) & ~pte_run_wr); // keep the DRAM address |
|
// If there is a PTE still in the data cache it must be deleted. If MMU Bits are set by the pte eng |
// READ would deliver wrong data if cache hit. Therefore access of the Tags. |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) ko_state <= 3'b000; |
else |
casex ({kostart,ko_state}) |
4'b0_000 : ko_state <= 3'b000; |
4'b1_000 : ko_state <= 3'b110; |
4'bx_110 : ko_state <= 3'b111; |
4'bx_111 : ko_state <= 3'b100; |
4'bx_100 : ko_state <= 3'b000; |
default : ko_state <= 3'b000; |
endcase |
|
assign kostart = pte_go | rd_level2; |
|
assign run_dc = ~ko_state[2] & ~dma_run; |
assign KOMUX = ko_state[1] | DMA_MUX; |
assign KDET = ko_state[0] | dma_kdet; |
|
assign HIT_ALL = MMU_HIT & CA_HIT & run_dc & ~pte_acc; // for Update "Last-Set" , MMU_HIT contains |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) card_flag <= 1'b0; |
else card_flag <= (do_ca_rd & ~rd_rdy) | (card_flag & ~MDONE); |
|
assign CUPDATE = card_flag & USE_CA & MDONE; |
|
always @(posedge BCLK) rd_rdy <= card_flag & MDONE; |
|
// The cache RAM can not provide fast enough the data after an Update. In this case a secondary dat |
assign AUX_DAT = rd_rdy; |
|
// DRAM interface : |
|
always @(posedge BCLK) DRAM_WR <= wr_dram | pte_wr_sig; // pulse |
always @(posedge BCLK) if (dram_go) DRAM_ACC <= 1'b1; |
else |
DRAM_ACC <= DRAM_ACC & ~MDONE & BRESET; |
// IO interface : |
|
always @(posedge BCLK) |
begin |
if (IO_ACC) IO_RD <= READ; else IO_RD <= IO_RD & ~IO_READY & BRESET; |
if (IO_ACC) IO_WR <= WRITE; else IO_WR <= IO_WR & ~IO_READY & BRESET; |
end |
|
assign io_busy = IO_RD | IO_WR | rd_done; // access is gone in next clock cycle, therefore blocked |
|
always @(posedge BCLK) rd_done <= IO_RD & IO_READY; // For READ one clock later for data to come th |
|
assign dma = ICTODC[2]; // external request HOLD after FF in ICACHE |
|
always @(posedge BCLK) dma_run <= (dma_go | (dma_run & dma)) & BRESET; // stops the data access unt |
|
assign HLDA = ~(ICTODC[1] & dma_run); // Signal for system that the CPU has stopped accesses |
|
always @(posedge BCLK) dma_kdet <= FILLRAM; |
assign DMA_MUX = FILLRAM | dma_kdet; |
|
// global feedback to ADDR_UNIT, early feedback to Op-Dec : you can continue |
|
assign ACC_OK = ZTEST ? (~VIRTUELL | zt_ok) |
: (IO_SPACE ? ((IO_ACC & WRITE) | rd_done) : (wr_dram | (READ & MMU_HIT & rd_ende & run_dc)) |
|
// PTB1 and PTB0 |
|
always @(posedge BCLK) if (PTB_WR && !PTB_SEL) ptb0 <= CPU_OUT[27:12]; |
always @(posedge BCLK) if (PTB_WR && PTB_SEL) ptb1 <= CPU_OUT[27:12]; |
|
always @(posedge BCLK) NEW_PTB <= PTB_WR; // to MMU Update Block |
always @(posedge BCLK) if (PTB_WR) PTB_ONE <= PTB_SEL; |
|
assign ptb10 = SEL_PTB1 ? ptb1 : ptb0; |
|
// Address multiplex between ICACHE=1 and DCACHE=0 : |
always @(posedge BCLK) if (pte_go) icp_acc <= do_ic_p; |
|
assign pte_sel = pte_go ? do_ic_p : icp_acc; |
|
assign virtual_adr = pte_sel ? IC_VA : VADR_R; |
|
// The 2 Address-LSB's : no full access : USE_CA = 0 |
assign PTE_ADR = rd_level2 ? {CAPDAT[27:12],virtual_adr[21:12],2'b00} : {ptb10,virtual_adr[31:22],2 |
|
// PTE_DAT[8] is used for update of MMU_RAM. |
assign pte_dat_8 = (level2 & WRITE & write_ok & ~icp_acc) | CAPDAT[8]; |
always @(posedge BCLK) pte_modi = pte_dat_8; |
assign PTE_DAT = {4'h3,CAPDAT[15:9],pte_modi,1'b1,CAPDAT[6:0]}; // the top 4 bits are Byte-Enable |
|
// The data for the MMU-RAM : 24 Bits , [6]=Cache Inhibit |
assign MMU_DIN = {pl_dat,pte_dat_8,CAPDAT[6],CAPDAT[31:12]}; |
|
// Protection field |
|
always @(posedge BCLK) if (mem_done && (pstate[2:0] == 3'd4)) prot_level1 <= cap_dat[2:1]; |
|
always @(prot_level1 or cap_dat) |
casex ({prot_level1,cap_dat[2]}) |
3'b11_x : pl_dat = cap_dat[2:1]; |
3'b10_1 : pl_dat = 2'b10; |
3'b10_0 : pl_dat = cap_dat[2:1]; |
3'b01_1 : pl_dat = 2'b01; |
3'b01_0 : pl_dat = cap_dat[2:1]; |
3'b00_x : pl_dat = 2'b00; |
endcase |
|
always @(USER or pl_dat) // is used if no PTE update is neccesary for M-Bit if writing is not allow |
casex ({USER,pl_dat}) |
3'b1_11 : write_ok = 1'b1; |
3'b0_1x : write_ok = 1'b1; |
3'b0_01 : write_ok = 1'b1; |
default : write_ok = 1'b0; |
endcase |
|
assign acc_level = level2 ? pl_dat : cap_dat[2:1]; |
assign user_ptw = icp_acc ? ICTODC[3] : USER; |
assign wr_ptw = ~icp_acc & (WRITE | RMW | (ZTEST & ~RWVAL[1])); // only data cache can write |
|
always @(acc_level or user_ptw or wr_ptw) |
case (acc_level) |
2'b00 : prot_i = user_ptw | wr_ptw; |
2'b01 : prot_i = user_ptw; |
2'b10 : prot_i = user_ptw & wr_ptw; |
2'b11 : prot_i = 1'b0; |
endcase |
|
endmodule |
|
/trunk/rtl/example.v
0,0 → 1,209
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: example.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// example Your first system with the M32632 CPU |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module example ( CLK, RESET_N, NMI_N, INT_N, IN_REG, OUT_REG); |
|
input CLK; |
input RESET_N; |
input NMI_N; |
input INT_N; |
|
input [7:0] IN_REG; |
|
output [7:0] OUT_REG; |
|
reg nmi_reg,int_reg; |
|
wire IC_MDONE; |
wire DC_MDONE; |
wire ENWR; |
wire WAMUX; |
wire [11:2] WADDR; |
wire [31:0] DRAM_Q; |
wire [2:0] IWCTRL; |
wire [2:0] DWCTRL; |
wire IC_ACC; |
wire [27:0] IDRAM_ADR; |
wire DC_ACC; |
wire DC_WR; |
wire [27:0] DRAM_ADR; |
wire [35:0] DRAM_DI; |
|
wire [31:0] IO_A; |
wire [31:0] IO_DI; |
wire [3:0] IO_BE; |
wire IO_RD; |
wire IO_WR; |
wire IO_READY; |
wire ENDRAM; |
wire [31:0] IO_Q; |
wire W_OUT_REG; |
wire RST_N; |
|
wire [31:0] BOOT_DAT; |
wire [31:0] STAT_DAT; |
wire [7:0] IN_DAT; |
|
wire [7:0] STATSIGS; |
wire COP_GO; |
wire [23:0] COP_OP; |
wire [127:0] COP_OUT; |
wire COP_DONE; |
wire [63:0] COP_IN; |
|
M32632 CPU( |
// ++++++++++ Basic Signals |
.BCLK(CLK), |
.MCLK(~CLK), |
.WRCFG(1'b1), |
.BRESET(RST_N), |
.NMI_N(nmi_reg), |
.INT_N(int_reg), |
.STATUS(), |
.ILO(), |
.STATSIGS(STATSIGS), |
// +++++++++ General Purpose Interface |
.IO_WR(IO_WR), |
.IO_RD(IO_RD), |
.IO_A(IO_A), |
.IO_BE(IO_BE), |
.IO_DI(IO_DI), |
.IO_Q(IO_Q), |
.IO_READY(IO_READY), |
// +++++++++ DRAM Interface In |
.ENDRAM(ENDRAM), |
.IC_MDONE(IC_MDONE), |
.DC_MDONE(DC_MDONE), |
.ENWR(ENWR), |
.WAMUX(WAMUX), |
.WADDR(WADDR), |
.DRAM_Q(DRAM_Q), |
.DWCTRL(DWCTRL), |
.IWCTRL(IWCTRL), |
// +++++++++ DRAM Interface Out |
.IC_ACC(IC_ACC), |
.IDRAM_ADR(IDRAM_ADR), |
.DC_ACC(DC_ACC), |
.DC_WR(DC_WR), |
.DRAM_ADR(DRAM_ADR), |
.DRAM_DI(DRAM_DI), |
// ++++++++++ DMA Interface |
.HOLD(1'b1), |
.HLDA(), |
.FILLRAM(1'b0), |
.DMA_AA(24'd0), |
// ++++++++++ Coprocessor Interface |
.COP_GO(COP_GO), |
.COP_OP(COP_OP), |
.COP_OUT(COP_OUT), |
.COP_DONE(COP_DONE), |
.COP_IN(COP_IN)); |
|
ex_io_bus_ctrl u_bus_ctrl( |
.CLK(CLK), |
.RESET_N(RESET_N), |
.RST_N(RST_N), |
.ENDRAM(ENDRAM), |
.IO_WR(IO_WR), |
.IO_RD(IO_RD), |
.IO_A(IO_A[31:28]), |
.IO_BE(IO_BE), |
.IO_Q(IO_Q), |
.IO_READY(IO_READY), |
.W_OUT_REG(W_OUT_REG), |
.IN_DAT(IN_DAT), |
.BOOT_DAT(BOOT_DAT), |
.STAT_DAT(STAT_DAT)); |
|
ex_in_reg u_in_reg( |
.CLK(CLK), |
.IN_REG(IN_REG), |
.IN_DAT(IN_DAT)); |
|
ex_out_reg u_out_reg( |
.CLK(CLK), |
.OUT_REG(OUT_REG), |
.W_OUT_REG(W_OUT_REG), |
.DIN(IO_DI)); |
|
ex_boot_rom u_boot_rom( |
.CLK(CLK), |
.ADDR(IO_A[9:2]), |
.DATA(BOOT_DAT)); |
|
ex_statcou u_statcou( |
.CLK(CLK), |
.RST_N(RST_N), |
.STATSIGS(STATSIGS), |
.ADDR(IO_A[4:2]), |
.DATA(STAT_DAT)); |
|
ex_copro u_copro( |
.CLK(CLK), |
.COP_GO(COP_GO), |
.COP_OP(COP_OP), |
.COP_INP(COP_OUT), |
.COP_DONE(COP_DONE), |
.COP_OUTP(COP_IN)); |
|
ex_dram_emul u_dram_emul( |
.MCLK(CLK), |
.RST_N(RST_N), |
.IC_ACC(IC_ACC), |
.IDRAM_ADR(IDRAM_ADR), |
.DC_ACC(DC_ACC), |
.DC_WR(DC_WR), |
.DRAM_ADR(DRAM_ADR), |
.DRAM_DI(DRAM_DI), |
.IC_MDONE(IC_MDONE), |
.DC_MDONE(DC_MDONE), |
.ENWR(ENWR), |
.WAMUX(WAMUX), |
.WADDR(WADDR), |
.MEM_Q(DRAM_Q), |
.DWCTRL(DWCTRL), |
.IWCTRL(IWCTRL) ); |
|
always @(posedge CLK) // recommended to synchronize this signals |
begin |
nmi_reg <= NMI_N; |
int_reg <= INT_N; |
end |
|
endmodule |
/trunk/rtl/M32632.v
0,0 → 1,445
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: M32632.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// M32632 The top level of M32632 |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module M32632( BCLK, MCLK, WRCFG, BRESET, NMI_N, INT_N, STATUS, ILO, STATSIGS, |
IO_WR, IO_RD, IO_A, IO_BE, IO_DI, IO_Q, IO_READY, |
ENDRAM, IC_MDONE, DC_MDONE, ENWR, WAMUX, WADDR, DRAM_Q, DWCTRL, IWCTRL, |
IC_ACC, IDRAM_ADR, DC_ACC, DC_WR, DRAM_ADR, DRAM_DI, |
HOLD, HLDA, FILLRAM, DMA_AA, |
COP_GO, COP_OP, COP_OUT, COP_DONE, COP_IN ); |
|
// ++++++++++ Basic Signals |
input BCLK; // Basic Clock for everything |
input MCLK; // Memory Clock, used in Caches |
input WRCFG; |
input BRESET; |
input NMI_N; |
input INT_N; |
output [3:0] STATUS; |
output ILO; |
output [7:0] STATSIGS; |
// +++++++++ General Purpose Interface |
output IO_WR; |
output IO_RD; |
output [31:0] IO_A; |
output [3:0] IO_BE; |
output [31:0] IO_DI; |
input [31:0] IO_Q; |
input IO_READY; |
// +++++++++ DRAM Interface In |
input ENDRAM; |
input IC_MDONE; |
input DC_MDONE; |
input ENWR; |
input WAMUX; |
input [11:2] WADDR; |
input [31:0] DRAM_Q; |
input [2:0] DWCTRL; |
input [2:0] IWCTRL; |
// +++++++++ DRAM Interface Out |
output IC_ACC; |
output [27:0] IDRAM_ADR; |
output DC_ACC; |
output DC_WR; |
output [27:0] DRAM_ADR; |
output [35:0] DRAM_DI; |
// ++++++++++ DMA Interface |
input HOLD; |
output HLDA; |
input FILLRAM; |
input [27:4] DMA_AA; |
// ++++++++++ Coprocessor Interface |
output COP_GO; |
output [23:0] COP_OP; |
output [127:0] COP_OUT; |
input COP_DONE; |
input [63:0] COP_IN; |
|
wire ACC_DONE; |
wire [5:0] ACC_STAT; |
wire [12:0] CFG; |
wire [3:0] CINV; |
wire DATA_HOLD; |
wire DC_INIT; |
wire Y_INIT; |
wire DONE; |
wire [63:0] DP_Q; |
wire [3:0] IACC_STAT; |
wire PROT_ERROR; |
wire [2:0] GENSTAT; |
wire IC_INIT; |
wire IC_PREQ; |
wire IC_READ; |
wire [1:0] IC_SIGS; |
wire IC_USER; |
wire [31:12] IC_VA; |
wire [3:0] ICTODC; |
wire [6:0] INFO_AU; |
wire [1:0] IVAR; |
wire KDET; |
wire [27:4] KOLLI_A; |
wire [3:0] MCR; |
wire [23:0] MMU_DIN; |
wire [11:0] PSR; |
wire PTB_SEL; |
wire PTB_WR; |
wire READ; |
wire WRITE; |
wire ZTEST; |
wire RMW; |
wire [2:0] RWVAL; |
wire RWVFLAG; |
wire [3:0] D_IOBE; |
wire D_IORDY; |
wire REG_OUT; |
wire [3:0] PACKET; |
wire [1:0] SIZE; |
wire [31:0] VADR; |
wire WREN_REG; |
wire LD_DIN; |
wire LD_IMME; |
wire WR_REG; |
wire [14:0] ACC_FELD; |
wire [31:0] DIN; |
wire [31:0] DISP; |
wire [2:0] IC_TEX; |
wire [31:0] IMME_Q; |
wire [1:0] LD_OUT; |
wire [12:0] DETOIP; |
wire [1:0] MMU_UPDATE; |
wire [10:0] OPER; |
wire [31:0] PC_ARCHI; |
wire [31:0] PC_ICACHE; |
wire [7:0] RDAA; |
wire [7:0] RDAB; |
wire [1:0] START; |
wire [1:0] WMASKE; |
wire [5:0] WRADR; |
wire I_IORDY; |
wire ACB_ZERO; |
wire DC_ABORT; |
wire SAVE_PC; |
wire [31:0] IC_DIN; |
wire [31:0] PC_NEW; |
wire [4:0] STRING; |
wire [5:0] TRAPS; |
wire I_IORD; |
wire D_IOWR; |
wire D_IORD; |
wire [31:0] D_IOA; |
wire [31:0] I_IOA; |
wire ENA_HK; |
wire STOP_CINV; |
wire KOLLISION; |
wire ILO_SIG; |
wire [1:0] PTE_STAT; |
wire DBG_HIT; |
wire [40:2] DBG_IN; |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Data Cache |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
DCACHE ARMS( |
.MCLK(MCLK), |
.BCLK(BCLK), |
.WRCFG(WRCFG), |
.BRESET(BRESET), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.MDONE(DC_MDONE), |
.IO_READY(D_IORDY), |
.REG_OUT(REG_OUT), |
.PSR_USER(INFO_AU[1]), |
.WRITE(WRITE), |
.READ(READ), |
.ZTEST(ZTEST), |
.RMW(RMW), |
.WAMUX(WAMUX), |
.ENWR(ENWR), |
.IC_PREQ(IC_PREQ), |
.FILLRAM(FILLRAM), |
.CFG(CFG[10:9]), |
.ENDRAM(ENDRAM), |
.CINVAL(CINV[1:0]), |
.DMA_AA(DMA_AA), |
.DP_Q(DP_Q), |
.DRAM_Q(DRAM_Q), |
.IC_VA(IC_VA), |
.ICTODC(ICTODC), |
.IO_Q(IO_Q), |
.IVAR(IVAR), |
.MCR_FLAGS(MCR), |
.PACKET(PACKET), |
.SIZE(SIZE), |
.VADR(VADR), |
.WADDR(WADDR), |
.WCTRL(DWCTRL), |
.DRAM_ACC(DC_ACC), |
.DRAM_WR(DC_WR), |
.IO_RD(D_IORD), |
.IO_WR(D_IOWR), |
.INIT_RUN(DC_INIT), |
.KDET(KDET), |
.HLDA(HLDA), |
.ACC_STAT(ACC_STAT), |
.DP_DI(DIN), |
.DRAM_A(DRAM_ADR), |
.DRAM_DI(DRAM_DI), |
.IACC_STAT(IACC_STAT[3:1]), |
.IC_SIGS(IC_SIGS), |
.IO_A(D_IOA), |
.IO_BE(D_IOBE), |
.IO_DI(IO_DI), |
.PTE_STAT(PTE_STAT), |
.DBG_HIT(DBG_HIT), |
.DBG_IN(DBG_IN), |
.KOLLI_A(KOLLI_A), |
.MMU_DIN(MMU_DIN), |
.RWVAL(RWVAL), |
.RWVFLAG(RWVFLAG)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Datapath |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
DATENPFAD STOMACH( |
.WREN(WREN_REG), |
.BRESET(BRESET), |
.BCLK(BCLK), |
.IO_READY(D_IORDY), |
.LD_DIN(LD_DIN), |
.LD_IMME(LD_IMME), |
.WR_REG(WR_REG), |
.IC_USER(IC_USER), |
.ACC_FELD(ACC_FELD), |
.ACC_STAT(ACC_STAT), |
.DIN(DIN), |
.DISP(DISP), |
.IC_TEX(IC_TEX), |
.IMME_Q(IMME_Q), |
.INFO_AU(INFO_AU), |
.LD_OUT(LD_OUT), |
.DETOIP(DETOIP), |
.MMU_UPDATE(MMU_UPDATE), |
.OPER(OPER), |
.PC_ARCHI(PC_ARCHI), |
.PC_ICACHE(PC_ICACHE), |
.RDAA(RDAA), |
.RDAB(RDAB), |
.START(START), |
.WMASKE(WMASKE), |
.WRADR(WRADR), |
.READ_OUT(READ), |
.WRITE_OUT(WRITE), |
.ZTEST(ZTEST), |
.RMW(RMW), |
.ACC_DONE(ACC_DONE), |
.REG_OUT(REG_OUT), |
.Y_INIT(Y_INIT), |
.DONE(DONE), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.ACB_ZERO(ACB_ZERO), |
.ABORT(DC_ABORT), |
.SAVE_PC(SAVE_PC), |
.CFG(CFG), |
.CINV(CINV), |
.DP_Q(DP_Q), |
.IVAR(IVAR), |
.MCR(MCR), |
.PACKET(PACKET), |
.PC_NEW(PC_NEW), |
.PSR(PSR), |
.SIZE(SIZE), |
.STRING(STRING), |
.TRAPS(TRAPS), |
.VADR(VADR), |
.RWVFLAG(RWVFLAG), |
.DBG_HIT(DBG_HIT), |
.DBG_IN(DBG_IN), |
.COP_DONE(COP_DONE), |
.COP_OP(COP_OP), |
.COP_IN(COP_IN), |
.COP_GO(COP_GO), |
.COP_OUT(COP_OUT)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Instruction Cache |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
ICACHE LEGS( |
.MCLK(MCLK), |
.BCLK(BCLK), |
.BRESET(BRESET), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.MDONE(IC_MDONE), |
.IO_READY(I_IORDY), |
.READ_I(IC_READ), |
.PSR_USER(IC_USER), |
.DATA_HOLD(DATA_HOLD), |
.DRAM_WR(DC_WR), |
.KDET(KDET), |
.HOLD(HOLD), |
.CFG(CFG[12:11]), |
.ENDRAM(ENDRAM), |
.DRAM_Q(DRAM_Q), |
.CINVAL(CINV[3:2]), |
.IC_SIGS(IC_SIGS), |
.IO_Q(IO_Q), |
.IVAR(IVAR), |
.KOLLI_A(KOLLI_A), |
.MCR_FLAGS(MCR), |
.MMU_DIN(MMU_DIN), |
.VADR(PC_ICACHE), |
.WADDR(WADDR), |
.WCTRL(IWCTRL), |
.DRAM_ACC(IC_ACC), |
.IO_RD(I_IORD), |
.INIT_RUN(IC_INIT), |
.PROT_ERROR(PROT_ERROR), |
.ACC_OK(IACC_STAT[0]), |
.IC_PREQ(IC_PREQ), |
.KOLLISION(KOLLISION), |
.DRAM_A(IDRAM_ADR), |
.IC_DQ(IC_DIN), |
.IC_VA(IC_VA), |
.ICTODC(ICTODC), |
.ENA_HK(ENA_HK), |
.STOP_CINV(STOP_CINV), |
.IO_A(I_IOA)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Control Unit |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
STEUERUNG BRAIN( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.DC_ACC_DONE(ACC_DONE), |
.ACB_ZERO(ACB_ZERO), |
.DONE(DONE), |
.NMI_N(NMI_N), |
.INT_N(INT_N), |
.DC_ABORT(DC_ABORT), |
.IC_INIT(IC_INIT), |
.DC_INIT(DC_INIT), |
.Y_INIT(Y_INIT), |
.SAVE_PC(SAVE_PC), |
.CFG(CFG[8:0]), |
.IACC_STAT(IACC_STAT), |
.PROT_ERROR(PROT_ERROR), |
.IC_DIN(IC_DIN), |
.PC_NEW(PC_NEW), |
.PSR(PSR), |
.STRING(STRING), |
.TRAPS(TRAPS), |
.IC_READ(IC_READ), |
.DATA_HOLD(DATA_HOLD), |
.LD_DIN(LD_DIN), |
.LD_IMME(LD_IMME), |
.WREN(WREN_REG), |
.WR_REG(WR_REG), |
.GENSTAT(GENSTAT), |
.IC_USER(IC_USER), |
.ACC_FELD(ACC_FELD), |
.DISP(DISP), |
.IC_TEX(IC_TEX), |
.IMME_Q(IMME_Q), |
.INFO_AU(INFO_AU), |
.LD_OUT(LD_OUT), |
.DETOIP(DETOIP), |
.MMU_UPDATE(MMU_UPDATE), |
.OPER(OPER), |
.PC_ARCHI(PC_ARCHI), |
.PC_ICACHE(PC_ICACHE), |
.RDAA(RDAA), |
.RDAB(RDAB), |
.START(START), |
.WMASKE(WMASKE), |
.WRADR(WRADR), |
.ENA_HK(ENA_HK), |
.STOP_CINV(STOP_CINV), |
.COP_OP(COP_OP), |
.ILO(ILO_SIG), |
.RWVAL(RWVAL)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Input/Output Interface |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
IO_SWITCH ISWITCH( |
.I_IORD(I_IORD), |
.D_IOWR(D_IOWR), |
.IO_READY(IO_READY), |
.D_IORD(D_IORD), |
.D_IOBE(D_IOBE), |
.BRESET(BRESET), |
.BCLK(BCLK), |
.GENSTAT(GENSTAT), |
.D_IOA(D_IOA), |
.I_IOA(I_IOA), |
.D_IORDY(D_IORDY), |
.I_IORDY(I_IORDY), |
.IO_RD(IO_RD), |
.IO_WR(IO_WR), |
.IO_BE(IO_BE), |
.ILO_SIG(ILO_SIG), |
.ILO(ILO), |
.IO_A(IO_A), |
.DCWACC({DC_WR,DC_ACC}), |
.STATUS(STATUS)); |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// The Statistic Signal Generator |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
MAKE_STAT MKSTAT( |
.BCLK(BCLK), |
.READ(READ), |
.DACC_OK(ACC_STAT[0]), |
.KOLLISION(KOLLISION), |
.DC_ACC(DC_ACC), |
.DPTE_ACC(PTE_STAT[0]), |
.DC_MDONE(DC_MDONE), |
.DRAM_WR(DC_WR), |
.IC_READ(IC_READ), |
.IACC_OK(IACC_STAT[0]), |
.IC_ACC(IC_ACC), |
.IPTE_ACC(PTE_STAT[1]), |
.IC_MDONE(IC_MDONE), |
.DATA_HOLD(DATA_HOLD), |
.STATSIGS(STATSIGS)); |
|
endmodule |
/trunk/rtl/SP_FPU.v
0,0 → 1,472
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: SP_FPU.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. ADDSUB Adder and Subtractor for 36 bit |
// 2. SFPU_ADDSUB Single Precision Floating Point Adder/Subtractor and Converter |
// 3. SFPU_MUL Single Precision Floating Point Multiplier |
// 4. SP_FPU Top Level of Single Precision Floating Point Unit |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. ADDSUB Adder and Subtractor for 36 bit |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module ADDSUB (dataa, datab, add_sub, result); |
|
input [35:0] dataa,datab; |
input add_sub; // 1 = Addition , 0 = Subtraction |
output [35:0] result; |
|
assign result = dataa + (add_sub ? datab : ~datab) + {35'd0,~add_sub}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. SFPU_ADDSUB Single Precision Floating Point Adder/Subtractor and Converter |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SFPU_ADDSUB ( SRC1, SRC2, NZEXP, BWD, SELECT, OUT, IOUT, CMPRES ); |
|
input [31:0] SRC1,SRC2; // Input data |
input [2:1] NZEXP; |
input [1:0] BWD; // size of integer |
input [3:0] SELECT; |
|
output [36:0] OUT; // the result |
output [31:0] IOUT; // result of ROUNDFi/TRUNCFi/FLOORFi |
output [1:0] CMPRES; |
|
// ++++++++++++++++++++++++++++++++++ |
// MOViF : 1. step |
|
reg [31:8] movdat; |
wire [31:0] movif; |
|
always @(BWD or SRC1) |
casex({BWD,SRC1[15],SRC1[7]}) |
4'b00x0 : movdat = 24'h0000_00; // Byte |
4'b00x1 : movdat = 24'hFFFF_FF; |
4'b010x : movdat = {16'h0000,SRC1[15:8]}; // Word |
4'b011x : movdat = {16'hFFFF,SRC1[15:8]}; |
default : movdat = SRC1[31:8]; // Double |
endcase |
|
assign movif = movdat[31] ? (32'h0 - {movdat,SRC1[7:0]}) : {movdat,SRC1[7:0]}; |
// -2^31 is kept |
|
// ROUNDFi/TRUNCFi/FLOORFi : 1. step |
|
reg ovflag,ovflag2; |
wire [8:0] rexdiff,rexo; |
wire rovfl,minint; |
wire ganzklein; // Flag for 0 |
|
assign rexdiff = 9'h09D - {1'b0,SRC1[30:23]}; // 4..0 is the right shift value |
assign rovfl = (ovflag | ovflag2) & (SELECT[1:0] == 2'b11) & ~minint; |
assign ganzklein = (~rexdiff[8] & (rexdiff[7:5] != 3'b000)); // 0 is implicit via SRC1[30:23]=0 |
|
// Detection of Overflow |
assign rexo = ({1'b0,SRC1[30:23]} - {8'h3F,~BWD[1]}); // subtract B/W = 7F , D = 7E |
|
always @(BWD or rexo) |
casex (BWD) |
2'b00 : ovflag = (~rexo[8] & (rexo[7:3] != 5'h0)); // Exponent 0..7 because of -128.4 => -128 |
2'b01 : ovflag = (~rexo[8] & (rexo[7:4] != 4'h0)); // Exponent 0..15 because of -128.4 => -128 |
default : ovflag = (~rexo[8] & (rexo[7:5] != 3'h0)); // Exponent only 0..30 |
endcase |
|
assign minint = (SRC1 == 32'hCF00_0000) & BWD[1]; // detection of -2^31 |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 1. step : which operand ist bigger ? if required exchange |
// SUB/CMP : SRC2 - SRC1 |
|
wire [8:0] exdiff; |
wire [23:0] madiff; |
wire switch,sign,sign1,sign2; |
wire variante; |
wire vorz,addflag; |
wire [35:0] result_sw,result_nosw; |
wire [24:0] value1,value2; |
|
wire [35:0] result; |
|
assign exdiff = {1'b0,SRC2[30:23]} - {1'b0,SRC1[30:23]}; // Difference of Exponents |
assign madiff = {1'b0,SRC2[22:0]} - {1'b0,SRC1[22:0]}; // Difference of Mantissas |
|
// if exdiff = 0 the shifter to the right is not needed ! |
assign variante = (exdiff[8:1] == 8'h00) | (exdiff == 9'h1FF) | SELECT[1]; // MUX at the end, ROUND |
|
// ++++++++++++++++++++++++++ 1. case works on MOViF +++++++++++++++++++++++++++++++++++++++ |
|
assign switch = exdiff[8] | ((exdiff[7:0] == 8'h0) & madiff[23]); // exchange ? |
|
assign value1 = exdiff[0] ? {1'b0,NZEXP[1],SRC1[22:0]} : {NZEXP[1],SRC1[22:0],1'b0}; |
assign value2 = exdiff[0] ? {1'b0,NZEXP[2],SRC2[22:0]} : {NZEXP[2],SRC2[22:0],1'b0}; |
|
// The Subtraction needs 3 Guard-Bits after LSB for rounding ! 36 Bit wide |
// 1 |
ADDSUB addsub_nosw (.dataa({1'b0,SRC2[30:23],NZEXP[2],SRC2[22:0],3'b000}), |
.datab({9'h0,value1,2'b0}), .add_sub(addflag), |
.result(result_nosw) ); |
|
ADDSUB addsub_sw (.dataa({1'b0,SRC1[30:23],NZEXP[1],SRC1[22:0],3'b000}), |
.datab({9'h0,value2,2'b0}), .add_sub(addflag), |
.result(result_sw) ); |
|
assign result = switch ? result_sw : result_nosw; |
|
// SRC2 SRC1 : switch = 0 SRC2 SRC1 : switch = 1 |
// 5 + 3 : +(5 + 3) = 8 3 + 5 : +(5 + 3) = 8 SELECT[0] = 0 |
// 5 + (-3) : +(5 - 3) = 2 3 + (-5) : -(5 - 3) = -2 |
// (-5) + 3 : -(5 - 3) = -2 (-3) + 5 : +(5 - 3) = 2 |
// (-5) + (-3) : -(5 + 3) = -8 (-3) + (-5) : -(5 + 3) = -8 |
// 5 - 3 : +(5 - 3) = 2 3 - 5 : -(5 - 3) = -2 SELECT[0] = 1 |
// 5 - (-3) : +(5 + 3) = 8 3 - (-5) : +(5 + 3) = 8 |
// (-5) - 3 : -(5 + 3) = -8 (-3) - 5 : -(5 + 3) = -8 |
// (-5) - (-3) : -(5 - 3) = -2 (-3) - (-5) : +(5 - 3) = 2 |
|
assign sign1 = SRC1[31]; |
assign sign2 = SRC2[31]; |
|
assign vorz = switch ? (SELECT[0] ^ sign1) : sign2; |
assign addflag = ~(SELECT[0] ^ (sign1 ^ sign2)); |
|
// CMPF : 1. step : what happend if Invalid Operand occurs - no Flag update ! |
|
assign CMPRES[1] = ~CMPRES[0] & (switch ? ~sign1 : sign2); // see table above : N-Bit=1 if SRC1 > |
assign CMPRES[0] = (SRC1 == SRC2) | (~NZEXP[2] & ~NZEXP[1]); // Z-Bit : SRC1=SRC2, +0.0 = -0.0 |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 3. step : prepare of Barrelshifter Left |
|
wire [31:0] blshift; |
wire [9:0] shiftl; |
wire shift_16; |
wire [33:0] add_q; |
wire [31:0] muxsrc2; |
wire [1:0] inex; |
|
assign blshift = SELECT[1] ? movif : {result[26:0],5'h00}; // Feeding of MOViF |
|
assign shiftl = SELECT[1] ? 10'h09E : {1'b0,result[35:27]}; // MOViF |
|
assign shift_16 = (blshift[31:16] == 16'h0000); |
|
// In case of ADD the result bypasses the Barrelshifter left |
assign add_q = (muxsrc2[24] != result[27]) ? {result[35:3],(result[2:0] != 3'b000)} |
: {result[35:27],result[25:2],(result[1:0] != 2'b00)} ; |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB : 4. step : Barrelshifter left for SUB and MOViF : |
|
wire shift_8,shift_4,shift_2,shift_1,zero; |
wire [1:0] lsb_bl; |
wire [31:0] blshifta,blshiftb,blshiftc,blshiftd,blshifte; |
wire [9:0] expol; |
wire [36:0] out_v1; |
|
assign blshifta = shift_16 ? {blshift[15:0],16'h0000} : blshift; |
assign shift_8 = (blshifta[31:24] == 8'h00); |
assign blshiftb = shift_8 ? {blshifta[23:0],8'h00} : blshifta; |
assign shift_4 = (blshiftb[31:28] == 4'h0); |
assign blshiftc = shift_4 ? {blshiftb[27:0],4'h0} : blshiftb; |
assign shift_2 = (blshiftc[31:30] == 2'b00); |
assign blshiftd = shift_2 ? {blshiftc[29:0],2'b00} : blshiftc; |
assign shift_1 = ~blshiftd[31]; |
assign blshifte = shift_1 ? {blshiftd[30:0],1'b0} : blshiftd; |
|
// Overflow at ROUNDFi/TRUNCFi/FLOORFi via overflow in exponent shown, SELECT[1] is then 1 ! |
assign expol = (shiftl - {5'h00,shift_16,shift_8,shift_4,shift_2,shift_1}) | {1'b0,rovfl,8'h00}; |
|
// Inexact at ROUNDFi/TRUNCFi/FLOORFi : evaluation for all one level higher |
assign lsb_bl = (SELECT[1:0] == 2'b11) ? inex : {blshifte[7],(blshifte[6:0] != 7'h00)}; |
|
assign zero = (~SELECT[1] & ~NZEXP[2] & ~NZEXP[1]) |
| ((blshift == 32'h0) & ((~addflag & ~SELECT[1]) | (SELECT[1:0] == 2'b10))); |
|
assign sign = SELECT[1] ? movdat[31] : vorz; |
|
assign out_v1 = (addflag & ~SELECT[1]) ? {zero,sign,1'b0,add_q} |
: {zero,sign,expol,blshifte[30:8],lsb_bl}; |
|
// +++++++++++++++++++++++++ 2. case works on ROUND/TRUNC/FLOOR ++++++++++++++++++++++++++++++++++ |
|
wire vswitch; |
wire [4:0] shift1,shift2; |
wire [8:0] exdiff12; |
wire [23:0] muxsrc1; |
wire [32:9] pipe1; // numbering special for Right Shifter |
wire [4:0] shift; |
|
// the difference between SRC1 and SRC2 is bigger/equal 4:1 => no Barrelshifter after ADDSUB neccess |
|
assign vswitch = exdiff[8]; // exchange ? |
|
assign shift1 = (exdiff[7:5] != 3'h0) ? 5'h1F : exdiff[4:0]; |
assign exdiff12 = {1'b0,SRC1[30:23]} - {1'b0,SRC2[30:23]}; // caclulate already |
assign shift2 = (exdiff12[7:5] != 3'h0) ? 5'h1F : exdiff12[4:0]; |
|
assign muxsrc2 = vswitch ? {SRC1[30:23],1'b1,SRC1[22:0]} : {SRC2[30:23],1'b1,SRC2[22:0]}; // Includ |
assign muxsrc1 = vswitch ? {NZEXP[2],SRC2[22:0]} : {NZEXP[1],SRC1[22:0]}; |
|
assign pipe1 = SELECT[1] ? (ganzklein ? 24'h0 : {NZEXP[1],SRC1[22:0]}) : muxsrc1; // Feeding in R.T |
|
assign shift = SELECT[1] ? rexdiff[4:0] : (vswitch ? shift2 : shift1); |
|
// ++++++++++++++++++++++++++++++++++ |
// ADD/SUB + ROUND/TRUNC/FLOOR : 2. step : Barrelshifter to right --> |
|
wire [32:0] brshifta,brshiftb,brshiftc,brshiftd; |
wire [32:0] brshifte; // last stage |
|
// 33322222222221111111111 |
// 2109876543210987654321098765432-10 |
// 1VVVVVVVVVVVVVVVVVVVVVVV0000000-00 // last 2 Bit for rounding |
|
assign brshifta = shift[4] ? {16'h0,pipe1[32:17], (pipe1[16:9] != 8'h00)} : {pipe1,9'h0}; |
assign brshiftb = shift[3] ? { 8'h0,brshifta[32:9],(brshifta[8:0] != 9'h000)} : brshifta; |
assign brshiftc = shift[2] ? { 4'h0,brshiftb[32:5],(brshiftb[4:0] != 5'h00)} : brshiftb; |
assign brshiftd = shift[1] ? { 2'h0,brshiftc[32:3],(brshiftc[2:0] != 3'h0)} : brshiftc; |
assign brshifte = shift[0] ? { 1'b0,brshiftd[32:2],(brshiftd[1:0] != 2'h0)} : brshiftd; |
|
// ++++++++++++++++++++++++++++++++++ |
// ROUNDFi/TRUNCFi/FLOORFi : 3. step : round to integer |
|
reg car_ry; |
wire [30:0] compl; |
wire [31:0] iadder; |
|
assign inex = brshifte[1:0]; // Inexact-Flag-Data via multiplexer at the end |
|
always @(SELECT or sign1 or brshifte or inex or ganzklein) |
casex (SELECT[3:2]) |
2'b00 : car_ry = sign1 ^ ((brshifte[2:0] == 3'b110) | (inex == 2'b11)); // ROUNDLi |
2'b1x : car_ry = sign1 ? (~ganzklein & (inex == 2'b00)) : 1'b0; // +numbers like TRUNCLi, -num |
default : car_ry = sign1; // TRUNCLi , simple cut |
endcase |
|
assign compl = sign1 ? ~brshifte[32:2] : brshifte[32:2]; |
|
assign iadder = {sign1,compl} + {31'h0,car_ry}; |
|
assign IOUT = minint ? 32'h8000_0000 : iadder; |
|
always @(iadder or BWD or sign1) // special overflow detection i.e. -129 bis -255 bei Byte |
casex (BWD) // or 127.9 -> 128 = Fehler ! |
2'b00 : ovflag2 = (iadder[8] != iadder[7]); // Byte |
2'b01 : ovflag2 = (iadder[16] != iadder[15]); // Word |
default : ovflag2 = 1'b0; |
endcase |
|
// ++++++++++++++++++++++++++++++++++ |
// only ADD/SUB : 3. step : Add or Subtract |
// the modul ADDSUB integrates the carry from the mantissa : 35 Bit |
|
wire lsb; |
wire [35:0] vresult; |
wire [7:0] eminus1; |
wire [33:0] vadd_q,vsub_q; |
wire vzero; |
wire [36:0] out_v0; |
|
assign lsb = (brshifte[6:0] != 7'h00); |
|
// Adder-Definition : "0"(8 Bit Exponent)"1"(23 Bit Mantissa)"000" |
|
ADDSUB addsub_v (.dataa({1'b0,muxsrc2,3'b000}), |
.datab({9'h0,brshifte[32:7],lsb}), .add_sub(addflag), |
.result(vresult) ); |
|
assign eminus1 = muxsrc2[31:24] - 8'h01; // a greater Underflow can not exist, because minimal Expo |
|
// Case ADD : Bit 23 : LSB of exponent |
assign vadd_q = (muxsrc2[24] != vresult[27]) ? {vresult[35:3],(vresult[2:0] != 3'b000)} |
: {vresult[35:27],vresult[25:2],(vresult[1:0] != 2'b00)} ; |
|
// Case SUB : Bit 26 : "hidden" MSB of mantissa |
assign vsub_q = vresult[26] ? {vresult[35:27], vresult[25:2],(vresult[1:0] != 2'b00)} // like t |
: {vresult[35],eminus1,vresult[24:0]} ; |
|
// SELECT[1] has here no meaning |
assign vzero = (vresult[26:0] == 27'h0) & ~addflag; // only if "-" can be the result 0 |
|
assign out_v0 = addflag ? {vzero,vorz,1'b0,vadd_q} |
: {vzero,vorz,1'b0,vsub_q} ; |
|
assign OUT = variante ? out_v1 : out_v0; // Last multiplexer |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. SFPU_MUL Single Precision Floating Point Multiplier |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SFPU_MUL ( SRC1, SRC2, MRESULT, NZEXP, OUT); |
|
input [31:0] SRC1,SRC2; // only exponent of input data used |
input [47:0] MRESULT; |
input [2:1] NZEXP; // Flags of input data |
|
output [36:0] OUT; // The result |
|
wire [9:0] exponent,expoh,expol; |
wire [1:0] restlow,resthigh; |
wire zero,sign,orlow; |
|
assign zero = ~NZEXP[2] | ~NZEXP[1]; // one of both NULL -> NULL is the result |
assign sign = (SRC1[31] ^ SRC2[31]) & ~zero; |
assign orlow = (MRESULT[21:0] != 22'b0); |
|
assign restlow = {MRESULT[22],orlow}; |
assign resthigh = {MRESULT[23],(MRESULT[22] | orlow)}; |
|
assign exponent = {2'b00,SRC1[30:23]} + {2'b00,SRC2[30:23]}; |
assign expoh = exponent - 10'h07E; |
assign expol = exponent - 10'h07F; // for MSB if MRESULT=0 |
|
assign OUT = MRESULT[47] ? {zero,sign,expoh,MRESULT[46:24],resthigh} |
: {zero,sign,expol,MRESULT[45:23],restlow}; |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 4. SP_FPU Top Level of Single Precision Floating Point Unit |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module SP_FPU (BCLK, OPCODE, SRC1, SRC2, FSR, MRESULT, BWD, FL, FP_OUT, I_OUT, TT_SP, SP_CMP, SP_MUX |
|
input BCLK; // is not used ! |
input [7:0] OPCODE; |
input [31:0] SRC1,SRC2; // Input data |
input [8:3] FSR; // Floating Point Status Register |
input [47:0] MRESULT; // Multiplier result |
input [1:0] BWD; // Size of integer |
input FL; |
|
output [31:0] FP_OUT,I_OUT; // The results |
output [4:0] TT_SP; // Trap-Type |
output [2:0] SP_CMP; // CMPF result |
output SP_MUX,LD_FSR,UP_SP; |
|
reg [2:0] tt; |
reg [3:0] select; |
reg car_ry; |
|
wire [36:0] mulout,addout,fpout; |
wire [2:1] nzexp; |
wire [34:2] rund; // Indexnumbers like xxxout |
wire overflow,underflow,inexact; |
wire op_cmp; |
wire nan,nan_1,nan_2; |
|
// Control of datapath |
|
always @(OPCODE) |
casex (OPCODE) |
8'b1011_0000 : select = 4'b1000; // 0 0 0 : ADDF Shifter are reused |
8'b1011_0100 : select = 4'b1001; // 0 0 1 : SUBF |
8'b1001_000x : select = 4'b1010; // 0 1 0 : MOViF |
8'b1001_100x : select = 4'b1011; // 0 1 1 : ROUNDFi |
8'b1001_101x : select = 4'b1011; // 0 1 1 : TRUNCFi |
8'b1001_111x : select = 4'b1011; // 0 1 1 : FLOORFi |
8'b1011_0010 : select = 4'b1001; // 0 0 1 : CMPF |
8'b1011_1100 : select = 4'b1100; // 1 x x : MULF |
default : select = 4'b0; |
endcase |
|
assign SP_MUX = select[3] & (select[1:0] != 2'b11) & FL; // Output multiplexer |
|
assign LD_FSR = (OPCODE[7:4] == 4'h9) & (OPCODE[3:1] == 3'b001); // LFSR does only Double (accordin |
assign UP_SP = select[3] & FL; // All FPU opcodes of SP_FPU |
assign op_cmp = (OPCODE == 8'hB2) & FL; |
|
// SRCFLAGS |
|
assign nzexp[2] = (SRC2[30:23] != 8'd0); // only exponent 0 ,denormalized Number => NAN ! |
assign nzexp[1] = (SRC1[30:23] != 8'd0); // only exponent 0 ,denormalized Number => NAN ! |
assign nan_2 = (SRC2[30:23] == 8'hFF) | (~nzexp[2] & (SRC2[22:0] != 23'd0)); // NAN |
assign nan_1 = (SRC1[30:23] == 8'hFF) | (~nzexp[1] & (SRC1[22:0] != 23'd0)); // NAN |
|
assign nan = (select[1:0] == 2'b11) ? nan_1 : (~select[1] & (nan_2 | nan_1)); |
|
// 001 : ADDF,... + 011 : CMPF |
SFPU_ADDSUB IADDSUB ( .SRC1(SRC1), .SRC2(SRC2), .NZEXP(nzexp), .BWD(BWD), |
.SELECT({OPCODE[2:1],select[1:0]}), .OUT(addout), .IOUT(I_OUT), .CMPRES(SP_CMP[1:0]) ); |
|
// 100 : MULF |
SFPU_MUL IMUL ( .SRC1(SRC1), .SRC2(SRC2), .MRESULT(MRESULT), .OUT(mulout), .NZEXP(nzexp) ); |
|
// FP - Pfad : selection of result and rounding : |
|
assign fpout = (OPCODE[5] & OPCODE[3]) ? mulout : addout; |
|
always @(FSR or fpout) // calculate Carry according rounding mode, fpout[35] = sign bit |
casex (FSR[8:7]) |
2'b00 : car_ry = ((fpout[1:0] == 2'b10) & fpout[2]) | (fpout[1:0] == 2'b11); // round to nearest |
2'b10 : car_ry = ~fpout[35] & (fpout[1:0] != 2'b00); // round to positiv infinity |
2'b11 : car_ry = fpout[35] & (fpout[1:0] != 2'b00); // round to negativ infinity |
default : car_ry = 1'b0; // round to zero |
endcase |
|
assign rund = {fpout[34:2]} + {32'h0,car_ry}; |
|
// Detection of Overflow, Underflow and Inexact : epxonent is [34:25] = 10 Bits |
assign overflow = ~rund[34] & (rund[33] | (rund[32:25] == 8'hFF)); |
assign underflow = (rund[34] | (rund[33:25] == 9'h0)) & ~fpout[36]; // Zero-Flag |
assign inexact = (fpout[1:0] != 2'b00); |
|
// CMPF can have no other error except NAN |
always @(nan or op_cmp or overflow or underflow or inexact or FSR) |
casex ({nan,op_cmp,overflow,FSR[3],underflow,FSR[5],inexact}) |
7'b1xxxxxx : tt = 3'b101; // Invalid operation |
7'b001xxxx : tt = 3'b010; // Overflow |
7'b00011xx : tt = 3'b001; // Underflow |
7'b0000011 : tt = 3'b110; // Inexact Result |
default : tt = 3'b000; // no error |
endcase |
|
assign TT_SP = {(inexact & ~op_cmp),(underflow & ~op_cmp),tt}; |
assign SP_CMP[2] = nan; |
|
// Underflow Special case and force ZERO |
assign FP_OUT = (underflow | fpout[36]) ? 32'd0 : {fpout[35],rund[32:2]}; |
|
endmodule |
/trunk/rtl/DECODER.v
0,0 → 1,1754
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: DECODER.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// DECODER Instruction Decoding and Flow Control |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module DECODER ( BCLK, BRESET, INT_N, NMI_N, ANZ_VAL, OPREG, CFG, PSR, ACC_DONE, DC_ABORT, IC_ABORT, |
PC_SAVE, STRING, INIT_DONE, ILL, UNDEF, TRAPS, IC_READ, STOP_CINV, |
GENSTAT, DISP, IMME_Q, DISP_BR, USED, NEW, LOAD_PC, NEXT_PCA, RDAA, RDAB, OPER, START, LD_OUT, |
INFO_AU, ACC_FELD, WREN, WRADR, WMASKE, WR_REG, DETOIP, MMU_UPDATE, RESTART, STOP_IC, RWVAL, EN |
|
input BCLK,BRESET; |
input INT_N,NMI_N; // external inputs |
input [2:0] ANZ_VAL; |
input [55:0] OPREG; // the OPREG contains the bytes to decode, OPREG[55:32] are don't care |
input [8:0] CFG; // CONFIG : many bits are don't-care |
input [11:0] PSR; |
input ACC_DONE; |
input DC_ABORT,IC_ABORT; |
input ACB_ZERO; |
input DONE; |
input [31:0] PC_SAVE; |
input [4:0] STRING; |
input INIT_DONE; |
input ILL,UNDEF; |
input [5:0] TRAPS; |
input IC_READ; |
input STOP_CINV; // not to mix it up with STOP_IC |
|
output [2:0] GENSTAT; |
output [31:0] DISP,IMME_Q,DISP_BR; // three main data busses : Displacement, Immediate and Displace |
output [2:0] USED; |
output NEW; |
output LOAD_PC; |
output NEXT_PCA; |
output [7:0] RDAA,RDAB; |
output [10:0] OPER; |
output [1:0] START,LD_OUT; |
output LD_DIN,LD_IMME; |
output [6:0] INFO_AU; |
output [14:0] ACC_FELD; |
output WREN; |
output [5:0] WRADR; |
output [1:0] WMASKE; |
output reg WR_REG; |
output [12:0] DETOIP; |
output [1:0] MMU_UPDATE; |
output RESTART; |
output STOP_IC; |
output [2:0] RWVAL; |
output ENA_HK; |
output reg ILO; |
output [23:0] COP_OP; |
|
reg [31:0] DISP,disp_val; |
reg [10:0] oper_i; |
reg [2:0] USED; |
reg [14:0] ACC_FELD; |
reg [1:0] ldoreg; |
reg wren_i; |
reg [5:0] wradr_i; |
reg [1:0] wmaske_i; |
reg [1:0] START; |
reg [23:0] COP_OP; |
reg spupd_i; |
reg [3:0] disp_sel; |
reg [52:0] op1_feld; |
reg [47:0] op2_feld; |
reg [47:0] op3_feld; |
reg [47:0] op_feld_reg; |
reg [31:0] imme_i; |
reg [2:0] valid; |
reg [7:0] phase_reg; |
reg [3:0] di_stat; // Displacement Status |
reg [3:0] cc_feld; |
reg [1:0] ex_br_op; |
reg acb_reg; |
reg jsr_flag; |
reg [8:0] waitop,wait_reg; |
reg branch; |
reg [3:0] dim_feld; |
reg [66:0] new_op; |
reg short_op_reg; |
reg [15:0] idx_reg; |
reg [35:0] gen_src1; |
reg [33:0] gen_src2; |
reg qw_flag; |
reg long_reg; |
reg new_spsel; |
reg s_user,old_su; |
reg [1:0] stack_sel; // Stack select for USER and SUPERVISOR |
reg [1:0] s_mod; // Modifier for Stack select |
reg upd_info,dw_info; |
reg [2:0] rpointer; |
reg [5:0] resto; // for RESTORE |
reg init_rlist; |
reg new_fp; |
reg format1; |
reg ldpc_phase; |
reg reti_flag; |
reg no_t2p; |
reg iabort,ia_save; |
reg mmu_sel; |
reg [1:0] nmi_reg; |
reg nmi_flag,int_flag; |
reg type_nmi; |
reg [3:0] exc_vector; |
reg phase_exc; |
reg [3:0] ovf_pipe; |
reg dbg_s,dbg_trap,dbg_en,addr_cmp; |
reg ssrc_flag,sdest_flag; |
reg op_setcfg,setcfg_lsb; |
reg inss_op; |
reg exin_cmd,extract; // EXT/INS |
reg bit_reg; // Flag for Bit opcodes : Source2 = Reg |
reg kurz_st; // Flag for MOVM/CMPM |
reg kill_opt; // Flag for optimized MOVS |
reg cmps_flag; // Flag for CMPS |
reg skps_flag; // Flag for SKPS |
reg mt_flag; // Flag for Match and Translate |
reg spu_block; // block of SP update at Long operation |
reg dia_op,dia_flag; // Flag for DIA |
reg m_ussu,m_usel,dc_user; // MOVUS/SU |
reg rwval_flag,wrval_flag; // RDVAL/WRVAL |
reg cinv_flag; // Flag for CINV |
reg [5:0] lmrreg; |
reg no_init,a_ivar; |
reg index_cmd; |
reg stop_d; |
reg dc_ilo; |
|
wire PHASE_0; |
wire [7:0] phase_ein; // Phase after ABORT has changed the content to 0 |
wire de_flag,ivec_flag; |
wire next; |
wire [18:0] new_addr,pop_fp,save_pc; |
wire [13:0] new_regs; |
wire [7:0] new_ph,ppfp; |
wire [7:0] new_nx; |
wire op_1byte,op_12byte,op_2byte,op_3byte; |
wire jump; |
wire short_op,short_def; |
wire acb_op,acb_flag; |
wire zero,carry_psr,negativ,larger,flag; |
wire valid_size; |
wire op_ok; |
wire stop; |
wire [47:0] opc_bits; |
wire [47:0] op_feld; |
wire [2:0] atys,atyd; |
wire [3:0] auop_s,auop_d; |
wire long,src2_flag,dest_flag; |
wire [6:0] src_1,src_2,src_1l,src_2l; |
wire [1:0] src1_le,src2_le; |
wire acc1,acc2; |
wire spupd; |
wire [6:0] saver; // for SAVE |
wire [2:0] reg_nr; |
wire save_reg; |
wire ld_disp,disp_ok; |
wire store_pc; |
wire do_xor; |
wire do_long; |
wire [1:0] idx_n,n_idx; |
wire idx; |
wire [1:0] otype; |
wire [10:0] opera,op_str,op_sho; |
wire [5:0] dest_r,dest_rl; |
wire phase_idx; |
wire [15:0] idx_bytes,idx_feld; |
wire [3:0] idx_1,idx_2; |
wire [4:0] src1_addr,src2_addr; |
wire [6:0] usp_1,usp_2; |
wire [33:0] tos_oper; |
wire [18:0] adrd1,exr11,exr12,adrd2,adwr2,exr22,exw22,re_wr,st_src,st_src2,st_dest,st_len,st_trde,s |
wire [7:0] phrd1,phrd2,phwr2; |
wire [6:0] rega1,irrw1,rega2,irrw2; |
wire [3:0] nxrd1,nxrw2; |
wire rmw; |
wire [6:0] quei1,quet1; // Registeradr |
wire [7:0] endea,goacb,dowait; // Phase |
wire [3:0] diacb; // DIMM access |
wire qword; |
wire [6:0] stack,no_modul,ttstak; |
wire [12:0] pop_1; |
wire mpoi_1,mpoi_2; |
wire [1:0] src1_tos; // the code for REUSE is 2'b11 |
wire svc_flag,bpt_flag,flag_flag,trac_flag; |
wire [3:0] misc_vectors; |
wire [2:0] psr_code; |
wire exception; |
wire interrupt; |
wire abort; // DC_ABORT | iabort; |
wire abo_int; |
wire iabo_fall; |
wire abbruch,fpu_trap,dvz_trap; |
wire abbruch2; |
wire dbg_flag; |
wire ovf_op,ovf2_op,ovf_flag; |
wire pc_match; |
wire no_trap; |
wire [10:0] op_psr,op_scp; |
wire [30:0] ai_next; |
wire set_src,set_dest,clr_sflag; |
wire [7:0] rrepa; // Repair Phase of Abort for String opcodes |
wire [7:0] ph_str; // working phase String |
wire ph_match; |
wire t2p; |
wire rw_bit,op_ilo; |
wire setcfg; |
wire string_ende; |
wire wlor; // Flag to generate WR_REG signal |
wire [5:0] wstr0,wstr1,wstr2; |
wire [6:0] rstr0,rstr1,rstr2; |
wire rett_exc; |
wire chk_rmw; |
|
// Variables for 2- and 3-Byte Dekoder : |
reg [5:0] hzr_c; // CASE Statement |
wire [1:0] hzl_a; |
wire [2:0] hzl_b; |
wire [5:0] hzr_a,hzr_b,hzr_s; |
wire hdx_a; |
wire hdo_b; |
wire [3:0] hdo_a,hdo_c,hdo_e; |
wire [7:0] hdo_d; |
wire [1:0] hdl_b,hdl_d,hdl_f,hdl_g,hdl_h; |
wire [2:0] hdl_a,hdl_c,hdl_e; |
wire [5:0] hdr_a,hdr_b,hdr_c,hdr_d,hdr_e,hdr_f,hdr_g,hdr_m; |
|
wire [66:0] state_0,state_group_50,state_group_60; // for the Gruppe 2 opcodes |
|
// Address field : Size:2 RD WR LDEA FULLACC INDEX:4 SPUPD disp_val:4 POST CLRMSW SRC2SEL:2 |
|
parameter addr_nop = 19'b10_0000_0000_0_0000_0000; // all parameter to 0 |
parameter push_op = 19'b10_0111_0000_1_1010_0000; // i.e. for BSR, ENTER ... |
parameter push_ea = 19'b10_0111_0000_1_1010_0011; // SAVE middle |
parameter pop_op = 19'b10_1011_0010_1_0000_1000; // RET/RESTORE |
parameter adddisp = 19'b10_0010_0000_0_0000_0011; // for RET : reuse of EA |
parameter adddispn = 19'b10_0010_0000_0_0000_0000; // for RETT : add Disp to Stack |
parameter save_sp = 19'b10_0000_0000_1_0000_0000; // u.a. RET : update of Stack |
parameter next_po = 19'b10_1011_0010_1_0000_1011; // RESTORE middle |
parameter dispmin = 19'b10_0010_0000_0_0100_0011; // Reuse for ENTER |
parameter rmod_rxp = 19'b10_1001_0000_1_0000_0100; // MODUL+0 read : SB , SP Update , therefore no |
parameter rmod_rtt = 19'b10_1001_0000_0_0000_0100; // MODUL+0 read : SB , no LDEA |
parameter rmod_4 = 19'b10_1011_0000_0_0001_0100; // MODUL+4 read : Link Table Base |
parameter rmod_8 = 19'b10_1011_0000_0_0010_0100; // MODUL+8 read : Program Base |
parameter rdltab = 19'b10_1010_0000_0_1000_0000; // Link table read - EA Phase |
parameter ea_push = 19'b10_0110_0000_0_1010_0011; // CXP : 2. Push EA Phase |
parameter ea_min8 = 19'b10_1010_0000_0_1011_0011; // CXP : reuse of MOD+8 |
parameter pop_ru = 19'b10_1010_0010_0_0000_1011; // RXP : EA Phase MOD POP |
parameter rd_icu = 19'b00_1001_0000_0_1100_0010; // Read ICU : Byte of fix address |
parameter get_vec = 19'b10_1001_0000_0_01xx_0000; // Read Exception-Vector : Index Exception No. |
parameter get_veci = 19'b10_1001_0110_0_0000_0000; // Read Exception-Vector : Index external Interr |
parameter load_ea = 19'b10_0010_0000_0_0000_0000; // used for store of TEAR and MSR |
parameter save_msr = 19'b10_0010_0001_0_0000_0000; // used for store of TEAR and MSR |
parameter ivar_adr = 19'b10_0000_0100_0_0000_0010; // only pass SRC1 |
parameter st_trans = 19'b00_1001_0100_0_0000_0000; // Translate at String : SRC1 + SRC2 , Byte |
parameter src_x = 7'hxx; |
parameter dest_x = 6'hxx; |
parameter imme = {1'b1,6'hxx}; |
parameter frame = 7'h18; |
parameter ibase = 7'h1E; |
parameter modul = 7'h1F; |
parameter w_msr = 6'h0A; |
parameter w_tear = 6'h0B; |
parameter fsr_r = 6'h17; // not defined register for FSR for opcodes LFSR and SFSR |
parameter temp_l = 6'h3C; |
parameter temp_h = 6'h3D; // second last space for 8B TEMP register |
parameter temp_1 = 6'h3E; // Backup for register at String operations |
parameter temp_2 = 6'h3F; |
parameter rtmpl = 7'h3C; |
parameter rtmph = 7'h3D; |
parameter rtmp1 = 7'h3E; |
parameter rtmp2 = 7'h3F; |
parameter op_mov = {3'bxxx,8'h45}; |
parameter op_adr = {3'bxxx,8'h49}; |
parameter op_add = 11'h340; // for CXP |
parameter op_flip = 11'h364; // for CXP : LSHD -16,Ri |
parameter op_lmr = 11'h36A; // for LPR CFG, LMR and CINV |
parameter op_wrp = 11'h387; // for CXP : write PSR , used also for Exception processing |
parameter op_ldp = 11'h388; // for RETT and RETI : load of PSR from Stack |
parameter op_zex = 11'h076; // Zero Extension for ICU Vector - is also used at String Option "T" |
parameter op_cop = 8'hDD; // Coprozessor Opcode |
|
// ++++++++++++++++++++++++++ The switch logic for the state machine ++++++++++++++++++++++++++++ |
|
always @(ANZ_VAL) |
case (ANZ_VAL) |
3'd0 : valid = 3'b000; |
3'd1 : valid = 3'b001; |
3'd2 : valid = 3'b011; |
default : valid = 3'b111; |
endcase |
|
assign next = ( PHASE_0 ? op_ok : // Opcode decoded or Exception processed |
// Displacement or Immediate operand and external memory access can happen in parallel |
// i.e. addressing mode Memory Relative |
( ((~dim_feld[0] | ACC_DONE) & (~dim_feld[3] | di_stat[0])) // ACC_DONE resets dim_feld |
// long operation |
& ~(long_reg & ~DONE) ) ) |
// hard break : abort or fpu_trap or dvz_trap or ovf_flag |
| abbruch ; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) long_reg <= 1'b0; |
else |
long_reg <= next ? do_long : long_reg; // START[1] |
|
always @(posedge BCLK or negedge BRESET) // the central phase register |
if (!BRESET) phase_reg <= 8'h0; |
else |
if (next) phase_reg <= new_op[47:40]; |
|
always @(*) // next switch of micro program counter |
casex ({PHASE_0,op_ok,dim_feld[3],di_stat[0]}) |
4'b11_xx : USED = {1'b0,~op_1byte,(op_1byte | op_3byte)}; |
4'b0x_11 : USED = di_stat[3:1]; |
default : USED = 3'd0; |
endcase |
|
// Special phases |
|
assign PHASE_0 = (phase_reg == 8'h00); // During Phase 0 the opcode is decoded |
|
assign NEXT_PCA = PHASE_0 & ~ovf_flag & ~dbg_flag; |
|
// Pulse to transfer from Trace Bit to Pending Trace Bit, only once in the beginning of phase 0 |
// The priority is such that a TRACE exception is served before an UNDEFINED/ILLEGAL exception |
always @(posedge BCLK) no_t2p <= PHASE_0 & ~op_ok; |
assign t2p = PHASE_0 & ~no_t2p; // signal to I_PFAD |
|
// ++++++++++++++++++++++++++ global control signals ++++++++++++++++ |
|
assign de_flag = CFG[8]; |
assign ivec_flag = CFG[0]; |
assign dvz_trap = TRAPS[1]; |
assign fpu_trap = TRAPS[0]; |
|
always @(posedge BCLK) nmi_reg <= {nmi_reg[0],NMI_N}; // one clock sync and than falling edge detec |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) nmi_flag <= 1'b0; |
else nmi_flag <= (nmi_reg == 2'b10) | (nmi_flag & ~(phase_reg == 8'h82)); |
|
always @(posedge BCLK) int_flag <= PSR[11] & ~INT_N; // one clock to synchronise |
|
assign stop = (int_flag | nmi_flag) & PHASE_0 & ~stop_d; // neccesary if FPU_TRAP and INT at t |
assign interrupt = (int_flag | nmi_flag) & (~PHASE_0 | stop_d); |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) stop_d <= 1'd0; |
else stop_d <= stop; |
|
// ++++++++++++++++++++++++++ Exception processing +++++++++++++++ |
|
// IC_ABORT is valid if Opcode Decoder cannot continue |
assign iabo_fall = IC_ABORT & (PHASE_0 ? ~op_ok : (~di_stat[0] & dim_feld[3])); |
|
always @(posedge BCLK) iabort <= iabo_fall & ~ia_save; // DC_ABORT ist a pulse |
always @(posedge BCLK) ia_save <= iabo_fall; |
|
// mmu_sel is used in ADDR_UNIT |
always @(posedge BCLK) mmu_sel <= DC_ABORT | (mmu_sel & ~iabort); // 1 = DCACHE , 0 = ICACHE |
assign MMU_UPDATE[0] = mmu_sel; |
|
assign abort = DC_ABORT | iabort; |
|
// that is the end of String loops where interrupts are checked : 8'hC7 & 8'hCF |
assign string_ende = (phase_reg[7:4] == 4'hC) & (phase_reg[2:0] == 3'b111); // attention : 8'hCF do |
|
always @(posedge BCLK) if (PHASE_0 || string_ende) type_nmi <= nmi_flag; // during processing kept |
|
assign svc_flag = (OPREG[7:0] == 8'hE2) & valid[0]; // Vector 5 : 0101 , Illegal Vector 4 : 0100 |
assign bpt_flag = (OPREG[7:0] == 8'hF2) & valid[0]; // Vector 8 : 1000 , Undefined Vec. 10 : 1010 |
assign flag_flag = (phase_reg == 8'h89) & flag; // Vector 7 - has an own state |
assign trac_flag = t2p & PSR[10]; // Vector 9 : 1001 , PSR[10] = P Bit , Pending Trace |
assign ovf_flag = (ovf_pipe[3] & flag) | (ovf_pipe[1] & TRAPS[2]); // Vector 13 : 1101 |
assign dbg_flag = dbg_trap | (dbg_s & PHASE_0); // Vector 14 : 1110 |
|
// abort + dvz_trap during a opcode, fpu_trap + ovf_flag + dbg_flag later |
assign abbruch = abort | fpu_trap | dvz_trap | ovf_flag | dbg_flag; // this 5 stop everything |
assign abbruch2 = abort | fpu_trap | dvz_trap | ovf_flag; // for exc_vector generation |
|
// forces the next step of state machine (op_ok), generates otype="11" for Trap Service |
assign exception = interrupt | svc_flag | bpt_flag | ILL | UNDEF | trac_flag | abbruch; |
|
// a TRACE Exception is done before the opcode execution |
assign misc_vectors = trac_flag ? 4'h9 : {(bpt_flag | UNDEF),(svc_flag | ILL),UNDEF,svc_flag}; // t |
|
always @(posedge BCLK) |
if (PHASE_0 || abbruch) // ABORTs, fpu_trap, dvz_trap + ovf_flag can happen every time |
begin |
exc_vector <= abbruch ? (abbruch2 ? {ovf_flag,(dvz_trap | ovf_flag),~ovf_flag,(fpu_trap | ovf_fl |
: (interrupt ? {3'b0,nmi_flag} : misc_vectors); // misc_vectors is default |
end |
else |
if (flag_flag) exc_vector <= 4'h7; // FLAG-Trap |
else |
if (interrupt && string_ende) exc_vector <= {3'b0,nmi_flag}; |
|
assign psr_code[2] = ~psr_code[1]; // Absicht : codiert das Sichern des PSR bei Exception-Entr |
assign psr_code[1] = abort | ILL | UNDEF | trac_flag; // enable for reseting the P-Bit during write |
assign psr_code[0] = (interrupt & ~fpu_trap) | abort; // enable for reseting the I-Bit of new PSR |
|
// valid codes are x'89 to x'8F |
assign op_psr = {8'b0_00_1000_1,psr_code}; // is used during first clock cylce after exception, is |
|
// Specialitiies : ABORT stores address & flags , the Interrrupts read vectors : all is used in big |
assign abo_int = (exc_vector == 4'h2) | (exc_vector[3:1] == 3'b000); |
assign ai_next = (exc_vector == 4'h2) ? {load_ea,8'h84,4'h0} : {rd_icu,8'h82,4'h1}; |
|
assign save_pc = {7'b10_0010_0,dia_flag,7'b00_0_0000,dia_flag,3'b001}; // Exception : PC_ARCHI => E |
assign no_trap = ~fpu_trap & ~ovf_flag & ~dbg_flag; // suppresion of WREN and LD_OUT[1] and ADDR_UN |
|
// ++++++++++++++++++++++++++ Overflow Trap ++++++++++++++ |
|
always @(posedge BCLK) |
if (ovf_flag || !PSR[4]) ovf_pipe <= 4'd0; |
else |
if (PHASE_0) ovf_pipe <= {ovf_pipe[2],(ovf_op & op_ok),ovf_pipe[0],(ovf2_op & op_ok)}; // V-Bit s |
|
assign ovf_op = ( ((OPREG[6:2] == 5'b000_11) // ADDQi |
| (OPREG[3:2] == 2'b00)) & (OPREG[1:0] != 2'b10)) // ADDi,ADDCi,SUBi,SUBCi |
| ((OPREG[7:0] == 8'h4E) & OPREG[13] & (OPREG[11:10] == 2'b00)) // NEGi,ABSi |
| ((OPREG[7:0] == 8'hEE) & ~OPREG[10]); // CHECKi |
|
assign ovf2_op = ((OPREG[6:2] == 5'b100_11) & (OPREG[1:0] != 2'b10)) // ACBi, these overflows have |
| ((OPREG[13:10] == 4'h1) & (OPREG[7:0] == 8'h4E)) // ASHi |
| ( OPREG[13] & (OPREG[11] == OPREG[10]) & (OPREG[7:0] == 8'hCE)); // MULi,DEIi,QUOi,DIVi |
|
// ++++++++++++++++++++++++++ Debug Trap ++++++++++++++ |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) dbg_s <= 1'b0; |
else dbg_s <= dbg_trap | (dbg_s & ~((exc_vector == 4'hE) & (phase_reg == 8'h81))); |
|
always @(posedge BCLK) dbg_en <= op_ok | ~PHASE_0; |
|
assign pc_match = dbg_en & TRAPS[3] & PHASE_0 & ~exception; // TRAPS[3] is only combinatorical |
|
always @(posedge BCLK) dbg_trap <= (pc_match | (addr_cmp & PHASE_0)) & TRAPS[5]; // TRAPS[5] = Enab |
|
always @(posedge BCLK) addr_cmp <= TRAPS[4] | (addr_cmp & ~PHASE_0); // TRAPS[4] = CAR HIT |
|
// ++++++++++++++++++++++++++ Special case String Abort ++++++++++++++ |
|
// Flags cleared if entry and exit of string operation and during Abort sequence, not valid for MO |
// special case UNTIL/WHILE : reset if exit (op_feld_reg[17] = 1 = UNTIL) |
assign clr_sflag = (phase_reg == 8'hC0) | (phase_reg == 8'hC7) | (phase_reg == 8'hC8) | (phase_ |
| (((phase_reg == 8'hD7) | (phase_reg == 8'hDF)) & ~(STRING[3] ^ op_feld_reg[17])) ; |
assign set_src = (phase_reg == 8'hC1) | (phase_reg == 8'hC9); |
assign set_dest = (phase_reg == 8'hC4) | (phase_reg == 8'hCC); |
|
always @(posedge BCLK or negedge BRESET) // R1 is modified |
if (!BRESET) ssrc_flag <= 1'b0; |
else ssrc_flag <= (set_src & ~kurz_st) | (ssrc_flag & ~clr_sflag); |
|
always @(posedge BCLK or negedge BRESET) // R2 is modified |
if (!BRESET) sdest_flag <= 1'b0; |
else sdest_flag <= (set_dest & ~kurz_st) | (sdest_flag & ~clr_sflag); |
|
assign rrepa = {7'b1000_011,~sdest_flag}; // R1 and if necessary R2 restore |
|
// ++++++++++++++++++++++++++ The one byte opcodes +++++++++++++++++++ |
|
// The one byte opcodes have a special case : one byte opcode but the second byte should be valid t |
// Used with SAVE, RESTORE, ENTER and EXIT with their reg list. |
// The advantage is that the reg list is store in op_feld_reg. |
|
// [52:34] addressing |
// [33:20] register |
// [19:18] 1 or 2 Byte opcode |
// [17:16] BSR/BR |
// [15:8] next phase |
// [7:4] START + LD_OUT |
// [3:0] operand access : Displacement or Speicher |
|
always @(*) // SVC (E2) and BPT (F2) decode as exception |
casex (OPREG[7:0]) |
8'hxA : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b01,8'h01,4'h0,4'hE}; // Bcc , DISP read |
8'h02 : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b10,8'h01,4'h0,4'hE}; // BSR , DISP read |
8'h12 : op1_feld = {pop_op , src_x, stack, 2'b01,2'b00,8'h2A,4'h0,4'h1}; // RET , DISP later |
8'h22 : op1_feld = {rmod_4 , src_x, modul, 2'b01,2'b00,8'h35,4'h0,4'h1}; // CXP |
8'h32 : op1_feld = {pop_op, src_x, stack, 2'b01,2'b00,8'h40,4'h0,4'h1}; // RXP |
8'h42 : op1_feld = {pop_op, src_x, stack, 2'b01,2'b00,8'h46,4'h0,4'h1}; // RETT |
8'h52 : op1_feld = {rd_icu, src_x, src_x, 2'b01,2'b00,8'h45,4'h0,4'h1}; // RETI |
8'h62 : op1_feld = {addr_nop, src_x, src_x, 2'b10,2'b00,8'h30,4'h0,4'h0}; // SAVE |
8'h72 : op1_feld = {addr_nop, src_x, src_x, 2'b10,2'b00,8'h32,4'h0,4'h0}; // RESTORE |
8'h82 : op1_feld = {push_op , frame, stack, 2'b10,2'b00,8'h2D,4'h2,4'h1}; // ENTER : PUSH FP |
8'h92 : op1_feld = {addr_nop, src_x, src_x, 2'b10,2'b00,8'h32,4'h0,4'h0}; // EXIT : POP FP |
8'hA2 : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b00,8'h00,4'h0,4'h0}; // NOP |
8'hB2 : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b00,8'h88,4'h0,4'h0}; // WAIT |
8'hC2 : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b00,8'h88,4'h0,4'h0}; // DIA |
8'hD2 : op1_feld = {addr_nop, src_x, src_x, 2'b01,2'b00,8'h89,4'h0,4'h0}; // FLAG |
default : op1_feld = {19'hxxxxx,14'hxxxx, 2'b00,2'b00,16'hxxxx}; |
endcase |
|
assign op_1byte = op1_feld[18] & valid[0]; |
assign op_12byte = op1_feld[19] & (valid[1:0] == 2'b11); |
|
assign new_addr = op1_feld[52:34]; |
assign new_regs = op1_feld[33:20]; |
assign new_ph = op1_feld[15:8]; |
assign new_nx = op1_feld[7:0]; // at Bcond DISP read |
|
assign pop_fp = new_fp ? pop_op : addr_nop; |
assign ppfp = new_fp ? 8'h34 : 8'h00; |
|
always @(posedge BCLK) |
if (PHASE_0) |
begin |
ex_br_op <= op1_feld[17:16]; // BSR/BR |
cc_feld <= OPREG[7:4]; |
new_fp <= (OPREG[7:6] == 2'b10); // not decoded complete but is sufficient |
reti_flag <= OPREG[4]; // only difference between RETI and RETT is important |
dia_op <= OPREG[6]; // only difference between DIA and WAIT is important |
end |
|
always @(posedge BCLK) dia_flag <= dia_op & (phase_reg == 8'h88); // special case DIA compared to W |
|
always @(posedge BCLK) // Format 1 opcodes write always DWord to reg, the same is true for Exceptio |
if (PHASE_0 || abbruch) format1 <= (valid[0] & (OPREG[3:0] == 4'h2)) | exception; |
else |
if (flag_flag || (interrupt && string_ende)) format1 <= 1'b1; |
|
// Branch etc. CXP CXPD |
assign store_pc = (phase_reg == 8'd1) | (phase_reg == 8'h37) | (phase_reg == 8'h6B); // only save i |
assign jump = (ex_br_op[0] & branch) | (acb_reg & ~ACB_ZERO) | ex_br_op[1]; |
|
always @(posedge BCLK) ldpc_phase <= (phase_reg == 8'h3E) // PC load at CXP/Traps , all one clock |
| (phase_reg == 8'h43) // PC load at RXP |
| ((phase_reg == 8'h49) & reti_flag) // PC load at RETI |
| (phase_reg == 8'h4E) // PC load at RETT |
| (phase_reg == 8'h66) // PC load at JUMP/JSR/CASE |
| (phase_reg == 8'h7B); // PC load at DE = Direct Exception |
|
assign NEW = ((phase_reg == 8'd1) & jump & di_stat[0]) | LOAD_PC; |
assign LOAD_PC = ((phase_reg == 8'h2B) & di_stat[0]) // only one pulse, but DISP must be ok => di_s |
| ldpc_phase; |
|
assign no_modul = de_flag ? {1'b0,dest_x} : {1'b1,modul[5:0]}; |
|
assign negativ = PSR[7]; |
assign zero = PSR[6]; |
assign flag = PSR[5]; |
assign larger = PSR[2]; |
assign carry_psr = PSR[0]; |
|
assign rett_exc = ~reti_flag & (phase_reg == 8'h4B); // special case RETT : Stack can change during |
always @(posedge BCLK) phase_exc <= (phase_reg == 8'h80); // 1. Exception phase |
always @(negedge BCLK) if (PHASE_0 || phase_exc || rett_exc) s_user <= PSR[9]; // Select Bit for St |
always @(negedge BCLK) |
if (PHASE_0 || phase_exc) s_mod <= {PSR[9],~PSR[9]}; |
else |
if (rett_exc) s_mod <= s_mod | {PSR[9],~PSR[9]}; // Both can be updated |
|
always @(cc_feld or zero or carry_psr or larger or negativ or flag) |
case (cc_feld) |
4'h0 : branch = zero; // EQual |
4'h1 : branch = ~zero; // Not Equal |
4'h2 : branch = carry_psr; // Carry Set |
4'h3 : branch = ~carry_psr; // Carry Clear |
4'h4 : branch = larger; // Higher |
4'h5 : branch = ~larger; // Lower or Same |
4'h6 : branch = negativ; // Greater Than |
4'h7 : branch = ~negativ; // Less or Equal |
4'h8 : branch = flag; // Flag Set |
4'h9 : branch = ~flag; // Flag Clear |
4'hA : branch = ~larger & ~zero; // LOwer |
4'hB : branch = larger | zero; // Higher or Same |
4'hC : branch = ~negativ & ~zero; // Less Than |
4'hD : branch = negativ | zero; // Greater or Equal |
4'hE : branch = 1'b1; // True |
4'hF : branch = 1'b0; // False |
endcase |
|
// +++++++++++++++++++++++ Register List Processing ++++++++++++++++++++++++++++ |
|
always @(posedge BCLK) init_rlist <= PHASE_0 | (phase_reg == 8'h2E); |
|
always @(posedge BCLK) |
if (PHASE_0) rpointer <= 3'b000; |
else |
if (ACC_DONE || init_rlist) rpointer <= reg_nr; |
|
REG_LIST scanner ( .DIN(op_feld_reg[22:15]), .INIT(init_rlist), .IPOS(rpointer), .VALID(save_reg), |
|
assign saver = {4'h0,reg_nr}; |
|
always @(posedge BCLK) if (ACC_DONE || init_rlist) resto <= {3'h0,~reg_nr}; // EXIT and RESTORE hav |
|
// ++++++++++++++++++++++++++ Processing of Displacement and Immediate Operand ++++++++++++++++++ |
|
always @(posedge BCLK or negedge BRESET) // Flag for DISP and IMME access |
if (!BRESET) dim_feld[3] <= 1'b0; |
else dim_feld[3] <= next ? new_op[3] : ~di_stat[0] & dim_feld[3]; |
|
always @(posedge BCLK) if (next) dim_feld[2:1] <= new_op[2:1]; |
|
always @(posedge BCLK or negedge BRESET) // Flag for external access |
if (!BRESET) dim_feld[0] <= 1'b0; |
else dim_feld[0] <= next ? new_op[0] : ~ACC_DONE & dim_feld[0]; |
|
// special case QWORD, last term for security |
always @(posedge BCLK) qw_flag <= dim_feld[0] & ACC_DONE & (ACC_FELD[13:12] == 2'b11) & ~qw_flag; |
|
assign LD_IMME = (dim_feld[3] & (dim_feld[2:1] != 2'b11)) | short_op | store_pc; // Data multiplexe |
assign LD_DIN = (di_stat[0] & dim_feld[3] & (dim_feld[2:1] != 2'b11)) // Enable for DIN Regist |
| (ACC_DONE & dim_feld[0]) | qw_flag | short_op | store_pc; // next not possible : i.e. imme |
assign ld_disp = (dim_feld[3:1] == 3'b111); // Enable for DISP Register |
|
// Signal to ADDR_UNIT , only Displacement critical |
assign disp_ok = ld_disp ? di_stat[0] : 1'b1; |
|
always @(dim_feld or OPREG or valid or ANZ_VAL) // Bit 0 is "Data ok", the upper 3 bits are for USE |
casex ({dim_feld[2:1],OPREG[7:6]}) |
4'b00_xx : di_stat = {3'b001,valid[0]}; |
4'b01_xx : di_stat = {3'b010,(valid[1] & valid[0])}; |
4'b10_xx : di_stat = {3'b100,ANZ_VAL[2]}; |
4'b11_0x : di_stat = {3'b001,valid[0]}; |
4'b11_10 : di_stat = {3'b010,(valid[1] & valid[0])}; |
4'b11_11 : di_stat = {3'b100,ANZ_VAL[2]}; |
endcase |
|
always @(OPREG) |
casex (OPREG[7:6]) |
2'b0x : disp_val = {{26{OPREG[6]}},OPREG[5:0]}; |
2'b10 : disp_val = {{19{OPREG[5]}},OPREG[4:0],OPREG[15:8]}; |
2'b11 : disp_val = {{3{OPREG[5]}},OPREG[4:0],OPREG[15:8],OPREG[23:16],OPREG[31:24]}; |
endcase |
|
assign DISP_BR = disp_val; // DISP is also used for Bcc opcode |
|
// The generator for DISP : data is used in ADDR_UNIT |
always @(*) |
casex ({ld_disp,disp_sel}) // disp_sel from new_op |
5'b1_00xx : DISP = disp_val; |
5'b1_01xx : DISP = 32'h0 - disp_val; // special case for ENTER |
5'b1_1xxx : DISP = {disp_val[29:0],2'b00}; // DISP*4 for External Address Mode |
5'b0_11xx : DISP = {20'hFFFFF,3'h7,type_nmi,8'h00}; // Interrupt Service Address |
5'b0_1000 : DISP = 32'hFFFF_FFFF; // PUSH Byte |
5'b0_1001 : DISP = 32'hFFFF_FFFE; // PUSH Word |
5'b0_1010 : DISP = 32'hFFFF_FFFC; // PUSH DWord |
5'b0_1011 : DISP = 32'hFFFF_FFF8; // PUSH QWord |
5'b0_01xx : DISP = {26'h0,exc_vector,2'b00}; // the exception vector as Offset for INTBASE |
5'b0_00xx : DISP = {28'h0,disp_sel[1:0],2'b00}; // 0,+4,+8,+12 used with MOD, default is 0 |
endcase |
|
always @(short_op or dim_feld or OPREG or op_setcfg or setcfg_lsb) |
casex ({short_op,dim_feld[2:1]}) |
3'b000 : imme_i = op_setcfg ? {28'h0000_00F,OPREG[2:0],setcfg_lsb} : {24'hxx_xxxx,OPREG[7:0]}; |
3'b001 : imme_i = {16'hxxxx,OPREG[7:0],OPREG[15:8]}; |
3'b01x : imme_i = {OPREG[7:0],OPREG[15:8],OPREG[23:16],OPREG[31:24]}; |
3'b1xx : imme_i = {{29{OPREG[10]}},OPREG[9:7]}; // for MOVQ etc. only OPREG can be used |
endcase |
|
assign IMME_Q = store_pc ? PC_SAVE : imme_i; |
|
// ++++++++++++++ Stack Control +++++++++++++++++ |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) new_spsel <= 1'b0; |
else new_spsel <= spupd | (new_spsel & ~PHASE_0 & ~fpu_trap & ~dvz_trap); |
|
always @(posedge BCLK) upd_info <= PHASE_0 & new_spsel; // one clock cycle earlier a change occurs, |
|
assign do_xor = fpu_trap ? upd_info : (PHASE_0 & new_spsel); |
|
always @(negedge BCLK or negedge BRESET) |
if (!BRESET) stack_sel <= 2'b00; |
else |
if (do_xor) stack_sel <= stack_sel ^ s_mod; |
|
// Special case RETT |
always @(posedge BCLK) if (!phase_reg[1]) old_su <= s_user; // is tested in state x'49 and used in |
assign ttstak = {1'b0,((old_su == PSR[9]) ^ stack_sel[PSR[9]]),3'b110,PSR[9],1'b1}; |
|
// ++++++++++++++ 2 byte opcodes +++++++++++++++++ |
|
// Hint : short_op is decoded separatly |
|
// [47:45] Source : [2] TOS=>(SP), [1] Ri => (Ri), [0] 1=access of memory |
// [44:42] Destination : like [47:45] |
// [41] long opcode [41:39] only for standard sequenz - not Gruppe 2 |
// [40] src2_flag - Source 2 is read |
// [39] dest_flag - a target operand exists |
// [38:33] src1_r Register field, no message about Immediate |
// [32:27] src2_r Register field |
// [26:25] src1_le Length of Source1 - this is used for qword |
// [24:23] src2_le Length of Source2 : 00=1/01=2/10=4/11=8 Bytes => WMASKE |
// [22:18] src1 field |
// [17:13] src2 field |
// [12:11] op_type 2 Bit for sort of opcode |
// [10] FL : F=1/L=0 |
// [9:8] original BWD : B=00/W=01/D=11 |
// [7:0] opcode: operation code |
|
assign valid_size = (OPREG[1:0] != 2'b10) & (valid[1:0] == 2'b11); // valid size + valid OPREG-Byte |
|
assign hzl_a = (OPREG[1:0] == 2'b11) ? 2'b10 : OPREG[1:0]; // length field recoded |
assign hzl_b = {1'b0,OPREG[1:0]}; // standard Length field |
assign hzr_a = {3'b000,OPREG[13:11]}; // SRC2 or SRC1 regfield |
assign hzr_b = {3'b000,OPREG[8:6]}; // SRC2 regfield |
assign hzr_s = {((OPREG[15:11] == 5'h17) ^ stack_sel[s_user]),3'b110,s_user,1'b1}; // USER or SUPER |
// Special case LPR & SPR regfield: |
always @(OPREG or stack_sel or s_user) |
casex ({OPREG[10:7]}) |
4'b1001 : hzr_c = {stack_sel[s_user],3'b110,s_user,1'b1}; // USER or SUPERVISOR Stack |
4'b1011 : hzr_c = {stack_sel[1] ,3'b110,1'b1, 1'b1}; // USER Stack |
4'b1100 : hzr_c = OPREG[6] ? temp_h : 6'h1C; // CFG special case : LPR : SPR |
default : hzr_c = {2'b01,OPREG[10:7]}; |
endcase |
|
// Unfortunately SETCFG must be implemented : it is transformed to a two byte opcode with one byte |
assign setcfg = (OPREG[13:0] == 14'h0B0E) & (valid[1:0] == 2'b11); |
|
always @(*) |
casex ({setcfg,OPREG[10:2]}) |
// Short-Op Codes , ACB is an ADD with following jump |
10'b0xxxx_x0011 : op2_feld = {6'o11,3'o3,6'hxx,hzr_a,hzl_a,hzl_a,5'h14,OPREG[15:11],2'b00,hzl_b,8' |
10'b0xxxx_00111 : op2_feld = {6'o11,3'o2,6'hxx,hzr_a,hzl_a,hzl_a,5'h14,OPREG[15:11],2'b00,hzl_b,8' |
10'b0xxxx_01011 : op2_feld = {6'o11,3'o1,hzr_c,hzr_a,hzl_a,hzl_a,5'h00,OPREG[15:11],2'b00,hzl_b,8' |
// Scond is moving the SHORT operand in the Integer area as condition field |
10'b0xxxx_01111 : op2_feld = {6'o11,3'o1,6'hxx,hzr_a,hzl_a,hzl_a,5'h14,OPREG[15:11],2'b00,hzl_b,8' |
10'b0xxxx_10111 : op2_feld = {6'o11,3'o1,6'hxx,hzr_a,hzl_a,hzl_a,5'h14,OPREG[15:11],2'b00,hzl_b,8' |
10'b0xxxx_11011 : op2_feld = {6'o11,3'o1,hzr_a,hzr_c,hzl_a,2'b10,OPREG[15:11],5'h00,2'b00,hzl_b,8' |
// Format 3 opcodes : |
10'b00x10_11111 : op2_feld = {6'o11,3'o1,hzr_a,6'h1D,hzl_a,hzl_a,OPREG[15:11],5'h00,2'b00,hzl_b,4' |
10'b0x100_11111 : op2_feld = {6'o61,3'o1,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:11],5'h00,2'b10,hzl_b,4' |
10'b01110_11111 : op2_feld = {6'o11,3'o1,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:11],5'h00,2'b10,hzl_b,4' |
// Format 4 opcodes : main group |
10'b0xxxx_xxxx0 : op2_feld = {6'o11,3'o3,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:6], 2'b00,hzl_b,4'h4,OP |
10'b0xxxx_x0001 : op2_feld = {6'o11,3'o2,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:6], 2'b00,hzl_b,4'h4,OP |
10'b0xxxx_x0101 : op2_feld = {6'o11,3'o1,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:6], 2'b00,hzl_b,4'h4,OP |
10'b0xxxx_x1101 : op2_feld = (OPREG[10:9] == 2'b00) ? // target is Register => standard flow |
{6'o11,3'o2,hzr_a,hzr_b,hzl_a,2'bxx,OPREG[15:6], 2'b00,hzl_b,4'h4,OPREG[5:2]} // TBIT |
: {6'o14,3'o2,hzr_a,hzr_b,hzl_a,2'b00,OPREG[15:6], 2'b10,hzl_b,4'h4,OPREG[5:2]}; |
// ADJSPi |
10'b01010_11111 : op2_feld = {6'o11,3'o3,hzr_a,hzr_s,hzl_a,2'b10,OPREG[15:11],5'h00,2'b00,hzl_b,8' |
// ADDR, length field not valid |
10'b0xxxx_x1001 : op2_feld = {6'o61,3'o1,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:6], 2'b00,hzl_b,8'h49}; |
10'b00000_11111 : op2_feld = {6'o71,3'o1,hzr_a,hzr_b,hzl_a,hzl_a,OPREG[15:11],5'h00,2'b10,hzl_b,4' |
// SETCFG => MOV Befehl , SRC1 is genrated for 32 bit , target is Register temp_h |
10'b1xxxx_xxxxx : op2_feld = {40'b001001_001_000000_111101_00_10_10100_00000_00_011, 8'h76}; |
default : op2_feld = {40'hxx_xxxx_xxxx,4'hA,4'hx}; |
endcase |
|
assign op_2byte = (valid_size | setcfg) & ~op2_feld[7]; // it must be for sure shown "Invalid Opcod |
|
// Special case : the quick opcodes with the exception SPR and LPR |
assign short_op = ((~OPREG[5]) | (OPREG[6:4] == 3'b011)) & (OPREG[3:2] == 2'b11) & valid_size & PHA |
always @(posedge BCLK) if (PHASE_0) short_op_reg <= short_op; |
assign short_def = PHASE_0 ? short_op : short_op_reg; // for the big state machine |
assign op_sho = (OPREG[6:4] == 3'b011) ? 11'h07A : op_mov; // Special case Scond at Index as Dest. |
|
// 2. special case ACB |
assign acb_op = (OPREG[6:2] == 5'h13) & valid_size; |
always @(posedge BCLK) if (PHASE_0) acb_reg <= acb_op; |
assign acb_flag = PHASE_0 ? acb_op : acb_reg; |
assign goacb = acb_flag ? 8'h28 : 8'h00; // x'28 = 40 , wait jump at REG operation - short-op speci |
|
// 3. special case load of PSR and Init-Done opcodes : because of U bit in PSR a restart must follo |
// CINV and LMR PTB must wait until Init-Done and than Restart. |
// All variants of LPR and BIC/S have an extra cycle due to TRACE operation |
always @(OPREG) |
casex (OPREG[18:0]) |
19'bxxx_xxxxx_1101_110_11_xx : waitop = 9'h14C; // LPRi PSR,... |
19'bxxx_xxxxx_1100_110_11_xx : waitop = 9'h174; // LPRi CFG,... |
19'bxxx_xxxxx_0x10_111_11_xx : waitop = 9'h14C; // BICPSRi/BISPSRi ... |
19'bxxxx_x_0010_xx_0000_1110 : waitop = 9'h174; // SETCFG [] |
19'bxxxx_0_0010_xx_0001_1110 : waitop = 9'h174; // LMR - at the end Restart |
19'bxxxx_0_1001_xx_0001_1110 : waitop = 9'h174; // CINV - at the end Restart |
default : waitop = 9'h000; |
endcase |
|
assign dowait = waitop[7:0]; // is used in Phase 0 if PSR is loaded from Register |
always @(posedge BCLK) if (PHASE_0) wait_reg <= waitop; |
|
// Here 2. and 3. special case are coming together: |
// Phase definition, end over jump for ACB , not used in Phase 0 |
assign endea = acb_reg ? 8'h01 : (wait_reg[8] ? wait_reg[7:0] : 8'h00); |
assign diacb = acb_reg ? 4'hE : 4'h0; // load Disp ? |
|
// special case ADJSPi : SP=SRC2 always 32 Bit |
always @(posedge BCLK) |
if (PHASE_0) dw_info <= (OPREG[10:2] == 9'b1010_11111); |
else dw_info <= dw_info & ~phase_reg[7]; // for security at ABORT |
|
// SETCFG : Flag to transform the Byte Immeadiate operand |
always @(posedge BCLK) if (PHASE_0) op_setcfg <= setcfg; |
always @(posedge BCLK) if (PHASE_0) setcfg_lsb <= OPREG[15]; |
|
always @(posedge BCLK) if (PHASE_0) jsr_flag <= (OPREG[10:2] == 9'b1100_11111); // JSR : for PUSH |
always @(posedge BCLK) // Bit opcodes to Register and EXT:SRC1 / INS:SRC2 |
if (PHASE_0) bit_reg <= ((OPREG[3] ? ((OPREG[7:6] == 2'd0) ? OPREG[23:22] : OPREG[18:17]) : OPREG |
always @(posedge BCLK) if (PHASE_0) exin_cmd <= (~OPREG[10] & (OPREG[6:0] == 7'h2E)) & (valid[2:0] |
always @(posedge BCLK) if (PHASE_0) extract <= ~OPREG[7]; |
always @(posedge BCLK) if (PHASE_0) inss_op <= (OPREG[13:10] == 4'h2) & (OPREG[7:0] == 8'hCE) & (va |
|
// ++++++++++++++ 3 byte opcodes +++++++++++++++++ |
|
// [47:45] Source : [2] TOS=>(SP), [1] Ri => (Ri), [0] 1=access of memory |
// [44:42] Destination : like [47:45] |
// [41] long opcode [41:39] only for standard sequenz - not Gruppe 2 |
// [40] src2_flag - Source 2 is read |
// [39] dest_flag - a target operand exists |
// [38:33] src1_r Register field, no message about Immediate |
// [32:27] src2_r Register field |
// [26:25] src1_le Length of Source1 - this is used for qword |
// [24:23] src2_le Length of Source2 : 00=1/01=2/10=4/11=8 Bytes => WMASKE |
// [22:18] src1 field |
// [17:13] src2 field |
// [12:11] op_type 2 Bit for sort of opcode |
// [10] FL : F=1/L=0 |
// [9:8] original BWD : B=00/W=01/D=11 |
// [7:0] opcode: operation code |
|
assign hdx_a = OPREG[7] ? OPREG[8] : OPREG[10]; |
assign hdo_a = OPREG[13:10]; |
assign hdo_b = ~hdx_a; // long operation if L |
assign hdo_c = {1'b0,OPREG[10],OPREG[7:6]}; // Format 8 opcodes |
assign hdo_d = {6'b0101_00,OPREG[10],1'b0}; // CMPM/S or MOVM/S : 8'h52 or 8'h50 |
assign hdo_e = {3'b011,OPREG[10]}; // Special codes for LOGB and SCALB due to DP_OUT datapath |
// Definitions of length |
assign hdl_a = {1'b0,OPREG[9:8]}; // i size, is used in OPER |
assign hdl_b = (OPREG[9:8] == 2'b11) ? 2'b10 : OPREG[9:8]; // recode length field, is used in ACC f |
assign hdl_c = OPREG[10:8]; // FL + BWD |
assign hdl_d = {1'b1,~hdx_a}; // length FP |
assign hdl_e = {OPREG[8],2'bxx}; // BWD don't care |
assign hdl_f = (OPREG[18:17] == 2'b00) ? OPREG[9:8] : {OPREG[8],~(OPREG[9] ^ OPREG[8])}; // exclusi |
assign hdl_g = {(OPREG[9:8] != 2'b00),(OPREG[9:8] == 2'b00)}; // exclusiv for EXT/EXTS base operand |
assign hdl_h = {(OPREG[9:8] != 2'b00),(OPREG[9:8] != 2'b01)}; // exclusiv for CHECK bound operand |
// Register definitions |
assign hdr_a = {3'b000,OPREG[21:19]}; // SRC1 Integer Register |
assign hdr_b = {3'b000,OPREG[16:14]}; // SRC2 Integer Register |
assign hdr_c = hdx_a ? {2'b10,OPREG[21:20],1'b0,OPREG[19]} : {2'b10,OPREG[21:19],1'b1}; |
assign hdr_d = hdx_a ? {2'b10,OPREG[16:15],1'b0,OPREG[14]} : {2'b10,OPREG[16:14],1'b1}; |
assign hdr_e = OPREG[11] ? {2'b10,OPREG[21:20],1'b0,OPREG[19]} : {2'b10,OPREG[21:19],1'b1}; |
assign hdr_f = OPREG[11] ? {2'b10,OPREG[16:14],1'b1} : {2'b10,OPREG[16:15],1'b0,OPREG[14]}; |
assign hdr_g = {3'b000,OPREG[16:15],1'b1}; // exclusiv for DEI |
assign hdr_m = {3'b001,OPREG[17:15]}; // MMU Register Index 8-15 |
|
always @(*) |
casex (OPREG[13:3]) |
11'b1000_xx_1100x : op3_feld = {6'o11,3'o3,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'b000x_xx_0100x : op3_feld = {6'o11,3'o3,hdr_a,hdr_b, 2'b00,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'b0101_xx_0100x : op3_feld = {6'o11,3'o3,hdr_a,hdr_b, 2'b00,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'b1x0x_xx_0100x : op3_feld = {6'o11,3'o1,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'b010x_xx_1100x : op3_feld = {6'o11,3'o1,hdr_a,hdr_b, hdl_b,2'b01,OPREG[23:14],2'b00,hdl_a,4'h |
11'b011x_xx_1100x : op3_feld = {6'o11,3'o1,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b00,hdl_a,4'h |
11'b0001_xx_0110x : op3_feld = {6'o11,3'o3,hdr_a,hdr_b, hdl_b,2'b00,OPREG[23:14],2'b00,hdl_a,4'h |
// Floating Point opcodes |
11'b000x_xx_0011x : op3_feld = {6'o11,hdo_b,2'b01,hdr_a,hdr_d, hdl_b,hdl_d,OPREG[23:14],2'b00,hd |
11'b010x_xx_0011x : op3_feld = {6'o11, 3'o5,hdr_e,hdr_f, 2'b11,2'b10,OPREG[23:14],2'b00,hd |
11'b011x_xx_0011x : op3_feld = {6'o11, 3'o5,hdr_e,hdr_f, 2'b10,2'b11,OPREG[23:14],2'b00,hd |
11'b10xx_xx_0011x : op3_feld = {6'o11,hdo_b,2'b01,hdr_c,hdr_b, hdl_d,hdl_b,OPREG[23:14],2'b00,hd |
11'b111x_xx_00111 : op3_feld = {6'o11,hdo_b,2'b01,hdr_c,hdr_b, hdl_d,hdl_b,OPREG[23:14],2'b00,hd |
11'b111x_xx_00110 : op3_feld = {6'o11, 3'o5,hdr_c,hdr_b, hdl_d,hdl_b,OPREG[23:14],2'b00,hd |
11'b0x00_0x_10111 : op3_feld = {6'o11,hdo_b,2'b11,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'bxx00_0x_10110 : op3_feld = {6'o11, 3'o7,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'b1000_0x_10111 : op3_feld = {6'o11, 3'o7,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'b1100_0x_10111 : op3_feld = {6'o11,hdo_b,2'b11,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'b0010_0x_1011x : op3_feld = {6'o11,hdo_b,2'b10,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'b0001_0x_10111 : op3_feld = {6'o11, 3'o1,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'bx101_0x_10111 : op3_feld = {6'o11, 3'o1,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
11'b001x_11_00111 : op3_feld = {6'o11,3'o1,hdr_a,fsr_r, 2'b10,2'b10,OPREG[23:19],5'b0,2'b00,3'o3 |
11'b110x_11_00111 : op3_feld = {6'o11,3'o1,fsr_r,hdr_b, 2'b10,2'b10,5'b0,OPREG[18:14],2'b00,3'o3 |
// MMU opcodes |
11'b0010_11_0001x : op3_feld = {6'o11,3'o1,hdr_a,temp_h,2'b10,2'b10,OPREG[23:19],5'b0,2'b00, 3'o |
11'b0011_11_0001x : op3_feld = {6'o11,3'o1,hdr_m,hdr_a, 2'b10,2'b10,5'b0,OPREG[23:19],2'b00, 3'o |
// String opcodes |
11'b000x_xx_0000x : op3_feld = {6'o11,3'o0,6'hxx,6'hxx, 2'bxx,2'b10,OPREG[23:14], 2'b10,hdl_ |
11'b0011_xx_0000x : op3_feld = {6'o11,3'o0,6'hxx,6'hxx, 2'bxx,2'b10,OPREG[23:14], 2'b10,hdl_ |
// Custom opcodes |
11'bxx01_0x_10110 : op3_feld = {6'o11, 3'o5,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hd |
// Integer Divisionen : QUOi REMi DIVi MODi and DEIi + MEIi |
11'b11xx_xx_1100x : op3_feld = {6'o11,3'o7,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'b10x1_xx_1100x : op3_feld = {6'o11,3'o7,hdr_a,hdr_g, hdl_b,hdl_f,OPREG[23:14],2'b10,hdl_a,4'h |
// Gruppe 2 opcodes |
11'b0x11_xx_1010x : op3_feld = {6'o77,3'o1,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b00,hdl_a,8'h |
11'b000x_xx_1100x : op3_feld = {6'o66,3'o0,hdr_a,hdr_b, 2'bxx,2'b10,OPREG[23:14],2'b10,hdl_c, hd |
11'b001x_0x_1111x : op3_feld = {6'o11,3'o0,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b10,hdl_e,4'h |
11'b0101_0x_1111x : op3_feld = {6'o11,3'o5,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b00,hdl_e,4'h |
11'b0100_0x_1111x : op3_feld = {6'o11,3'o0,hdr_c,hdr_d, hdl_d,hdl_d,OPREG[23:14],2'b10,hdl_e,4'h |
11'b0011_xx_1100x : op3_feld = {6'o50,3'o0,hdr_a,hdr_b, hdl_g,hdl_b,OPREG[23:14],2'b10,hdl_c,4'h |
11'bxxx0_xx_1110x : op3_feld = {6'o71,3'o0,hdr_a,hdr_b, hdl_h,hdl_b,OPREG[23:14],2'b10,hdl_c,4'h |
11'b0x1x_xx_0100x : op3_feld = (OPREG[18:17] == 2'b00) ? // target is register => standard flow |
{6'o11,3'o3,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b00,hdl_a,4'h6,hdo_a} // SBIT/CBIT |
: {6'o14,3'o3,hdr_a,hdr_b, hdl_b,2'b00,OPREG[23:14],2'b10,hdl_a,4'h6,hdo_a}; |
11'b1110_xx_0100x : op3_feld = (OPREG[18:17] == 2'b00) ? // target is register => standard flow |
{6'o11,3'o3,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b00,hdl_a,4'h6,hdo_a} // IBIT |
: {6'o14,3'o3,hdr_a,hdr_b, hdl_b,2'b00,OPREG[23:14],2'b10,hdl_a,4'h6,hdo_a}; |
11'b1x11_xx_0100x : op3_feld = {6'o11,3'o7,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b00,hdl_a,4'h |
11'bxxx0_xx_0010x : op3_feld = {6'o40,3'o0,hdr_a,hdr_b, hdl_g,hdl_b,OPREG[23:14],2'b10,hdl_c,4'h |
11'bxxx0_xx_1010x : op3_feld = {6'o14,3'o0,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b10, 3'o3,4'h |
11'b0010_xx_1100x : op3_feld = {6'o14,3'o0,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b10, 3'o3,4'h |
11'bxxx0_xx_0110x : op3_feld = {6'o61,3'o0,hdr_a,hdr_b, hdl_b,2'b10,OPREG[23:14],2'b10, 3'o3,4'h |
11'bxxx1_xx_0010x : op3_feld = {6'o11,3'o0,hdr_a,hdr_b, hdl_b,hdl_b,OPREG[23:14],2'b10, 3'o3,8'h |
// Gruppe 2 opcodes can have dedicated operation codes. Therefore the operation code definition her |
11'b000x_xx_0001x : op3_feld = {6'o70,3'o0,hdr_a,hdr_b, 2'b00,2'b10,OPREG[23:19],5'b0,2'b10,3'o0 |
11'b1001_11_0001x : op3_feld = {6'o11,3'o1,hdr_a,temp_h,2'b10,2'b10,OPREG[23:19],5'b0,2'b00,3'o3 |
|
default : op3_feld = {40'hxx_xxxx_xxxx,4'hA,4'hx}; |
endcase |
|
assign op_3byte = (valid[2:0] == 3'b111) & (OPREG[2:0] == 3'b110) & (op3_feld[7:4] != 4'hA); // val |
|
// +++++++++++++ Evaluation for 2 and 3 byte opcodes ++++++++++++++++++ |
|
// for one byte opcodes special treatmant neccessary |
assign opc_bits = op_3byte ? op3_feld : op2_feld; |
|
assign op_ok = (op_1byte | op_12byte | op_2byte | op_3byte | exception) & ~stop; // used for comput |
|
always @(posedge BCLK) if (PHASE_0) op_feld_reg <= opc_bits; |
assign op_feld = PHASE_0 ? opc_bits : op_feld_reg; // constant for all following cycles |
|
// Evaluation of op_feld : |
|
assign atys = op_feld[47:45]; // [2] : TOS=>(SP), [1] : Ri => (Ri), [0] : 1=access of memory |
assign atyd = op_feld[44:42]; // [2] : TOS=>(SP), [1] : Ri => (Ri), [0] : 1=access of memory |
assign long = op_feld[41]; |
assign src2_flag = op_feld[40]; |
assign dest_flag = op_feld[39]; |
|
assign src_1 = {1'b0,op_feld[38:33]}; |
assign src_2 = {1'b0,op_feld[32:27]}; |
assign src1_le = op_feld[26:25]; |
assign src2_le = op_feld[24:23]; |
assign acc1 = (op_feld[22:21] != 2'b00) | atys[1]; // external access Source1 or "addr" : Reg => ( |
assign acc2 = (op_feld[17:16] != 2'b00) | atyd[1]; // external access Source2 or "addr" : Reg => ( |
assign wlor = dest_flag & ~acc2; |
assign idx_n = {1'b0,(op_feld[22:20] == 3'b111)} + {1'b0,(op_feld[17:15] == 3'b111)}; // Index : 0 |
assign idx = (idx_n != 2'b00); // Index is active |
assign n_idx = idx_n - 2'b01; |
|
// The field otype is used only in Phase 0 |
assign otype = exception ? 2'b11 : ((op_1byte | op_12byte) ? 2'b01 : opc_bits[12:11]); // string op |
|
assign opera = op_feld[10:0]; |
|
assign dest_r = src_2[5:0]; |
assign dest_rl = {dest_r[5:1],1'b0}; |
|
// +++++++++++++++++++++++++ Coprocessor operations field ++++++++++++++++++++++++++++++ |
|
always @(posedge BCLK) if (PHASE_0) COP_OP <= OPREG[23:0]; |
|
// +++++++++++++++++++++++++ Special signals for LMR and CINV ++++++++++++++++++++++++++ |
// op_lmr is constant = parameter |
|
assign STOP_IC = (phase_reg == 8'h74) | (phase_reg == 8'h75); |
|
// CINV uses Register x'30 - x'37 : CINV = 110... , LMR = 001... otherwise CFG |
always @(posedge BCLK) if (PHASE_0) lmrreg <= op_3byte ? {{2{OPREG[13]}},~OPREG[13],OPREG[17:15]} : |
|
always @(posedge BCLK) no_init <= (lmrreg[5:4] == 2'b00) & (lmrreg[3:1] != 3'b110); // LMR waits fo |
// a_ivar = "Addresse IVAR0/1" |
always @(posedge BCLK) a_ivar <= STOP_IC; // Phase 74 & 75, is used at INFO_AU together with IC_RE |
|
// CINV detection for IC_CACHE |
always @(posedge BCLK) |
if (PHASE_0) cinv_flag <= OPREG[13] & (OPREG[7:0] == 8'h1E); |
else cinv_flag <= cinv_flag & ~phase_reg[7]; // reset at exception |
|
assign ENA_HK = ~(cinv_flag & STOP_IC); // always "1", if CINV then "0" |
|
// +++++++++++++++++++++++++ USER flag for MOVUS & MOVSU ++++++++++++++++++++++++ |
|
always @(posedge BCLK) |
if (PHASE_0) m_ussu <= (~OPREG[13] & (OPREG[11:10] == 2'b11) & (OPREG[7:0] == 8'hAE)); |
else m_ussu <= m_ussu & ~phase_reg[7]; // reset at exception |
|
always @(posedge BCLK) if (PHASE_0) m_usel <= OPREG[12]; |
|
// +++++++++++++++++++++++++ USER flag for RDVAL & WRVAL ++++++++++++++++++++++++ |
|
always @(posedge BCLK) |
if (PHASE_0) rwval_flag <= (OPREG[13:11] == 3'd0) & (OPREG[7:0] == 8'h1E); |
else rwval_flag <= rwval_flag & ~phase_reg[7]; // reset at exception |
|
always @(posedge BCLK) if (PHASE_0) wrval_flag <= OPREG[10]; // Difference RDVAL=0 and WRVAL=1 |
|
// +++++++++++++++++++++++++ Flags for CBIT/I+SBIT/I+IBIT +++++++++++++++++++++++ |
|
assign rw_bit = (op_feld_reg[7:4] == 4'd6) & ((~op_feld_reg[3] & op_feld_reg[1]) | (op_feld_reg[3:0 |
assign op_ilo = rw_bit & op_feld_reg[0]; // Interlocked : CBITI and SBITI |
|
// +++++++++++++++++++++++++++++ Operations for String processing +++++++++++++++++ |
// Address field : Size:2 RD WR LDEA FULLACC INDEX:4 SPUPD disp_val:4 POST CLRMSW SRC2SEL:2 |
|
assign st_src = {STRING[1:0],5'b1010_0,(op_feld_reg[15] & ~kurz_st),STRING[1:0],9'b0_0000_1000}; / |
assign st_src2 = {STRING[1:0],5'b1010_0,(op_feld_reg[15] & ~kurz_st),STRING[1:0],9'b0_0000_1011}; / |
assign st_dest = {STRING[1:0],5'b0110_0,(op_feld_reg[15] & ~kurz_st),STRING[1:0],9'b0_0000_1011}; / |
assign st_trde = {2'b00, 5'b0110_0, op_feld_reg[15], 2'b00, 9'b0_0000_1000}; / |
assign st_trs2 = {STRING[1:0],5'b1010_0, op_feld_reg[15], STRING[1:0],9'b0_0000_1000}; / |
assign st_len = {STRING[1:0],17'b0000_0000_0_0000_0000}; // length important for qw_flag |
|
// Signals of DETOIP go to I_PFAD |
always @(posedge BCLK) if (PHASE_0) kill_opt <= ~OPREG[7] & (OPREG[17:15] != 3'b000); // watch diff |
assign ph_match = (phase_reg[7:4] == 4'hD) & (phase_reg[2:0] == 3'd7); // Phase D7 and DF |
|
assign op_str = {op_feld_reg[10:8],6'b0101_00,op_feld_reg[1],1'b1}; // Opcode 8'h51 or 8'h53; |
assign op_scp = {op_feld_reg[10:8],8'h41}; // normal CMPi |
assign ph_str = {4'hC,op_feld_reg[1],3'b001}; // Phase 8'hC1 (MOVS/M) or 8'hC9 (CMPS/M) |
|
always @(posedge BCLK) kurz_st <= (phase_reg == 8'h65) | (kurz_st & ~PHASE_0); // Flag for MOVM/C |
always @(posedge BCLK) if (PHASE_0) cmps_flag <= ~OPREG[7] & (OPREG[11:10] == 2'b01); // Flag for C |
always @(posedge BCLK) if (PHASE_0) skps_flag <= ~OPREG[7] & (OPREG[11:10] == 2'b11); // Flag for S |
always @(posedge BCLK) if (PHASE_0) mt_flag <= ~OPREG[7] & (OPREG[17] | OPREG[15]); // Flag for Ma |
|
assign wstr0 = {{4{kurz_st}},2'b00}; |
assign wstr1 = {{4{kurz_st}},2'b01}; |
assign wstr2 = {{4{kurz_st}},2'b10}; |
assign rstr0 = {1'b0,wstr0}; |
assign rstr1 = {1'b0,wstr1}; |
assign rstr2 = {1'b0,wstr2}; |
|
// +++++++++++++++++++++++++++++++++++ Index processing +++++++++++++++++++++++++++++++++++++++++ |
|
assign phase_idx = (phase_reg == 8'h02) | (phase_reg == 8'h50); |
|
assign idx_bytes = idx_1[2] ? OPREG[15:0] : {OPREG[7:0],OPREG[7:0]}; // here last access of OPREG |
always @(posedge BCLK) if (phase_idx) idx_reg <= idx_bytes; |
assign idx_feld = (phase_idx) ? idx_bytes : idx_reg; |
|
// +++++++++++++++++++++++++++++++++++ The big state machine ++++++++++++++++++++++++++++++++++++ |
|
// Hints : |
// 1. At short-op SRC1 is out of memory to use TEMP |
// 2. At SRC2 rmw suppresed TOS and changed it to (SP) |
// 3. The Long-operation path takes the dest_r address to write if WR_REG activ |
// 4. It is ok, that an extra cycle for the read of the index registers is needed - then data could |
|
// Source 1 |
|
assign idx_1 = {1'b0,(op_feld[22:20] == 3'b111),op_feld[19:18]}; |
assign src1_addr = idx_1[2] ? idx_feld[7:3] : op_feld[22:18]; |
assign stack = {1'b0,stack_sel[s_user],3'b110,s_user,1'b1}; |
assign usp_1 = src1_addr[0] ? stack : {5'b0_0110,src1_addr[1:0]}; |
assign src_1l = {src_1[6:1],1'b0}; |
assign pop_1 = {2'b00,src1_le,9'h108}; // SP update, DISP=0 and POST |
assign mpoi_1 = (src1_addr[4:2] == 3'b100) | (src1_addr == 5'h16); // Pointer in memory always DWor |
assign auop_s = atys[0] ? 4'b1011 : 4'b0010; // Only make effective address ? |
assign src1_tos = (op_feld[22:18] == 5'h17) ? 2'b11 : 2'b00; // Source 1 is true TOS |
|
// Nextfield : 11=DISP read |
// Address field : Size:2 RD WR LDEA FULLACC INDEX:4 SPUPD disp_val:4 POST CLRMSW SRC2SEL:2 |
always @(*) |
casex (src1_addr) // RWLF IDX ADDR_F NEUP SRC_REG NEXT |
// Special case which is only valid at INDEX or "addr" : REG -> ADDR , DISP=0 : starts immediate |
5'b00xxx : gen_src1 = {auop_s, idx_1,9'h000,8'h07,4'h0,src1_addr[2:0],3'b000,atys[0]}; |
// Register relativ : 0(R0) |
5'b01xxx : gen_src1 = {auop_s, idx_1,9'h000,8'h07,4'h0,src1_addr[2:0],3'b111,atys[0]}; |
// Memory relativ : 0(0(SB)) |
5'b100xx : gen_src1 = {4'b1011,4'h0, 9'h000,8'h06,usp_1, 4'b1111}; // 1. access always ful |
// Immediate |
5'b10100 : gen_src1 = (src1_le == 2'b11) ? |
{4'h0, 4'h0, 9'h000,8'h0B,src_x, 1'b1,2'b10,1'b0} // load in DWord pieces |
: {4'h0, 4'h0, 9'h000,8'h07,src_x, 1'b1,src1_le,1'b0}; |
5'b10101 : gen_src1 = {auop_s, idx_1,9'h002,8'h07,src_x, 3'b111,atys[0]}; // Absolut Address |
5'b10110 : gen_src1 = {4'b1011,4'h0, 9'h014,8'h05,7'h1F, 4'b0001}; // External with MOD Re |
5'b10111 : gen_src1 = (idx_1[2] | atys[2]) ? // Access class "addr" ? |
{auop_s, idx_1,9'h000,8'h07,stack, 3'b000,atys[0]} // 0(SP) : no TOS flag |
: {4'b1011,pop_1, 8'h07,stack, 4'b0001}; // TOS |
// Memory Space : 0(SB) |
5'b110x0 : gen_src1 = {auop_s, idx_1,9'h000,8'h07,5'b0_0110,src1_addr[1:0],3'b111,atys[0]}; // S |
5'b11001 : gen_src1 = {auop_s, idx_1,9'h000,8'h07,stack, 3'b111,atys[0]}; // SP |
5'b11011 : gen_src1 = {auop_s, idx_1,9'h001,8'h07,src_x, 3'b111,atys[0]}; // PC relativ |
default : gen_src1 = 36'hx_xxxx_xxxx; // don't care |
endcase |
|
assign adrd1 = {(mpoi_1 ? 2'b10 : src1_le),gen_src1[35:19]}; // Addressfield : 19 Bits |
assign phrd1 = gen_src1[18:11]; // next phase |
assign rega1 = gen_src1[10:4]; // Source 1 Register |
assign irrw1 = {4'b0,idx_feld[2:0]}; // Index-Register |
assign nxrd1 = gen_src1[3:0]; // Memory/Disp/Immediate operation |
assign exr11 = {2'b10 ,4'b1011,4'h0 ,9'h080}; // 2. access external with Mem.-Pointer + 4* Disp |
assign exr12 = {src1_le,auop_s,idx_1,9'h000}; // for Memory Relative and EXT in last step |
|
// Source 2 resp. Destination |
|
assign rmw = src2_flag & dest_flag; |
assign idx_2 = {1'b0,(op_feld[17:15] == 3'b111),op_feld[14:13]}; // 4 bits |
assign src2_addr = idx_2[2] ? idx_feld[15:11] : op_feld[17:13]; |
assign usp_2 = src2_addr[0] ? stack : {5'b0_0110,src2_addr[1:0]}; |
assign src_2l = {src_2[6:1],1'b0}; |
assign mpoi_2 = (src2_addr[4:2] == 3'b100) | (src2_addr == 5'h16); // Pointer in memory always DWor |
assign auop_d = atyd[0] ? 4'b1011 : 4'b0010; // Only make effective address ? |
|
// The next assessment processes TOS separated for PUSH and POP |
assign tos_oper = src2_flag ? |
{2'b00,atyd[0],2'b01,atyd[0],2'b00,src2_le,7'b1_0000_10, src1_tos,4'h7,stack,3'b0,atyd[0]} |
: {1'b0,atyd[0],3'b001,atyd[0],4'h0, 1'b1,2'b10,src2_le,2'b0,src1_tos,4'h7,stack,3'b0,aty |
|
// Nextfield : 11=DISP read |
// Address field : Size:2 RD WR LDEA FULLACC INDEX:4 SPUPD disp_val:4 POST CLRMSW SRC2SEL:2 |
always @(*) |
casex (src2_addr) // RW:W RW:R LF IDX ADDR_F NEUP SRC_REG NEXT |
// Special case which is only valid at INDEX or "addr" : REG -> ADDR , DISP=0 : starts immediate |
5'b00xxx : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h000,4'h7,4'h0,src2_addr[2:0],3'b000,aty |
// Register relativ : 0(R0) |
5'b01xxx : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h000,4'h7,4'h0,src2_addr[2:0],3'b111,aty |
// Memory relativ : 0(0(SB)) |
5'b100xx : gen_src2 = {2'b10,2'b10,2'b11,4'h0, 9'h000,4'h6,usp_2, 4'b1111}; // 1. access always |
// Immediate |
5'b10100 : gen_src2 = (src2_le == 2'b11) ? |
{2'b00,2'b00,2'b00,4'h0, 9'h000,4'hB,src_x, 1'b1,2'b10,1'b0} // load in DWord pieces |
: {2'b00,2'b00,2'b00,4'h0, 9'h000,4'h7,src_x, 1'b1,src2_le,1'b0}; |
5'b10101 : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h002,4'h7,src_x, 3'b111,atyd[0]}; // Ab |
5'b10110 : gen_src2 = {2'b10,2'b10,2'b11,4'h0, 9'h014,4'h5,7'h1F, 4'b0001}; // External with MO |
5'b10111 : gen_src2 = (idx_2[2] | rmw | atyd[2]) ? |
{1'b0,atyd[0],auop_d, idx_2,7'b0_0000_00,src1_tos,4'h7,stack, 3'b000,atyd[0]} // 0(SP) : TOS |
: tos_oper; // TOS : 2 cases for PUSH and POP |
// Memory Space |
5'b110x0 : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h000,4'h7,5'b0_0110,src2_addr[1:0],3'b11 |
5'b11001 : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h000,4'h7,stack, 3'b111,atyd[0]}; |
5'b11011 : gen_src2 = {1'b0,atyd[0],auop_d, idx_2,9'h001,4'h7,src_x, 3'b111,atyd[0]}; // PC |
default : gen_src2 = 34'hx_xxxx_xxxx; // don't care |
endcase |
|
assign adrd2 = {(mpoi_2 ? 2'b10 : src2_le),gen_src2[31:15]}; |
assign adwr2 = {(mpoi_2 ? 2'b10 : src2_le),gen_src2[33:32],gen_src2[29:15]}; |
assign phrd2 = {4'h1,gen_src2[14:11]}; // Phase for Read Source 2 |
assign phwr2 = {4'h2,gen_src2[14:11]}; // Phase for Write Destination |
assign rega2 = gen_src2[10:4]; |
assign nxrw2 = gen_src2[3:0]; |
assign irrw2 = {4'b0,idx_feld[10:8]}; |
assign re_wr = {src2_le,4'b0101,4'h0, 9'h003}; // REUSE Address : Write of rmw |
assign exr22 = {src2_le,atyd[0],1'b0,1'b1,atyd[0],idx_2,9'h000}; // for Memory Relative and EXT in |
assign exw22 = {src2_le,1'b0,atyd[0],1'b1,atyd[0],idx_2,9'h000}; // for Memory Relative and EXT in |
|
// Special case : |
|
assign quei1 = acc1 ? imme : src_1l; // 8B passing either from register or from extern |
// 8B is requested from both operands but only to certain times |
assign qword = (phase_reg[7:4] != 4'h0) ? (src2_le == 2'b11) : (src1_le == 2'b11); |
assign quet1 = acc1 ? temp_h : src_1; // select source during calculation |
|
// Output data of state machine |
// LOAD if PULS if simple |
// NEXT -> ENABLE ENABLE out |
// [66:48] 19 ADDR : X ; Op-length REUSE RD/WR etc. |
// [47:40] 8 new phase X |
// [39:33] 7 SRC1 X |
// [32:26] 7 SRC2 X |
// [25] 1 WREN X |
// [24:19] 6 DEST X |
// [18:8] 11 OPER X |
// [7:6] 2 START X |
// [5:4] 2 LD_OUT X |
// [3] 1 ID Load X |
// [2:1] 2 ID Type X ; 0 = DISP |
// [0] 1 MEM Access X |
|
// State acc2-src2_flag-dest_flag |
// no SRC2 x 0 x |
// SRC2=REG 0 1 0 ; CMP+TBIT |
// SRC2=REG 0 1 1 ; all else |
// SRC2=MEM 1 1 0 ; CMP+TBIT |
// SRC2=MEM 1 1 1 ; all else |
|
// Input data for state machine |
|
// 8 phase_reg : phase of state machine |
// 2 otype : Opcode type |
|
// 1 idx : Index is available : 1 or 2 , only PHASE_0 |
// 1 short_op : short opcodes like ADDQ |
// 1 long : "long" opcode |
// 1 qword : 8B access at Source (Exception DEI+MEI) |
|
// 1 acc1 : Reg/Extern SRC1 |
// 1 acc2 : Reg/Extern SRC2 |
// 1 src2_flag : the 2. operand is being read |
// 1 dest_flag : there is a target operand : only CMP and TBIT have none |
|
assign phase_ein = abbruch ? 8'h00 : phase_reg; |
|
always @(*) // "_" "_" |
casex ({phase_ein,otype, idx,short_def,long,qword, acc1,acc2,src2_flag,dest_flag}) |
{8'h00,10'b00_1xxx_xxxx}: // Index must be loaded : phase 2 : in any case load TEMP for Short-Op an |
new_op = short_op ? // START LD_OUT |
{addr_nop,8'h02, imme, src_x, 1'b1,temp_h, op_sho, 2'b00,2'b10, 1'b1,n_idx,1'b0} |
: {addr_nop,8'h02, src_1,src_1l,1'b0,dest_x, opera, 2'b00,~src2_flag,2'b1_1,n_idx,1'b0}; |
{8'h00,10'b00_01xx_x0xx}: // Short-Op to register, LD_OUT because of CMPQ |
new_op = {addr_nop,goacb, imme, src_2,dest_flag,dest_r, opera, 2'b00,2'b10, 4'h0}; |
{8'h00,10'b00_01xx_x11x}: // Short-Op : external operand read : SRC2 ! Data in TEMP ! Here no Index |
new_op = {adrd2, phrd2, imme, rega2, 1'b1,temp_h, op_mov, 2'b00,2'b00, nxrw2}; |
{8'h00,10'b00_01xx_x10x}: // MOVQ to Mem |
new_op = {adwr2, phwr2, imme, rega2, 1'b0,dest_x, opera, 2'b00,2'b10, nxrw2}; |
{8'h00,10'b00_0000_00xx}: // simple register operation : dest_flag controls WREN, LD_OUT for CMP |
new_op = {addr_nop,dowait,src_1,src_2, dest_flag,dest_r,opera, 2'b00,2'b10, 4'h0}; |
{8'h00,10'b00_0001_00xx}: // "simple" Reg-Op of 8B, phase 8 after 2. DWord , not via LONG-path |
new_op = {addr_nop,8'h08, src_1,src_x, 1'b1,dest_r, opera, 2'b00,2'b00, 4'h0}; |
{8'h00,10'b00_0010_00xx}: // long register operation i.e. DIV - phase 31 |
new_op = {addr_nop,8'h1F, src_1,src_2, wlor,dest_r, opera, 2'b11,2'b00, 4'h0}; |
{8'h00,10'b00_0011_001x}: // long register operation with QWORD - phase 26 then wait |
new_op = {addr_nop,8'h1A, src_1,src_2, 1'b0,dest_r, opera, 2'b01,2'b00, 4'h0}; |
{8'h00,10'b00_00xx_1xxx}: // Source 1 in memory - first to read , here no Index |
new_op = {adrd1, phrd1, src_x,rega1, 1'b0,dest_x, opera, 2'b00,2'b00, nxrd1}; |
{8'h00,10'b00_00xx_011x}: // Source 2 in memory - first to read (Source 1 in register) |
new_op = {adrd2, phrd2, src_x,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
{8'h00,10'b00_0000_0101}: // Source 1 store in Dest : "pass through" for MOV,NEG,ABS |
new_op = {adwr2, phwr2, src_1,rega2, 1'b0,dest_x, opera, 2'b00,2'b10, nxrw2}; |
{8'h00,10'b00_0001_0101}: // Source 1 store in Dest : "pass through" for MOV,NEG,ABS for Long opera |
new_op = //(op_feld[17:13] == 5'h17) ? // TOS : special case , first 8B out of Reg and then r |
{addr_nop,8'h1C, src_1,src_1l,1'b0,dest_x, opera, 2'b00,2'b11, 4'h0}; |
{8'h00,10'b00_0010_0101}: // SRC1 -> DEST with short operands |
new_op = {addr_nop,8'h1F, src_1,src_x, 1'b0,dest_r, opera, 2'b11,2'b00, 4'h0}; |
{8'h00,10'b00_0011_0x01}: // SRC1 -> DEST i.e. ROUNDLi |
new_op = {addr_nop,8'h1F, src_1,src_1l,wlor,dest_r, opera, 2'b11,2'b00, 4'h0}; |
|
// Phase 2 : after read of Index nearly everything is repeated from PHASE_0 |
{8'h02,10'bxx_x1xx_x11x}: // Short-Op : external operand read |
new_op = {adrd2, phrd2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
{8'h02,10'bxx_x1xx_x101}: // MOVQ to Mem, data is in Out-Register |
new_op = {adwr2, phwr2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
{8'h02,10'bxx_x0xx_1xxx}: // Source 1 in memory - first to read |
new_op = {adrd1, phrd1, irrw1,rega1, 1'b0,dest_x, opera, 2'b00,2'b00, nxrd1}; |
{8'h02,10'bxx_x0xx_011x}: // Source 2 in memory - first to read |
new_op = {adrd2, phrd2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
{8'h02,10'bxx_x00x_0101}: // Source 1 store in Dest : "pass through" , data is already in Out-Regis |
new_op = {adwr2, phwr2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
{8'h02,10'bxx_x010_0101}: // SRC1 -> DEST with short operands |
new_op = {addr_nop,8'h1F, src_1,src_x, 1'b0,dest_x, opera, 2'b11,2'b00, 4'h0}; |
{8'h02,10'bxx_x011_0101}: // SRC1 -> DEST i.e. ROUNDLi |
new_op = {addr_nop,8'h1F, src_1,src_1l,1'b0,dest_x, opera, 2'b11,2'b00, 4'h0}; |
|
// +++++++++++++++++ SRC1 operand loading +++++++++++++++++++ |
|
// Phase 5 : wait for data and Disp2 for External addressing : part 2 EA = (MOD+4)+4*DISP1 |
// next phase fix : 6 |
{8'h05,10'bxx_xxxx_xxxx}: new_op = {exr11, 8'h06, src_x,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
// Phase 6 : Memory-Pointer for Memory Relative and last access External |
// next phase fix : 7 , add Index |
{8'h06,10'bxx_xxxx_xxxx}: new_op = {exr12, 8'h07, irrw1,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
|
// Phase 7 : wait for final data , direct from PHASE_0 if TOS without Index |
// next phase : if 8B data phase 8 is neccessary |
// if SRC2=REG execution started (otherwise store data in TEMP) and PHASE_0 |
{8'h07,10'bxx_xx00_x0xx}: // into Register , short operation execution , but LD_OUT for PSR Update |
new_op = {addr_nop,endea, imme, src_2, dest_flag,dest_r,opera, 2'b00,2'b10, diacb}; |
{8'h07,10'bxx_xx01_x0xx}: // into Reg but with a step om between for ABSL etc. : phase 8 |
new_op = {addr_nop,8'h08, imme, src_x, 1'b1,dest_r, opera, 2'b00,2'b00, 4'h0}; |
{8'h07,10'bxx_xx10_x0xx}: // execute long operation , wait in phase 31 |
new_op = {addr_nop,8'h1F, imme, src_2, wlor,dest_r, opera, 2'b11,2'b00, 4'h0}; |
{8'h07,10'bxx_xx11_xx0x}: // execute long operation : 2. operand only Dest , load LSD , phase 24 , |
new_op = {addr_nop,8'h18, imme, src_x, 1'b1,temp_l, op_mov, 2'b01,2'b00, 4'h0}; |
{8'h07,10'bxx_xx11_x01x}: // lange Operation ausfuehren , LSD laden , phase 25 , warten in phase 31 |
new_op = {addr_nop,8'h19, imme, src_2, 1'b0,dest_r, opera, 2'b01,2'b00, 4'h0}; |
{8'h07,10'bxx_xxx0_x11x}: // Data into TEMP , read 2. operand , is there Index ? Yes -> phase 15 |
new_op = idx_2[2] ? |
{addr_nop,8'h0F, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, 4'h0} |
: {adrd2, phrd2, imme, rega2, 1'b1,temp_h, op_mov, 2'b00,2'b00, nxrw2}; |
{8'h07,10'bxx_xxx1_x11x}: // 8B data in TEMP , step in between then 2. Op read : phase 10 - can onl |
new_op = {addr_nop,8'h0A, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, 4'h0}; |
{8'h07,10'bxx_xx00_x101}: // something like ABSi , execute and store (LD_OUT) |
new_op = idx_2[2] ? |
{addr_nop,8'h10, imme, src_x, 1'b0,dest_x, opera, 2'b00,2'b10, 4'h0} |
: {adwr2, phwr2, imme, rega2, 1'b0,dest_x, opera, 2'b00,2'b10, nxrw2}; |
{8'h07,10'bxx_xx01_x101}: // ABS etc. : LSD data over SRC2 in 2. OUT-Reg , MSD data see opcode ABS/ |
new_op = {addr_nop,8'h09, imme, src_x, 1'b0,dest_x, opera, 2'b00,2'b10, 4'h0}; |
{8'h07,10'bxx_xx10_x101}: // opcodes like MOVFL |
new_op = {addr_nop,8'h1F, imme, src_x, 1'b0,dest_x, opera, 2'b11,2'b00, 4'h0}; |
|
// Phase 8 : 2. part of 64 bit data : can be reached from PHASE_0 if 8B data |
{8'h08,10'bxx_xxxx_xxxx}: new_op = {addr_nop,endea, quei1,src_x, 1'b1,dest_rl, op_mov, 2'b00,2'b00, |
// Phase 9 : step in between to get data in OUT-Reg Low , SRC1 is not possible |
{8'h09,10'bxx_xxxx_xxxx}: // afterwards to data write |
new_op = {addr_nop,8'h10, src_x,imme , 1'b0,dest_x, op_mov, 2'b00,2'b01, 4'h0}; |
// Phase 10 : LSD data write in TEMP , source can be IMME data to |
{8'h0A,10'bxx_xxxx_xxxx}: // 8B , after TEMP there can only be a 2. operand |
new_op = idx_2[2] ? |
{addr_nop,8'h0F, imme, src_x, 1'b1,temp_l, op_mov, 2'b00,2'b00, 4'h0} |
: {adrd2, phrd2, imme, rega2, 1'b1,temp_l, op_mov, 2'b00,2'b00, nxrw2}; |
|
// Phase 11 : wait for 8B IMME data : switch over at address decoder , qword flag is for sure "1" |
{8'h0B,10'bxx_xx0x_x0xx}: // into Reg with step in between for ABSL etc. : phase 12 |
new_op = {addr_nop,8'h0C, imme, src_x, 1'b1,dest_r, opera, 2'b00,2'b00, 4'b1100}; |
{8'h0B,10'bxx_xx1x_x01x}: // execute long operation , load LSD , phase 25 , wait in phase 31 |
new_op = {addr_nop,8'h19, imme, src_2, 1'b0,dest_r, opera, 2'b01,2'b00, 4'b1100}; |
{8'h0B,10'bxx_xxxx_x11x}: // 8B data into TEMP , step in between then read 2. Op : phase 10 - can o |
new_op = {addr_nop,8'h0A, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, 4'b1100}; |
{8'h0B,10'bxx_xx0x_x10x}: // ABS etc. : LSD data via SRC2 into 2. OUT-Reg , MSD data see opcode ABS |
new_op = {addr_nop,8'h09, imme, src_x, 1'b0,dest_x, opera, 2'b00,2'b10, 4'b1100}; |
{8'h0B,10'bxx_xx1x_xx0x}: // MOVLF with 8B IMME data ? Must be possible, the end in phase 24 like S |
new_op = {addr_nop,8'h18, imme, src_x, 1'b1,temp_l, op_mov, 2'b01,2'b00, 4'b1100}; |
// Phase 12 : wait for 2. part of 64 bit IMME data : after phase 0 |
{8'h0C,10'bxx_xxxx_xxxx}: new_op = {addr_nop,endea, imme ,src_x, 1'b1,dest_rl, op_mov, 2'b00,2'b00, |
|
// Phase 15 : secure in TEMP with Index continue and read 2. operand |
{8'h0F,10'bxx_xxxx_xxxx}: new_op = {adrd2, phrd2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, |
// Phase 16 : after LD_OUT continue with Index and store 1. operand |
{8'h10,10'bxx_xxxx_xxxx}: new_op = {adwr2, phwr2, irrw2,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, |
|
// +++++++++++++++++ SRC2 operand loading : phase SRC1 + 16 +++++++++++++++++++ |
|
// Phase 21 : wait for data and Disp2 for external addressing : part 2 EA = (MOD+4)+4*DISP1 |
// next phase fix : 22 |
{8'h15,10'bxx_xxxx_xxxx}: new_op = {exr11, 8'h16, src_x,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
// Phase 22 : Memory-Pointer for Memory Relative and last access external |
// next phase fix : 23 , add Index |
{8'h16,10'bxx_xxxx_xxxx}: new_op = {exr22, 8'h17, irrw2,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
|
// Phase 23 : wait for final data , direct from PHASE_0 if TOS without Index |
// next phase : if 8B data phase 24 is used |
{8'h17,10'bxx_xx0x_xxx1}: // execute short operation and write data into memory , no WREN -> phase |
new_op = {re_wr, 8'h27, quet1,imme , 1'b0,dest_r, opera, 2'b00,2'b10, 4'b0001}; |
{8'h17,10'bxx_xx0x_xxx0}: // execute short operation , no WREN -> phase 0 , CMP(+TBIT) |
new_op = {addr_nop,endea, quet1,imme , 1'b0,dest_r, opera, 2'b00,2'b10, diacb}; |
{8'h17,10'bxx_xx10_xxxx}: // execute long operation , wait in phase 31 |
new_op = {addr_nop,8'h1F, quet1,imme , wlor,dest_r, opera, 2'b11,2'b00, 4'h0}; |
{8'h17,10'bxx_xx11_xxxx}: // execute long operation , load LSD in phase 24 |
new_op = {addr_nop,8'h18, quet1,imme , 1'b0,dest_r, opera, 2'b01,2'b00, 4'h0}; |
// Phase 24 : load 2. part of 64 bit data : with and without wait - from 28 the phase waits , from |
{8'h18,10'bxx_xxxx_0xxx}: // execute long operation , wait in phase 31 |
new_op = {addr_nop,8'h1F, src_1l,imme, wlor,dest_r, opera, 2'b10,2'b00, 4'h0}; |
{8'h18,10'bxx_xxxx_1xxx}: // execute long operation , wait in phase 31 , data from TEMP, used also |
new_op = {addr_nop,8'h1F, rtmpl,imme, wlor,dest_r, opera, 2'b10,2'b00, 4'h0}; |
// Phase 25 : load 2. part of 64 bit data : SRC1 from memory and SRC2 from Reg |
{8'h19,10'bxx_xxxx_xxxx}: // execute long operation , wait in phase 31 |
new_op = {addr_nop,8'h1F, imme, src_2l,wlor,dest_r, opera, 2'b10,2'b00, 4'h0}; |
// Phase 26 : load 2. part of 64 bit data : SRC1 from Reg and SRC2 from Reg |
{8'h1A,10'bxx_xxxx_xxxx}: // execute long operation , wait in phase 31 |
new_op = {addr_nop,8'h1F, src_1l,src_2l,wlor,dest_r, opera, 2'b10,2'b00, 4'h0}; |
|
// Phase 27 : wait for 8B IMME data : switch over at address decoder , qword flag is for sure "1" |
{8'h1B,10'bxx_xxxx_xxxx}: // execute long operation , load LSD in phase 24 |
new_op = {addr_nop,8'h18, quet1,imme , 1'b0,dest_r, opera, 2'b01,2'b00, 4'b1100}; |
|
// +++++++++++++++++ special case ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// Phase 28 : TOS with 8B SRC1 operand , no Index ! Jump to phase 39 |
{8'h1C,10'bxx_xxxx_xxxx}: // store Source 1 in Dest : "pass through" for MOV,NEG,ABS |
new_op = {adwr2, phwr2, src_x,rega2, 1'b0,dest_x, opera, 2'b00,2'b00, nxrw2}; |
// +++++++++++++++++ close operation : write out DEST , TOS update +++++++++++++++++++ |
|
// Phase 31 : wait for DONE of long operation |
{8'h1F,10'bxx_xxxx_xxx0}: // CMP done -> phase 0 |
new_op = {addr_nop,8'h00, src_x,src_x, 1'b0,dest_r, opera, 2'b00,2'b10, 4'h0}; // no ACB |
{8'h1F,10'bxx_xxxx_x0x1}: // operation closed , data into register |
new_op = {addr_nop,8'h00, src_x,src_x, 1'b0,dest_r, opera, 2'b00,2'b00, 4'h0}; // no ACB |
{8'h1F,10'bxx_xxxx_x101}: // operation closed , data into memory - first calculate address phase 32 |
new_op = {adwr2, phwr2, irrw2,rega2, 1'b0,dest_r, opera, 2'b00,2'b00, nxrw2}; |
{8'h1F,10'bxx_xxxx_x111}: // operation closed , data into memory - address reuse phase 39 ACC_DONE |
new_op = {re_wr, 8'h27, src_x,src_x, 1'b0,dest_r, opera, 2'b00,2'b00, 4'b0001}; |
|
// Destination address calculate |
// Phase 37 : wait for data and Disp2 for External addressing : part 2 EA = (MOD+4)+4*DISP1 |
// next phase fix : 38 |
{8'h25,10'bxx_xxxx_xxxx}: new_op = {exr11, 8'h26, src_x,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
// Phase 38 : Memory-Pointer for Memory Relative and letzter Zugriff External |
// next phase fix : 39 , add Index and write |
{8'h26,10'bxx_xxxx_xxxx}: new_op = {exw22, 8'h27, irrw2,imme , 1'b0,dest_x, opera, 2'b00,2'b00, |
|
// Phase 39 : wait for ACC_DONE : consequent numbering : 7+32 |
{8'h27,10'bxx_xxxx_xxxx}: // now operation closed , only ACB could follow |
new_op = {addr_nop,endea, src_x,src_x, 1'b0,dest_x, opera, 2'b00,2'b00, diacb}; |
|
// +++++++++++++++ special case : ACB to Reg is to fast ! One wait cycle for ZERO-Flag |
{8'h28,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h01,src_x, src_x, 1'b0,dest_x, opera, 2'b00,2'b00, |
|
// +++++++++++++++ The other opcodes are following ++++++++++++++++++ |
|
{8'h00,10'b01_xxxx_xxxx}: new_op = {new_addr,new_ph,new_regs, 1'b0,dest_x, op_mov, new_nx}; |
|
// Phase 1 : used for Bcond and ACB : |
{8'h01,10'bxx_xxxx_xxxx}: new_op = (ex_br_op[1] | jsr_flag) ? // BSR or JSR ? |
{push_op, 8'h27, imme, stack, 1'b0,dest_x, op_mov, 2'b00,2'b10, 4'b0001} // wait at end |
: {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0}; |
|
// Phase 42 : RET : read of PC from Stack and DIN via SRC1 to PC |
{8'h2A,10'bxx_xxxx_xxxx}: new_op = {adddisp, 8'h2B, imme, src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00 |
// Phase 43 : RET : Displacement add to Stack. Attention : "imme" important to keep source constan |
{8'h2B,10'bxx_xxxx_xxxx}: new_op = {save_sp, 8'h2C, imme, src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00 |
// Phase 44 : RET : Update of Stack : fixed phase |
{8'h2C,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
|
// Phase 45 : ENTER Entry |
{8'h2D,10'bxx_xxxx_xxxx}: new_op = {dispmin, 8'h2E, src_x,src_x, 1'b1,temp_l, op_adr, 2'b00,2'b00, |
// Phase 46 : ENTER Stack longer |
{8'h2E,10'bxx_xxxx_xxxx}: new_op = {save_sp ,8'h31, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 48 : SAVE/ENTER : Init phase , phases 48 & 49 very similar |
{8'h30,10'bxx_xxxx_xxxx}: new_op = save_reg ? |
{push_op, 8'h31, saver,stack, 1'b0,dest_x, op_mov, 2'b00,2'b10, 4'h1} // 1. load SP=>EA |
: {addr_nop,8'h00, rtmpl,src_x,new_fp,frame[5:0],op_mov, 2'b00,2'b00, 4'h0}; // At ENTER |
// Phase 49 : SAVE/ENTER : at the same time memory access and detection of next Reg |
{8'h31,10'bxx_xxxx_xxxx}: new_op = save_reg ? |
{push_ea, 8'h31, saver,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b10, 4'h1} // one more |
: {addr_nop,8'h00, rtmpl,src_x,new_fp,frame[5:0],op_mov, 2'b00,2'b00, 4'h0}; // At ENTER |
|
// Phase 50 : RESTORE/EXIT Entry |
{8'h32,10'bxx_xxxx_xxxx}: new_op = save_reg ? |
{pop_op, 8'h33, src_x,stack, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1} |
: {pop_fp, ppfp, src_x,frame, 1'b0,dest_x, op_mov, 2'b00,2'b00, 3'h0,new_fp}; |
// Phase 51 : RESTORE/EXIT next reg |
{8'h33,10'bxx_xxxx_xxxx}: new_op = save_reg ? |
{next_po, 8'h33, imme, src_x, 1'b1,resto, op_mov, 2'b00,2'b00, 4'h1} |
: {pop_fp, ppfp, imme, frame, 1'b1,resto, op_mov, 2'b00,2'b00, 3'h0,new_fp}; |
// Phase 52 : EXIT End |
{8'h34,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, imme, src_x, 1'b1,frame[5:0], op_mov, 2'b00,2'b |
|
// Phase 53 : CXP Entry : this opcode needs 12 States and 16 cycles minimum ... |
{8'h35,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h36, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, |
// Phase 54 : CXP : Store Address Link table |
{8'h36,10'bxx_xxxx_xxxx}: new_op = {rdltab, 8'h37, src_x,rtmph, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 55 : CXP : DISP is worked on, the return address => temp_l |
{8'h37,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h38, imme, rtmph, 1'b1,temp_l, op_mov, 2'b00,2'b00, |
// Phase 56 : CXP : Access to Link table => Result is MOD-Entry => store in temp_h |
{8'h38,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h39, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, |
// Phase 57 : CXP : store and PUSH MOD prepare , Entry from Exception Processing |
{8'h39,10'bxx_xxxx_xxxx}: new_op = {push_op, 8'h3A, modul,stack, 1'b0,dest_x, op_wrp, 2'b00,2'b10, |
// Phase 58 : CXP : PUSH of MOD ongoing, PUSH PC prepare |
{8'h3A,10'bxx_xxxx_xxxx}: new_op = {ea_push, 8'h3B, rtmpl,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b10, |
// Phase 59 : CXP : New EA for PC |
{8'h3B,10'bxx_xxxx_xxxx}: new_op = {save_sp, 8'h3C, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 60 : CXP : write of PC, calculate of Offset |
{8'h3C,10'bxx_xxxx_xxxx}: new_op = {rmod_8, 8'h3D, rtmph,rtmph, 1'b1,temp_l, op_flip,2'b00,2'b00, |
// Phase 61 : CXP : read from (MOD:New+8) |
{8'h3D,10'bxx_xxxx_xxxx}: new_op = {ea_min8, 8'h3E, imme, rtmpl, 1'b1,temp_l, op_add, 2'b00,2'b00, |
// Phase 62 : CXP : EA Phase of SB read , new PC calculated |
{8'h3E,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h3F, rtmpl,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 63 : CXP : read of SB , new PC to ICache |
{8'h3F,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h2F, imme, src_x, 1'b1,6'h1A, op_mov, 2'b00,2'b00, |
// Phase 47 : CXP : Last phase update of MOD prepare |
{8'h2F,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, rtmph,src_x, 1'b1,modul[5:0], op_mov, 2'b00,2'b |
|
// Phase 64 : RXP Entry : POP of PC , full Access |
{8'h40,10'bxx_xxxx_xxxx}: new_op = {pop_ru, 8'h41, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, |
// Phase 65 : RXP : PC is read, next POP prepare |
{8'h41,10'bxx_xxxx_xxxx}: new_op = {adddisp, 8'h42, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 66 : RXP : DISP is addeed to Stack and MOD is read |
{8'h42,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h43, imme, src_x, 1'b1,modul[5:0], op_mov, 2'b00,2'b |
// Phase 67 : RXP : MOD is new |
{8'h43,10'bxx_xxxx_xxxx}: new_op = {rmod_rxp,8'h44, rtmph,modul, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 68 : RXP : wait for SB data, parallel SP update |
{8'h44,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, imme, src_x, 1'b1,6'h1A, op_mov, 2'b00,2'b00, |
|
// Phase 69 : RETI : read of ICU for End-of-Interrupt Cycle , prepare read PC from Stack |
{8'h45,10'bxx_xxxx_xxxx}: new_op = {pop_op, 8'h46, src_x,stack, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 70 : RETI/ RETT Entry : POP of PC , full Access |
{8'h46,10'bxx_xxxx_xxxx}: new_op = {pop_ru, 8'h47, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, |
// Phase 71 : RETI/RETT : PC is read, next POP prepare |
{8'h47,10'bxx_xxxx_xxxx}: new_op = {save_sp, 8'h48, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 72 : RETI/RETT : DISP is added to Stack , PSR load and MOD is loaded if DE off |
{8'h48,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h49, imme, src_x, no_modul, op_ldp, 2'b00,2'b00, 4' |
// Phase 73 : RETI/RETT : different paths |
{8'h49,10'bxx_xxxx_xxxx}: new_op = de_flag ? |
( reti_flag ? |
{addr_nop,8'h4A, rtmph,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'h4B, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} ) |
: {rmod_rtt,8'h4B, rtmph,modul, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1}; |
// Phase 74 : RETI/RETT : one pause cycle if DE on |
{8'h4A,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 75 : RETI/RETT : SB read if DE off |
{8'h4B,10'bxx_xxxx_xxxx}: new_op = reti_flag ? |
{addr_nop,8'h00, imme, src_x, 1'b1,6'h1A, op_mov, 2'b00,2'b00, 4'h0} |
: ( de_flag ? |
{adddispn,8'h4E, src_x,ttstak,1'b0,dest_x, op_mov, 2'b00,2'b00, 4'hE} |
: {adddispn,8'h4E, imme, ttstak,1'b1,6'h1A, op_mov, 2'b00,2'b00, 4'hE} ); |
// Phase 78 : RETT : SP update |
{8'h4E,10'bxx_xxxx_xxxx}: new_op = {save_sp, 8'h4A, rtmph,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
|
// +++++++++++++++ special wait states for PSR and the Cache/MMU system +++++++++++ |
|
// Phase 76 : PSR in Word case simple delay of 2 cycles : 1. cycle does nothing |
{8'h4C,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h4D, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 77 : PSR in Word case simple delay of 2 cycles : 2. cycle does Restart of instruction pro |
{8'h4D,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
// Phase 79 : Wait for INIT_DONE from Cachesystem |
{8'h4F,10'bxx_xxxx_xxxx}: new_op = (INIT_DONE | no_init) ? |
{addr_nop,8'h4D, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'h4F, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0}; |
|
// +++++++++++++++ Direct Exception procession similar to CXP ++++++++++++++++++++ |
|
// Phase 121 : CXP : store and PUSH PSR prepare , Entry of Exception Processing |
{8'h79,10'bxx_xxxx_xxxx}: new_op = {push_op, 8'h7A, modul,stack, 1'b0,dest_x, op_wrp, 2'b00,2'b10, |
// Phase 122 : CXP : PUSH of PSR running, PUSH PC prepare - MOD like normal Exception-Flow |
{8'h7A,10'bxx_xxxx_xxxx}: new_op = {ea_push, 8'h7B, rtmpl,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b10, |
// Phase 123 : CXP : New EA for PC , Output of Interrupt-Vector and LOAD_PC generation, continue a |
{8'h7B,10'bxx_xxxx_xxxx}: new_op = {save_sp, 8'h4A, rtmph,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
|
// +++++++++++++++ here comes the general Exception Processing ++++++++++++++++++ |
|
// Phase 0 : Entry with saving of PC_ARCHI and PSR |
{8'h00,10'b11_xxxx_xxxx}: new_op = {save_pc, 8'h80, src_x,src_x, 1'b0,dest_x, op_psr, 2'b00,2'b00, |
// Phase 128 : different paths to three cases |
{8'h80,10'bxx_xxxx_xxxx}: new_op = abo_int ? |
{ai_next[30:4], src_x,src_x, 1'b1,temp_l, op_adr, 2'b00,2'b00, ai_next[3:0]} |
: {get_vec, 8'h81, src_x,ibase, 1'b1,temp_l, op_adr, 2'b00,2'b00, 4'h1}; |
// Phase 129 : read of Exception-Vectors and store in TEMP_H , then continue at CXP if DE off |
{8'h81,10'bxx_xxxx_xxxx}: new_op = de_flag ? |
{addr_nop,8'h79, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'h39, imme, src_x, 1'b1,temp_h, op_mov, 2'b00,2'b00, 4'h0}; |
// Phase 130 : read of Interrupt-Vectors, Zero-Extension of Byte => TEMP_H |
{8'h82,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h83, imme, src_x, 1'b1,temp_h, op_zex, 2'b00,2'b00, |
// Phase 131 : access of Exception-Vector |
{8'h83,10'bxx_xxxx_xxxx}: new_op = (type_nmi | ~ivec_flag) ? // NMI or non-vectored INT ? |
{get_vec, 8'h81, src_x,ibase, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1} |
: {get_veci,8'h81, rtmph,ibase, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1}; |
|
// Phase 132 : ABORT : store TEAR |
{8'h84,10'bxx_xxxx_xxxx}: new_op = {save_msr,8'h85, src_x,src_x, 1'b1,w_tear, op_adr, 2'b00,2'b00, |
// Phase 133 : store MSR |
{8'h85,10'bxx_xxxx_xxxx}: new_op = (ssrc_flag | sdest_flag) ? |
{addr_nop,rrepa, src_x,src_x, 1'b1,w_msr, op_adr, 2'b00,2'b00, 4'h0} |
: {get_vec ,8'h81, src_x,ibase, 1'b1,w_msr, op_adr, 2'b00,2'b00, 4'h1}; |
// Phase 134 : reload of pointers for string opcodes : R2 Dest |
{8'h86,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h87, rtmp1,src_x, 1'b1,6'h02, op_mov, 2'b00,2'b00, |
// Phase 135 : reload of pointers for string opcodes : R1 Source |
{8'h87,10'bxx_xxxx_xxxx}: new_op = {get_vec ,8'h81, rtmph,ibase, 1'b1,6'h01, op_mov, 2'b00,2'b00, |
|
// +++++++++++++++++ WAIT +++++++++++++++++++++++++++++++++ |
{8'h88,10'bxx_xxxx_xxxx}: new_op = interrupt ? |
{addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} // wait ... |
: {addr_nop,8'h88, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0}; // Loop |
|
// +++++++++++++++++ FLAG +++++++++++++++++++++++++++++++++ |
{8'h89,10'bxx_xxxx_xxxx}: new_op = flag ? |
{save_pc, 8'h80, src_x,src_x, 1'b0,dest_x, op_psr, 2'b00,2'b00, 4'h0} // TRAP |
: {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0}; // continue |
|
// +++++++++++++++++ The Opcodes of Gruppe 2 +++++++++++++++ |
|
{8'h00,10'b10_0xxx_xxxx}: new_op = state_0; |
// Now the case with Index , the Long Operand is copied to OUT |
{8'h00,10'b10_1xxx_xxxx}: new_op = {addr_nop,8'h50, src_1,src_1l,1'b0,dest_x, opera, 2'b00,~src2_f |
|
{8'h5x,10'bxx_xxxx_xxxx}: new_op = state_group_50; // Gruppe 2 Opcodes |
{8'h6x,10'bxx_xxxx_xxxx}: new_op = state_group_60; // Gruppe 2 Opcodes |
|
// that is only for CVTP : |
{8'h73,10'bxx_xxxx_x0xx}: new_op = {addr_nop,8'h00, src_x,src_x, 1'b1,dest_r, op_adr, 2'b00,2'b00, |
{8'h73,10'bxx_xxxx_x1xx}: new_op = {adwr2, phwr2, irrw2,rega2, 1'b0,dest_x, op_adr, 2'b00,2'b10, |
|
// that is only for LMR and CINV : |
{8'h74,10'bxx_xxxx_xxxx}: new_op = (IC_READ | STOP_CINV) ? |
{ivar_adr,8'h74, rtmph,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} // wait ... |
: {ivar_adr,8'h75, rtmph,src_x, 1'b1,lmrreg, op_lmr, 2'b00,2'b00, 4'h0}; // continue |
{8'h75,10'bxx_xxxx_xxxx}: new_op = {ivar_adr,8'h4F, rtmph,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, |
|
// +++++++++++++++++ The String Opcodes +++++++++++++++++++++ |
|
// Phase 192 : R0=0 ? |
{8'hC0,10'bxx_xxxx_xxxx}: new_op = STRING[2] ? // Is R0<>0 ? |
{st_src, ph_str,rstr1,rstr1, ~kurz_st,temp_h, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0}; |
// Phase 193 : 1. part read of SRC-Register => EA |
{8'hC1,10'bxx_xxxx_xxxx}: new_op = {st_len, 8'hC2, src_x,src_x, 1'b1,wstr1, op_adr, 2'b00,2'b00, |
// Phase 194 : memory operation : read |
{8'hC2,10'bxx_xxxx_xxxx}: new_op = mt_flag ? |
{addr_nop,8'hD3, imme, src_x, 1'b1,temp_2, (op_feld_reg[14] ? op_zex : op_mov), |
2'b00,2'b00, 4'h0} |
: {load_ea, 8'hC3, imme, rstr2, 1'b0,dest_x, op_mov, 2'b00,2'b10, 4'h0}; |
// Phase 195 : Data in output register and at the same time R2 to EA |
{8'hC3,10'bxx_xxxx_xxxx}: new_op = {st_dest, 8'hC4, rstr2,imme, ~kurz_st,temp_1, op_mov, 2'b00,2'b |
// Phase 196 : 1. part reuse EA and LSD of 8B data to Out-Register |
{8'hC4,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hC5, src_x,src_x, 1'b1,wstr2, op_adr, 2'b00,2'b00, |
// Phase 197 : memory operation : write |
{8'hC5,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hC7, rstr0,src_x, 1'b1,wstr0, op_str, 2'b00,2'b00, |
// Phase 199 : Test for End and Interrupt |
{8'hC7,10'bxx_xxxx_xxxx}: new_op = (interrupt & ~kurz_st) ? |
{save_pc, 8'h80, src_x,src_x, 1'b0,dest_x, op_psr, 2'b00,2'b00, 4'h0} // Interrupt ! |
: ( STRING[2] ? // Is R0<>0 ? |
{st_src, ph_str,rstr1,rstr1, ~kurz_st,temp_h, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} ); |
// String Compare : |
// Phase 201 : 1. part read of SRC-Register => EA |
{8'hC9,10'bxx_xxxx_xxxx}: new_op = {st_len, 8'hCA, src_x,src_x, 1'b1,wstr1, op_adr, 2'b00,2'b00, |
// Phase 202 : memory operation : read |
{8'hCA,10'bxx_xxxx_xxxx}: new_op = mt_flag ? |
{addr_nop,8'hDB, imme, src_x, 1'b1,temp_2, (op_feld_reg[14] ? op_zex : op_mov), |
2'b00,2'b00, 4'h0} |
: ( skps_flag ? // SKPS read only String1 |
{addr_nop,8'hC7, rstr0,src_x, 1'b1,wstr0, op_str, 2'b00,2'b00, 4'h0} |
: {load_ea, 8'hCB, imme, rstr2, 1'b1,temp_2, op_mov, 2'b00,2'b00, 4'h0} ); |
// Phase 203 : Data to output register and at the same time R2 to EA |
{8'hCB,10'bxx_xxxx_xxxx}: new_op = {st_src2, 8'hCC, rstr2,src_x, ~kurz_st,temp_1, op_mov, 2'b00,2'b |
// Phase 204 : 1. part reuse EA |
{8'hCC,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hCD, src_x,src_x, 1'b1,wstr2, op_adr, 2'b00,2'b00, |
// Phase 205 : memory operation : read and prepare compare |
{8'hCD,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hCE, rtmp2,imme, 1'b0,dest_x, op_scp, 2'b00,2'b10, |
// Phase 206 : compare of data |
{8'hCE,10'bxx_xxxx_xxxx}: new_op = STRING[3] ? // Elements equal ? Same as ACB_ZERO without delay o |
{addr_nop,8'hC7, rstr0,src_x, 1'b1,wstr0, op_str, 2'b00,2'b00, 4'h0} |
: ( kurz_st ? // at CMPM direct end |
{addr_nop,8'h00, src_x,src_x, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h0} |
: {addr_nop,8'hC8, rtmph,src_x, 1'b1,6'h01, op_mov, 2'b00,2'b00, 4'h0} ); |
// Phase 200 : reload of R1 at CMPS, prepare reload of R2 |
{8'hC8,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'h00, rtmp1,src_x, 1'b1,6'h02, op_mov, 2'b00,2'b00, |
// String Options Match and Translate for MOVS |
// Phase 211 : Test if Translate |
{8'hD3,10'bxx_xxxx_xxxx}: new_op = op_feld_reg[14] ? // Translate ? Translate Base is Register 3 |
{st_trans,8'hD4, rtmp2,7'h03, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1} |
: {addr_nop,8'hD7, rtmp2,7'h04, 1'b0,dest_x, op_scp, 2'b00,2'b10, 4'h0}; // Match |
// Phase 212 : memory operation : read |
{8'hD4,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hD5, imme, src_x, 1'b1,temp_2, op_mov, 2'b00,2'b10, |
// Phase 213 : Test if Match |
{8'hD5,10'bxx_xxxx_xxxx}: new_op = op_feld_reg[16] ? // Match ? Reference Value is Register 4 |
{addr_nop,8'hD7, rtmp2,7'h04, 1'b0,dest_x, op_scp, 2'b00,2'b10, 4'h0} |
: {st_trde, 8'hC4, 7'h02,7'h02, 1'b1,temp_1, op_mov, 2'b00,2'b00, 4'h0}; // back to MOVS |
// Phase 215 : Match result evaluation |
{8'hD7,10'bxx_xxxx_xxxx}: new_op = (STRING[3] ^ op_feld_reg[17]) ? // Not equal? (op_feld_reg[17] = |
{load_ea, 8'hC3, rtmp2,7'h02, 1'b0,dest_x, op_mov, 2'b00,2'b10, 4'h0} // back to MOVS |
: {addr_nop,8'h00, rtmph,src_x, 1'b1,6'h01, op_mov, 2'b00,2'b00, 4'h0}; // Abort, R1 ba |
// String Options Match and Translate for CMPS and SKPS - to many options to get it in one state |
// Phase 218 : Test if Translate |
{8'hDB,10'bxx_xxxx_xxxx}: new_op = op_feld_reg[14] ? // Translate ? Translate Base is Register 3 |
{st_trans,8'hDC, rtmp2,7'h03, 1'b0,dest_x, op_mov, 2'b00,2'b00, 4'h1} |
: {addr_nop,8'hDF, rtmp2,7'h04, 1'b0,dest_x, op_scp, 2'b00,2'b10, 4'h0}; // Match |
// Phase 220 : memory operation : read |
{8'hDC,10'bxx_xxxx_xxxx}: new_op = {addr_nop,8'hDD, imme, src_x, 1'b1,temp_2, op_mov, 2'b00,2'b10, |
// Phase 221 : Test if Match |
{8'hDD,10'bxx_xxxx_xxxx}: new_op = op_feld_reg[16] ? // Match ? Reference value is Register 4 |
{addr_nop,8'hDF, rtmp2,7'h04, 1'b0,dest_x, op_scp, 2'b00,2'b10, 4'h0} |
: ( skps_flag ? // SKPS read only String1 |
{addr_nop,8'hC7, 7'h00,src_x, 1'b1,6'h00, op_str, 2'b00,2'b00, 4'h0} // back to SKPS |
: {st_trs2, 8'hCC, 7'h02,7'h02, 1'b1,temp_1, op_mov, 2'b00,2'b00, 4'h0}); // back to CMP |
// Phase 223 : Match result evaluation |
{8'hDF,10'bxx_xxxx_xxxx}: new_op = (STRING[3] ^ op_feld_reg[17]) ? // Not equal? (op_feld_reg[17] = |
( skps_flag ? // SKPS read only String1 |
{addr_nop,8'hC7, 7'h00,src_x, 1'b1,6'h00, op_str, 2'b00,2'b00, 4'h0} // back to SKPS |
: {st_trs2, 8'hCC, 7'h02,7'h02, 1'b1,temp_1, op_mov, 2'b00,2'b00, 4'h0} ) // back to CMP |
: {addr_nop,8'h00, rtmph,src_x, 1'b1,6'h01, op_mov, 2'b00,2'b00, 4'h0}; // Abort, R1 ba |
|
default : new_op = 67'hx_xxxx_xxxx_xxxx_xxxx; |
endcase |
|
// ++++++++++++++++++++++++ Deliver data of state machine ++++++++++++++++++++++++++++ |
|
// not all new_op bits are evaluated here ... |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) ACC_FELD[11:10] <= 2'b00; // RD WR |
else if (next) ACC_FELD[11:10] <= new_op[64:63]; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) spupd_i <= 1'b0; // Stack Pointer Update |
else if (next) spupd_i <= new_op[56]; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) oper_i <= 11'b0; |
else if (next) oper_i <= new_op[18:8]; |
|
always @(posedge BCLK) |
if (next) |
begin |
ACC_FELD[13:12] <= new_op[66:65]; // ASIZE[1:0] |
ACC_FELD[8:0] <= {new_op[61:57],new_op[51:48]}; // FULLACC INDEX[3:0] POST CLRMSW SRC2SEL[1:0] |
disp_sel <= new_op[55:52]; |
wradr_i <= new_op[24:19]; |
end |
|
always @(posedge BCLK) wmaske_i <= src2_le; // to simple ? |
|
always @(posedge BCLK) index_cmd <= (phase_reg == 8'h60); // that only for INDEX |
|
// WMASKE : SP always 32 Bit, opcodes in Format 1, Reg-Nr. >31 , INDEX opcodes and the CHECK operan |
assign WMASKE = {(spupd | format1 | wradr_i[5] | wmaske_i[1] | index_cmd | (oper_i[7:0] == 8'h83)), |
assign WRADR = spupd ? {~stack[5],stack[4:0]} : wradr_i; |
assign WREN = (spupd | wren_i) & no_trap; |
assign OPER = spupd ? op_adr : oper_i; |
|
always @(posedge BCLK) ACC_FELD[14] <= next & (new_op[64] | new_op[63] | new_op[62]); // NEWACC is |
always @(posedge BCLK) ACC_FELD[9] <= next & new_op[62]; // LDEA is only one pulse |
|
always @(posedge BCLK) START <= next ? new_op[7:6] : 2'b00; |
always @(posedge BCLK) ldoreg <= next ? new_op[5:4] : 2'b00; // [1] = LD_OUT , [0] = LD_LDQ |
always @(posedge BCLK) wren_i <= next & new_op[25] & ~new_op[7]; // only if no START[1] from Long-O |
|
assign LD_OUT = {(ldoreg[1] & no_trap),ldoreg[0]}; // [1] = LD_OUT (for CMP too) , [0] = LD_LDQ |
|
assign spupd = spupd_i & ~wren_i & ~ldoreg[1] & ~spu_block; // no Stack Update if OUT Register load |
|
assign do_long = new_op[7]; // START[1] for long_reg |
|
assign RDAA = {next,new_op[39:33]}; // Source 1 |
assign RDAB = {next,new_op[32:26]}; // Source 2 |
|
always @(posedge BCLK) if (next) WR_REG = new_op[25] & new_op[7]; // START[1] : if WR then LONG pat |
|
// special case : example is POLYL F2,TOS |
always @(posedge BCLK) spu_block <= DONE & WR_REG; |
|
assign MMU_UPDATE[1] = (phase_reg == 8'h84) | (phase_reg == 8'h85); // serving the MMU at ABORT |
|
// only the real access gets USER Status : important for Memory Relative & External |
always @(posedge BCLK) // MOVUS MOVSU RDVAL/WRVAL |
if (ACC_FELD[14]) dc_user <= PSR[8] | (m_ussu & (m_usel ? (phase_reg == 8'h07) : (phase_reg == 8'h |
else dc_user <= dc_user & ~abort; |
|
always @(posedge BCLK) dc_ilo <= op_ilo & (phase_reg == 8'h59); |
always @(posedge BCLK) ILO <= op_ilo & ((phase_reg == 8'h59) | (phase_reg == 8'h27)); |
|
assign RWVAL = {dc_ilo,(rwval_flag & (phase_reg == 8'h53)),wrval_flag}; // is used for DCACHE ILO t |
|
// Signals for the I_PATH + Debug |
assign DETOIP = {pc_match,cmps_flag,ph_match,op_feld_reg[17],kill_opt,inss_op,exin_cmd,extract,bit_ |
|
// Signals for the ADDR_UNIT : [5]=RMW Signal |
assign chk_rmw = (phase_reg == 8'h17) | (phase_reg == 8'h58) | ((phase_reg == 8'h59) & rw_bit); // |
assign INFO_AU = {no_trap,chk_rmw,(op_feld_reg[40:39] == 2'b11),RWVAL[1],(a_ivar & ~IC_READ),dc_use |
|
assign RESTART = (phase_reg == 8'h4D); |
|
// Signals to generate external STATUS |
assign GENSTAT[2] = (phase_reg == 8'h88); // WAIT Signal |
assign GENSTAT[1] = (phase_reg == 8'h82); // Interrupt Acknowlege Cycle |
assign GENSTAT[0] = (phase_reg == 8'h45); // End-of-Interrupt Cycle |
|
// ++++++++++++++++++++ Here is the Sub-Modul for the opcodes of Gruppe 2 ++++++++++++++++ |
|
GRUPPE_2 reste_ops (.BCLK(BCLK), .PHASE_0(PHASE_0), .OPREG(OPREG[13:0]), .PHASE(phase_ein[3:0]), |
.SRC_1(src_1), .SRC_2(src_2), .REGA1(rega1), .REGA2(rega2), .IRRW1(irrw1), .IRRW2(irrw2), |
.ADRD1(adrd1), .ADRD2(adrd2), .EXR12(exr12), .EXR22(exr22), .PHRD1(phrd1[3:0]), .PHRD2(phrd2[3 |
.NXRD1(nxrd1), .NXRW2(nxrw2), .ACCA({acc1,1'b0,acc2,1'b0}), .OPERA(opera), |
.STATE_0(state_0), .STATE_GROUP_50(state_group_50), .STATE_GROUP_60(state_group_60) ); |
|
endmodule |
/trunk/rtl/REGISTERS.v
0,0 → 1,324
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: REGISTERS.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// 1. CONFIG_REGS Configuration and Debug Registers |
// 2. FP_STAT_REG Floating Point Status Register |
// 3. REGISTER General Purpose Registers |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 1. CONFIG_REGS Configuration and Debug Registers |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module CONFIG_REGS ( BCLK, BRESET, WREN, LD_OUT, OPCODE, SRC1, WRADR, PC_ARCHI, USER, PCMATCH, DBG_H |
CFG, MCR, PTB_WR, PTB_SEL, IVAR, CINV, Y_INIT, DSR, DBG_TRAPS, DBG_IN ); |
|
input BCLK,BRESET; |
input WREN,LD_OUT; |
input [7:0] OPCODE; |
input [31:0] SRC1; |
input [5:0] WRADR; |
input [31:0] PC_ARCHI; |
input USER; |
input PCMATCH; |
input DBG_HIT; |
input READ; |
|
output [12:0] CFG; |
output [3:0] MCR; |
output PTB_WR; |
output PTB_SEL; |
output [1:0] IVAR; |
output [3:0] CINV; |
output Y_INIT; |
output [3:0] DSR; |
output [2:0] DBG_TRAPS; |
output [40:2] DBG_IN; |
|
reg [3:0] MCR; |
reg [12:0] CFG; |
reg [1:0] old_cfg; |
reg PTB_WR,PTB_SEL; |
reg ivarreg; |
reg [1:0] ci_all,ci_line; |
reg check_y; |
|
wire ld_cfg,ld_mcr,do_cinv; |
wire init_ic,init_dc; |
wire op_ok; |
|
assign op_ok = (OPCODE == 8'h6A); // Special Opcode - for security reason |
|
assign ld_cfg = op_ok & (WRADR == 6'h1C) & WREN; |
assign ld_mcr = op_ok & (WRADR == 6'd9) & WREN; |
assign do_cinv = op_ok & (WRADR[5:4] == 2'b11) & WREN; |
|
// PF is not implemented |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) CFG <= 13'h0; |
else if (ld_cfg) CFG <= SRC1[12:0]; |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) MCR <= 4'h0; |
else if (ld_mcr) MCR <= SRC1[3:0]; |
|
always @(posedge BCLK) ivarreg <= op_ok & (WRADR[5:1] == 5'd7) & WREN; // IVAR0/1 = Reg. Nr. 14/15 |
assign IVAR = {ivarreg,PTB_SEL}; |
|
always @(posedge BCLK) PTB_WR <= op_ok & (WRADR[5:1] == 5'd6) & WREN; // PTB0/1 = Reg. Nr. 12/13 |
always @(posedge BCLK) PTB_SEL <= WRADR[0]; |
|
// The Cache content will be invalid if the Enable-Bit is set to 0 |
always @(posedge BCLK) old_cfg <= {CFG[11],CFG[9]}; |
|
// Cache Invalidate : the Flags are coming out of the Short-field which is otherwise used for Regis |
always @(posedge BCLK) ci_all <= do_cinv & WRADR[2] ? WRADR[1:0] : 2'b0; // clear all |
always @(posedge BCLK) ci_line <= do_cinv & ~WRADR[2] ? WRADR[1:0] : 2'b0; // clear cache line |
|
assign init_ic = old_cfg[1] & (~CFG[11] | ci_all[1]); |
assign init_dc = old_cfg[0] & (~CFG[9] | ci_all[0]); |
|
assign CINV = {init_ic,ci_line[1],init_dc,ci_line[0]}; |
|
// Y_INIT is neccessary if nothing has changed and therefore no DC/IC_INIT is generated |
always @(posedge BCLK) check_y <= ld_cfg | do_cinv; |
assign Y_INIT = check_y & ~init_ic & ~init_dc; // goes to register "old_init" |
|
// +++++++++++++ DEBUG Unit +++++++++++++++ |
|
reg [3:0] DSR; |
reg [12:0] dcr; |
reg [31:0] bpc; |
reg [31:2] car; |
|
wire op_dbg,ld_dcr,ld_bpc,ld_dsr,ld_car; |
wire enable; |
|
assign op_dbg = (OPCODE == 8'h76); |
|
assign ld_dcr = op_dbg & (WRADR == 6'h11) & WREN; |
assign ld_bpc = op_dbg & (WRADR == 6'h12) & WREN; |
assign ld_dsr = op_dbg & (WRADR == 6'h13) & WREN; |
assign ld_car = op_dbg & (WRADR == 6'h14) & WREN; |
|
assign enable = dcr[12] & (USER ? dcr[10] : dcr[11]); // DEN & (USER ? UD : SD) |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) dcr <= 13'd0; |
else if (ld_dcr) dcr <= {SRC1[23:19],SRC1[7:0]}; |
|
always @(posedge BCLK) if (ld_bpc) bpc <= SRC1; |
always @(posedge BCLK) if (ld_car) car <= SRC1[31:2]; |
|
// DEN SD DEN UD CAE CRD CAE CWR VNP/CBE CAR |
assign DBG_IN = {(dcr[12] & dcr[11]),(dcr[12] & dcr[10]),(dcr[7] & dcr[6]),(dcr[7] & dcr[5]),dcr[4: |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) DSR <= 4'd0; |
else |
if (ld_dsr) DSR <= SRC1[31:28]; |
else |
begin |
DSR[3] <= DBG_HIT ? READ : DSR[3]; |
DSR[2] <= DSR[2] | PCMATCH; |
DSR[1] <= DSR[1]; |
DSR[0] <= DSR[0] | DBG_HIT; |
end |
|
assign DBG_TRAPS[0] = enable & dcr[9] & (PC_ARCHI == bpc); // dcr[9]=PCE |
assign DBG_TRAPS[1] = DBG_HIT; // Compare Adress Hit |
assign DBG_TRAPS[2] = dcr[8]; // TR, Trap enable |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 2. FP_STAT_REG Floating Point Status Register |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module FP_STAT_REG ( BCLK, BRESET, LFSR, UP_SP, UP_DP, TT_SP, TT_DP, WREN, WRADR, DIN, FSR, TWREN, F |
|
input BCLK; |
input BRESET; |
input LFSR; // Load by LFSR opcode |
input UP_SP,UP_DP; // update if calculation operation |
input [4:0] TT_SP,TT_DP; |
input WREN; // for RMB and LFSR |
input [5:4] WRADR; |
input [16:0] DIN; // Data for LFSR opcode |
|
output [31:0] FSR; |
output TWREN; |
output reg FPU_TRAP; |
output SAVE_PC; |
|
reg [4:3] trap_d; |
reg update_d; |
reg set_rm_d; |
reg [10:0] set_bits; |
reg [4:0] flags; |
reg rm_bit; |
|
wire load_fsr; |
wire update,update_i; |
wire [4:0] trap; |
wire uflag,iflag,rmflag; |
|
assign load_fsr = LFSR & WREN; |
|
assign trap = UP_SP ? TT_SP : TT_DP; |
|
// This signal suppresses write into registers if FPU Trap, timing critical signal ! |
assign TWREN = ~((UP_SP & (TT_SP[2:0] != 3'b0)) | (UP_DP & (TT_DP[2:0] != 3'b0))); |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) FPU_TRAP <= 1'b0; |
else FPU_TRAP <= ~FPU_TRAP & ~TWREN; // one pulse of one cycle informs the Opcode Decoder |
|
assign update_i = (UP_SP | UP_DP) & ~FPU_TRAP; // unfortunately one FPU opcode may follow ! |
always @(posedge BCLK) update_d <= update_i; |
always @(posedge BCLK) trap_d <= trap[4:3]; |
always @(posedge BCLK) set_rm_d <= WREN & (WRADR == 2'b10); |
assign update = update_d & ~FPU_TRAP; |
|
// The Flags are set and stay "1" |
assign iflag = (update & trap_d[4]) | flags[4]; // Inexact Result |
assign uflag = (update & trap_d[3]) | flags[3]; // Underflow |
assign rmflag = (set_rm_d & ~FPU_TRAP) | rm_bit; // Register Modify |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) flags[4:3] <= 2'b0; // Inexact = Bit6, Underflow = Bit4 |
else |
begin |
if (load_fsr) flags[4:3] <= {DIN[6],DIN[4]}; |
else |
if (update) flags[4:3] <= {iflag,uflag}; |
end |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) flags[2:0] <= 3'b0; // TT Field = Bit2-0 |
else |
begin |
if (load_fsr) flags[2:0] <= DIN[2:0]; |
else |
if (update_i) flags[2:0] <= trap[2:0]; |
end |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) rm_bit <= 1'b0; // Register Modify Bit |
else |
begin |
if (load_fsr) rm_bit <= DIN[16]; |
else |
if (set_rm_d & ~FPU_TRAP) rm_bit <= 1'b1; // in case of TRAP there is no writing to Register |
end |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) set_bits <= 11'b0; // all other Bits |
else |
if (load_fsr) set_bits <= {DIN[15:7],DIN[5],DIN[3]}; |
|
assign FSR = {15'h0,rmflag,set_bits[10:2],iflag,set_bits[1],uflag,set_bits[0],flags[2:0]}; |
|
assign SAVE_PC = (UP_SP | UP_DP) & ~FPU_TRAP; // Store the correct PC for FPU Trap |
|
endmodule |
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// 3. REGISTER General Purpose Registers |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
module REGISTER( BCLK, ENWR, DOWR, BYDIN, DIN, RADR, WADR, WMASKE, DOUT, SELI ); |
|
input BCLK; |
input DOWR,ENWR; |
input [31:0] BYDIN,DIN; |
input [7:0] RADR; |
input [5:0] WADR; |
input [1:0] WMASKE; |
|
output [31:0] DOUT; |
output reg SELI; |
|
reg [2:0] MX; |
|
wire [3:0] BE; |
wire eq_rw; |
|
// +++++++++++++++++++ Memories ++++++++++++++++++++ |
|
reg [7:0] REGFILE_D [0:63]; |
reg [7:0] REGFILE_C [0:63]; |
reg [7:0] REGFILE_B [0:63]; |
reg [7:0] REGFILE_A [0:63]; |
reg [31:0] RF; |
|
assign BE = {WMASKE[1],WMASKE[1],(WMASKE[1] | WMASKE[0]),1'b1}; |
|
assign eq_rw = ENWR & (RADR[5:0] == WADR); |
|
always @(posedge BCLK) if (RADR[7]) MX[2:0] <= BE[2:0] & {{3{eq_rw}}}; |
|
always @(posedge BCLK) if (RADR[7]) SELI <= RADR[6]; |
|
assign DOUT[31:16] = MX[2] ? BYDIN[31:16] : RF[31:16]; |
assign DOUT[15:8] = MX[1] ? BYDIN[15:8] : RF[15:8]; |
assign DOUT[7:0] = MX[0] ? BYDIN[7:0] : RF[7:0]; |
|
// ++++++++++++++++ Register File 64 * 32 Bits ++++++++++++ |
|
always @(posedge BCLK) |
if (RADR[7]) |
begin |
RF[31:24] <= REGFILE_D[RADR[5:0]]; |
RF[23:16] <= REGFILE_C[RADR[5:0]]; |
RF[15:8] <= REGFILE_B[RADR[5:0]]; |
RF[7:0] <= REGFILE_A[RADR[5:0]]; |
end |
|
always @(posedge BCLK) |
if (DOWR) |
begin |
if (BE[3]) REGFILE_D[WADR] <= DIN[31:24]; |
if (BE[2]) REGFILE_C[WADR] <= DIN[23:16]; |
if (BE[1]) REGFILE_B[WADR] <= DIN[15:8]; |
if (BE[0]) REGFILE_A[WADR] <= DIN[7:0]; |
end |
|
endmodule |
|
/trunk/rtl/DCACHE.v
0,0 → 1,497
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: DCACHE.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// DCACHE the data cache of M32632 |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module DCACHE( BCLK, MCLK, WRCFG, MDONE, BRESET, PTB_WR, PTB_SEL, IO_READY, REG_OUT, PSR_USER, WRIT |
WAMUX, ENWR, IC_PREQ, FILLRAM, CFG, CINVAL, DMA_AA, DP_Q, DRAM_Q, IC_VA, ICTODC, IO_Q, IVAR, MCR |
PACKET, SIZE, VADR, WADDR, WCTRL, IO_RD, IO_WR, DRAM_ACC, DRAM_WR, INIT_RUN, PTE_STAT, KDET, HLD |
ACC_STAT, DP_DI, DRAM_A, DRAM_DI, IACC_STAT, IC_SIGS, IO_A, IO_BE, IO_DI, KOLLI_A, MMU_DIN, ZTES |
RWVAL, RWVFLAG, DBG_IN, DBG_HIT, ENDRAM ); |
|
input BCLK; |
input MCLK; |
input WRCFG; |
input MDONE; |
input BRESET; |
input PTB_WR; |
input PTB_SEL; |
input IO_READY; |
input REG_OUT; |
input PSR_USER; |
input WRITE; |
input READ; |
input ZTEST; |
input RMW; |
input WAMUX; |
input ENWR; |
input IC_PREQ; |
input FILLRAM; |
input [1:0] CFG; |
input [1:0] CINVAL; |
input [27:4] DMA_AA; |
input [63:0] DP_Q; |
input [31:0] DRAM_Q; |
input [31:12] IC_VA; |
input [3:0] ICTODC; |
input [31:0] IO_Q; |
input [1:0] IVAR; |
input [3:0] MCR_FLAGS; |
input [3:0] PACKET; |
input [1:0] SIZE; |
input [31:0] VADR; |
input [11:2] WADDR; |
input [2:0] WCTRL; |
input [2:0] RWVAL; |
input [40:2] DBG_IN; |
input ENDRAM; |
|
output IO_RD; |
output IO_WR; |
output DRAM_ACC; |
output DRAM_WR; |
output INIT_RUN; |
output [1:0] PTE_STAT; |
output KDET; |
output HLDA; |
output RWVFLAG; |
output [5:0] ACC_STAT; |
output [31:0] DP_DI; |
output [3:1] IACC_STAT; |
output [1:0] IC_SIGS; |
output [27:4] KOLLI_A; |
output [23:0] MMU_DIN; |
output reg [27:0] DRAM_A; |
output reg [35:0] DRAM_DI; |
output reg [31:0] IO_A; |
output reg [3:0] IO_BE; |
output reg [31:0] IO_DI; |
output DBG_HIT; |
|
reg [31:0] DFFE_IOR; |
reg [31:0] CAPDAT; |
reg [31:0] VADR_R; |
reg AUX_ALT; |
reg DFF_QWEXT; |
|
wire [27:4] ADDR; |
wire ADR_EQU; |
wire AUX_DAT; |
wire CA_HIT; |
wire CA_SET; |
wire CUPDATE; |
wire DMA_MUX; |
wire [3:0] ENBYTE; |
wire HIT_ALL; |
wire INIT_CA_RUN; |
wire IO_ACC; |
wire IO_SPACE; |
wire KOMUX; |
wire MMU_HIT; |
wire NEW_PTB; |
wire PTB_ONE; |
wire [27:0] PTE_ADR; |
wire [31:12] RADR; |
wire [11:4] TAGA; |
wire [23:0] UPDATE_C; |
wire [31:0] UPDATE_M; |
wire USE_CA; |
wire USER; |
wire WB_ACC; |
wire WEMV; |
wire WR_MRAM; |
wire [31:0] WRDATA; |
wire VIRT_A; |
wire PTE_MUX; |
wire WE_CV; |
wire [23:0] DAT_CV; |
wire [4:0] WADR_CV; |
wire WRSET0; |
wire [3:0] BE_SET; |
wire [31:0] DAT_SET; |
wire [9:0] A_SET; |
wire WRSET1; |
wire SEL_PTB1; |
wire CI; |
wire [27:0] ADR_MX; |
wire LD_DRAM_A; |
wire VIRTUELL; |
wire NEW_PTB_RUN; |
wire KILL; |
wire LAST_MUX; |
wire [31:0] SET_DAT; |
wire [31:0] ALT_DAT; |
wire [31:0] DAT_MV; |
wire [3:0] RADR_MV; |
wire [3:0] WADR_MV; |
wire [31:0] LAST_DAT; |
wire WRCRAM0; |
wire WRCRAM1; |
wire PROT_ERROR; |
wire AUX_QW; |
wire PD_MUX; |
wire [19:0] PTE_DAT; |
wire PKEEP; |
|
// +++++++++++++++++++ Memories ++++++++++++++++++++ |
|
reg [7:0] DATA0_D [0:1023]; // Data Set 0 : 4 kBytes |
reg [7:0] DATA0_C [0:1023]; |
reg [7:0] DATA0_B [0:1023]; |
reg [7:0] DATA0_A [0:1023]; |
reg [31:0] SET_DAT0; |
|
reg [7:0] DATA1_D [0:1023]; // Data Set 1 : 4 kBytes |
reg [7:0] DATA1_C [0:1023]; |
reg [7:0] DATA1_B [0:1023]; |
reg [7:0] DATA1_A [0:1023]; |
reg [31:0] SET_DAT1; |
|
reg [15:0] TAGSET_0 [0:255]; // Tag Set for Data Set 0 : 256 entries of 16 bits |
reg [15:0] TAG0; |
|
reg [15:0] TAGSET_1 [0:255]; // Tag Set for Data Set 1 : 256 entries of 16 bits |
reg [15:0] TAG1; |
|
reg [23:0] CA_VALID [0:31]; // Valid bits for Data Set 0 and 1 : 32 entries of 24 bits |
reg [23:0] CVALID; |
|
reg [35:0] MMU_TAGS [0:255]; // Tag Set for MMU : 256 entries of 36 bits |
reg [35:0] MMU_Q; |
|
reg [31:0] MMU_VALID [0:15]; // Valid bits for MMU Tag Set : 16 entries of 32 bits |
reg [31:0] MVALID; |
|
assign ADR_EQU = ({RADR[27:12],VADR_R[11:4]} == DRAM_A[27:4]); // Limited to 256 MB |
|
assign ALT_DAT = AUX_ALT ? DFFE_IOR : CAPDAT ; |
|
assign RADR = VIRT_A ? MMU_Q[19:0] : VADR_R[31:12] ; |
|
assign ADR_MX = PTE_MUX ? PTE_ADR : {RADR[27:12],VADR_R[11:2],USE_CA,CA_SET} ; |
|
assign KOLLI_A = DMA_MUX ? DMA_AA : DRAM_A[27:4] ; |
|
assign SET_DAT = CA_SET ? SET_DAT1 : SET_DAT0 ; |
|
assign VIRT_A = ~CINVAL[0] & VIRTUELL; |
|
assign USER = ~MCR_FLAGS[3] & PSR_USER; |
|
assign DAT_SET = WRITE ? WRDATA : DRAM_Q ; |
|
assign BE_SET = ENBYTE | {~WRITE,~WRITE,~WRITE,~WRITE}; |
|
assign ADDR = KOMUX ? KOLLI_A : {RADR[27:12],VADR_R[11:4]} ; |
|
assign A_SET = WAMUX ? WADDR : VADR_R[11:2] ; |
|
assign TAGA = KOMUX ? KOLLI_A[11:4] : VADR[11:4] ; |
|
assign INIT_RUN = NEW_PTB_RUN | INIT_CA_RUN; |
|
assign LAST_MUX = AUX_ALT | AUX_DAT | AUX_QW; |
|
assign LAST_DAT = LAST_MUX ? ALT_DAT : SET_DAT ; |
|
assign LD_DRAM_A = ~(DRAM_ACC | PKEEP); |
|
assign ACC_STAT[4] = IO_ACC; |
assign ACC_STAT[5] = CA_HIT; |
|
always @(posedge BCLK) |
if (IO_ACC) |
begin |
IO_BE <= ENBYTE; |
IO_DI <= WRDATA; |
IO_A <= {RADR[31:12],VADR_R[11:0]}; |
end |
|
always @(posedge BCLK) if (LD_DRAM_A) DRAM_A[27:0] <= ADR_MX[27:0]; |
|
always @(posedge BCLK) if (IO_RD) DFFE_IOR <= IO_Q; |
|
always @(posedge BCLK) |
begin |
DRAM_DI <= {(PD_MUX ? PTE_DAT[19:16] : ENBYTE),WRDATA[31:16], |
(PD_MUX ? PTE_DAT[15:0] : WRDATA[15:0])}; |
AUX_ALT <= DFF_QWEXT | IO_RD; |
DFF_QWEXT <= IO_RD & SIZE[0] & SIZE[1]; |
VADR_R <= VADR; |
end |
|
always @(posedge MCLK) if (WCTRL[2]) CAPDAT <= DRAM_Q; |
|
// +++++++++++++++++++++++++ Cache Valid +++++++++++++++++++ |
|
always @(posedge BCLK) CVALID <= CA_VALID[TAGA[11:7]]; |
|
always @(negedge BCLK) if (WE_CV) CA_VALID[WADR_CV] <= DAT_CV; |
|
// +++++++++++++++++++++++++ Tag Set 0 +++++++++++++++++++++ |
|
always @(posedge BCLK) TAG0 <= TAGSET_0[TAGA]; |
|
always @(negedge BCLK) if (WRCRAM0) TAGSET_0[VADR_R[11:4]] <= RADR[27:12]; |
|
// +++++++++++++++++++++++++ Tag Set 1 +++++++++++++++++++++ |
|
always @(posedge BCLK) TAG1 <= TAGSET_1[TAGA]; |
|
always @(negedge BCLK) if (WRCRAM1) TAGSET_1[VADR_R[11:4]] <= RADR[27:12]; |
|
// +++++++++++++++++++++++++ Data Set 0 ++++++++++++++++++++ |
|
always @(posedge BCLK) |
begin |
SET_DAT0[31:24] <= DATA0_D[VADR[11:2]]; |
SET_DAT0[23:16] <= DATA0_C[VADR[11:2]]; |
SET_DAT0[15:8] <= DATA0_B[VADR[11:2]]; |
SET_DAT0[7:0] <= DATA0_A[VADR[11:2]]; |
end |
|
always @(posedge MCLK) |
if (WRSET0) |
begin |
if (BE_SET[3]) DATA0_D[A_SET] <= DAT_SET[31:24]; |
if (BE_SET[2]) DATA0_C[A_SET] <= DAT_SET[23:16]; |
if (BE_SET[1]) DATA0_B[A_SET] <= DAT_SET[15:8]; |
if (BE_SET[0]) DATA0_A[A_SET] <= DAT_SET[7:0]; |
end |
|
// +++++++++++++++++++++++++ Data Set 1 ++++++++++++++++++++ |
|
always @(posedge BCLK) |
begin |
SET_DAT1[31:24] <= DATA1_D[VADR[11:2]]; |
SET_DAT1[23:16] <= DATA1_C[VADR[11:2]]; |
SET_DAT1[15:8] <= DATA1_B[VADR[11:2]]; |
SET_DAT1[7:0] <= DATA1_A[VADR[11:2]]; |
end |
|
always @(posedge MCLK) |
if (WRSET1) |
begin |
if (BE_SET[3]) DATA1_D[A_SET] <= DAT_SET[31:24]; |
if (BE_SET[2]) DATA1_C[A_SET] <= DAT_SET[23:16]; |
if (BE_SET[1]) DATA1_B[A_SET] <= DAT_SET[15:8]; |
if (BE_SET[0]) DATA1_A[A_SET] <= DAT_SET[7:0]; |
end |
|
DCACHE_SM DC_SM( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.VIRTUELL(VIRTUELL), |
.IO_SPACE(IO_SPACE), |
.MDONE(MDONE), |
.MMU_HIT(MMU_HIT), |
.CA_HIT(CA_HIT), |
.READ(READ), |
.WRITE(WRITE), |
.ZTEST(ZTEST), |
.RMW(RMW), |
.USE_CA(USE_CA), |
.PTB_WR(PTB_WR), |
.PTB_SEL(PTB_SEL), |
.SEL_PTB1(SEL_PTB1), |
.IO_READY(IO_READY), |
.USER(USER), |
.PROTECT(ACC_STAT[3]), |
.PROT_ERROR(PROT_ERROR), |
.ENWR(ENWR), |
.WB_ACC(WB_ACC), |
.ADR_EQU(ADR_EQU), |
.IC_PREQ(IC_PREQ), |
.CAPDAT(CAPDAT[31:0]), |
.CPU_OUT(DP_Q[59:44]), |
.FILLRAM(FILLRAM), |
.IC_VA(IC_VA), |
.ICTODC(ICTODC), |
.VADR_R(VADR_R[31:12]), |
.NEW_PTB(NEW_PTB), |
.PTB_ONE(PTB_ONE), |
.DRAM_ACC(DRAM_ACC), |
.DRAM_WR(DRAM_WR), |
.IO_ACC(IO_ACC), |
.IO_RD(IO_RD), |
.IO_WR(IO_WR), |
.PTE_STAT(PTE_STAT), |
.ABORT(ACC_STAT[1]), |
.WR_MRAM(WR_MRAM), |
.CUPDATE(CUPDATE), |
.AUX_DAT(AUX_DAT), |
.PTE_MUX(PTE_MUX), |
.ACC_OK(ACC_STAT[0]), |
.ABO_LEVEL1(ACC_STAT[2]), |
.IACC_STAT(IACC_STAT), |
.KOMUX(KOMUX), |
.KDET(KDET), |
.HIT_ALL(HIT_ALL), |
.DMA_MUX(DMA_MUX), |
.HLDA(HLDA), |
.RWVAL(RWVAL[1:0]), |
.RWVFLAG(RWVFLAG), |
.IC_SIGS(IC_SIGS), |
.MMU_DIN(MMU_DIN), |
.PD_MUX(PD_MUX), |
.PKEEP(PKEEP), |
.PTE_ADR(PTE_ADR), |
.PTE_DAT(PTE_DAT)); |
|
CA_MATCH DCA_COMPARE( |
.INVAL_L(CINVAL[0]), |
.CI(CI), |
.MMU_HIT(MMU_HIT), |
.WRITE(WRITE), |
.KDET(KDET), |
.ADDR(ADDR), |
.CFG(CFG), |
.ENDRAM(ENDRAM), |
.CVALID(CVALID), |
.TAG0(TAG0), |
.TAG1(TAG1), |
.CA_HIT(CA_HIT), |
.CA_SET(CA_SET), |
.WB_ACC(WB_ACC), |
.USE_CA(USE_CA), |
.IOSEL(RADR[31:28]), |
.IO_SPACE(IO_SPACE), |
.KILL(KILL), |
.DC_ILO(RWVAL[2]), |
.UPDATE(UPDATE_C)); |
|
DCA_CONTROL DCA_CTRL( |
.BCLK(BCLK), |
.MCLK(MCLK), |
.BRESET(BRESET), |
.CA_SET(CA_SET), |
.HIT_ALL(HIT_ALL), |
.UPDATE(UPDATE_C), |
.VADR_R(ADDR[11:7]), |
.DRAM_ACC(DRAM_ACC), |
.CUPDATE(CUPDATE), |
.KILL(KILL), |
.WRITE(WRITE), |
.WRCFG(WRCFG), |
.WCTRL(WCTRL[1:0]), |
.INVAL_A(CINVAL[1]), |
.DAT_CV(DAT_CV), |
.WADR_CV(WADR_CV), |
.WE_CV(WE_CV), |
.INIT_CA_RUN(INIT_CA_RUN), |
.WRCRAM0(WRCRAM0), |
.WRCRAM1(WRCRAM1), |
.WRSET0(WRSET0), |
.WRSET1(WRSET1)); |
|
MMU_MATCH MMU_COMPARE( |
.USER(USER), |
.WRITE(WRITE), |
.READ(READ), |
.RMW(RMW), |
.IVAR(IVAR), |
.MCR_FLAGS(MCR_FLAGS[2:0]), |
.MMU_VA(MMU_Q[35:20]), |
.MVALID(MVALID), |
.VADR_R(VADR_R[31:12]), |
.MMU_HIT(MMU_HIT), |
.PROT_ERROR(PROT_ERROR), |
.VIRTUELL(VIRTUELL), |
.CI(CI), |
.SEL_PTB1(SEL_PTB1), |
.UPDATE(UPDATE_M)); |
|
MMU_UP MMU_CTRL( |
.BCLK(BCLK), |
.BRESET(BRESET), |
.NEW_PTB(NEW_PTB), |
.IVAR(IVAR[1]), |
.PTB1(PTB_ONE), |
.WR_MRAM(WR_MRAM), |
.MVALID(MVALID), |
.UPDATE(UPDATE_M), |
.VADR(VADR[19:16]), |
.VADR_R(VADR_R[19:16]), |
.WE_MV(WEMV), |
.NEW_PTB_RUN(NEW_PTB_RUN), |
.DAT_MV(DAT_MV), |
.RADR_MV(RADR_MV), |
.WADR_MV(WADR_MV)); |
|
// +++++++++++++++++++++++++ MMU Valid +++++++++++++++++++++ |
|
always @(posedge BCLK) MVALID <= MMU_VALID[RADR_MV]; |
|
always @(negedge BCLK) if (WEMV) MMU_VALID[WADR_MV] <= DAT_MV; |
|
// +++++++++++++++++++++++++ MMU Tags ++++++++++++++++++++++ |
|
always @(posedge BCLK) MMU_Q <= MMU_TAGS[VADR[19:12]]; |
|
always @(negedge BCLK) if (WR_MRAM) MMU_TAGS[VADR_R[19:12]] <= {VADR_R[31:20],MMU_DIN[23:0]}; |
|
RD_ALIGNER RD_ALI( |
.BCLK(BCLK), |
.ACC_OK(ACC_STAT[0]), |
.REG_OUT(REG_OUT), |
.PACKET(PACKET), |
.RDDATA(LAST_DAT), |
.SIZE(SIZE), |
.CA_HIT(CA_HIT), |
.DP_DI(DP_DI), |
.AUX_QW(AUX_QW)); |
|
WR_ALIGNER WR_ALI( |
.DP_Q(DP_Q), |
.PACKET(PACKET), |
.SIZE(SIZE), |
.ENBYTE(ENBYTE), |
.WRDATA(WRDATA)); |
|
DEBUG_AE DBGAE( |
.DBG_IN(DBG_IN), |
.READ(READ), |
.WRITE(WRITE), |
.USER(USER), |
.VIRTUELL(VIRTUELL), |
.ACC_OK(ACC_STAT[0]), |
.VADR_R(VADR_R[31:2]), |
.MMU_Q(MMU_Q[19:0]), |
.ENBYTE(ENBYTE), |
.DBG_HIT(DBG_HIT)); |
|
endmodule |
/trunk/rtl/ADDR_UNIT.v
0,0 → 1,348
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// This file is part of the M32632 project |
// http://opencores.org/project,m32632 |
// |
// Filename: ADDR_UNIT.v |
// Version: 1.0 |
// Date: 30 May 2015 |
// |
// Copyright (C) 2015 Udo Moeller |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// |
// Modules contained in this file: |
// ADDR_UNIT generates data access addresses and controls data cache operation |
// |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
module ADDR_UNIT ( BCLK, BRESET, READ, WRITE, LDEA, NEWACC, CLRMSW, POST, DISP_OK, FULLACC, SRC2SEL, |
DISP, PC_ARCHI, PC_ICACHE, IO_READY, ACC_STAT, MMU_UPDATE, IC_TEX, ABO_STAT, ADIVAR, RWVAL_1, |
NO_TRAP, FPU_TRAP, READ_OUT, WRITE_OUT, ZTEST, RMW, VADR, ADDR, SIZE, PACKET, ACC_DONE, ABORT |
|
input BCLK,BRESET; |
input READ,WRITE,LDEA; |
input NEWACC; |
input CLRMSW,POST,FULLACC; |
input [1:0] SRC2SEL; |
input [3:0] INDEX; |
input [1:0] ASIZE; |
input [31:0] SRC1,SRC2; |
input [1:0] BWD; |
input [31:0] DISP; |
input [31:0] PC_ARCHI,PC_ICACHE; |
input DISP_OK; |
input IO_READY; |
input [5:0] ACC_STAT; // Feedback from data cache about the running access |
input [1:0] MMU_UPDATE; |
input [2:0] IC_TEX; |
input [1:0] ABO_STAT; |
input ADIVAR; |
input RWVAL_1; // special access for RDVAL + WRVAL |
input OP_RMW; |
input PHASE_17; |
input NO_TRAP; |
input FPU_TRAP; |
|
output READ_OUT,WRITE_OUT,ZTEST,RMW; |
output [31:0] VADR; |
output [31:0] ADDR; |
output [1:0] SIZE; |
output [3:0] PACKET; |
output ACC_DONE; |
output ABORT; |
output REG_OUT; |
output [2:0] BITSEL; |
|
reg [31:0] VADR; |
reg READ_OUT,write_reg,ZTEST,RMW; |
reg [1:0] SIZE; |
reg [3:0] PACKET; |
reg [2:0] BITSEL; |
reg [31:0] source2; |
reg [31:0] index_val; |
reg [31:0] vadr_reg; |
reg [31:0] ea_reg; |
reg [31:0] tos_offset; |
reg [31:0] icache_adr; |
reg [31:0] sign_ext_src1; |
reg [31:12] pg_areg; |
reg reg_out_i,next_reg; |
reg ld_ea_reg; |
reg acc_run,acc_ende,acc_step; |
reg qwa_flag; |
reg no_done; |
reg frueh_ok; |
reg io_rdy; |
reg ABORT; |
reg [1:0] tex_feld; |
reg [2:0] u_ddt; |
reg pg_op; |
reg do_wr; |
|
wire acc_ok,acc_err,io_acc; |
wire acc_pass; |
wire ca_hit; |
wire [31:0] reg_adder; |
wire [31:0] next_vadr; |
wire [31:0] final_addr; |
wire [31:0] pg_addr; |
wire [1:0] inc_pack; |
wire [3:0] index_sel; |
wire ld_ea_i; |
wire ea_ok; |
wire qw_align; |
wire init_acc; |
wire in_page; |
wire all_ok; |
wire fa_out; |
wire pg_test; |
|
// ++++++++++++++++++++ Decoding ACC_STAT from data cache ++++++++++++++++++++++++++++ |
|
// ACC_STAT[5:0] : CA_HIT, IO_ACC, PROT_ERROR , ABO_LEVEL1 , ABORT , ACC_OK |
|
assign ca_hit = ACC_STAT[5]; |
assign io_acc = ACC_STAT[4]; |
assign acc_err = ACC_STAT[3] | ACC_STAT[1]; // Abort or Protection Error |
assign acc_ok = ACC_STAT[0] & ~pg_op; |
assign acc_pass = ACC_STAT[0] & ZTEST; |
|
always @(posedge BCLK) ABORT <= acc_err; // Signal to Steuerung - only a pulse |
|
always @(posedge BCLK) if (acc_err) tex_feld <= ACC_STAT[3] ? 2'b11 : {~ACC_STAT[2],ACC_STAT[2]}; / |
always @(posedge BCLK) if (acc_err) u_ddt <= {RMW,ABO_STAT[1],(WRITE_OUT | ZTEST)}; |
|
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
always @(SRC2SEL or CLRMSW or SRC2 or PC_ARCHI or ea_reg) |
case (SRC2SEL) |
2'b00 : source2 = {(CLRMSW ? 16'h0000 : SRC2[31:16]),SRC2[15:0]}; // base reg, External Addressi |
2'b01 : source2 = PC_ARCHI; // PC relative |
2'b10 : source2 = 32'h0; // Absolute Addressing |
2'b11 : source2 = ea_reg; // REUSE : 2. TOS |
endcase |
|
assign index_sel = POST ? 4'h0 : INDEX; // Alternative application of Index for POST Adder : POP fr |
|
always @(BWD or SRC1) |
casex (BWD) |
2'b00 : sign_ext_src1 = {{24{SRC1[7]}}, SRC1[7:0]}; // Byte |
2'b01 : sign_ext_src1 = {{16{SRC1[15]}},SRC1[15:0]}; // Word |
default : sign_ext_src1 = SRC1; |
endcase |
|
always @(index_sel or sign_ext_src1 or SRC1) |
casex (index_sel) |
|
4'b1_1xx : index_val = {{ 3{sign_ext_src1[31]}},sign_ext_src1[31:3]}; // for Bit Opcodes |
4'b0_100 : index_val = SRC1; |
4'b0_101 : index_val = {SRC1[30:0],1'b0}; |
4'b0_110 : index_val = {SRC1[29:0],2'b00}; |
4'b0_111 : index_val = {SRC1[28:0],3'b000}; |
default : index_val = 32'h0; |
endcase |
|
assign reg_adder = source2 + index_val; // SRC2 allows simple MOV with SRC1 |
|
assign final_addr = reg_adder + DISP; // That's the final access address |
|
always @(posedge BCLK) if (LDEA && (index_sel[3:2] == 2'b11)) BITSEL <= SRC1[2:0]; // for Bit Opcod |
|
always @(INDEX) // SP POP Operation & String Backward |
case (INDEX[2:0]) |
3'b000 : tos_offset = 32'h0000_0001; |
3'b001 : tos_offset = 32'h0000_0002; |
3'b010 : tos_offset = 32'h0000_0004; |
3'b011 : tos_offset = 32'h0000_0008; |
3'b100 : tos_offset = 32'hFFFF_FFFF; |
3'b101 : tos_offset = 32'hFFFF_FFFE; |
3'b110 : tos_offset = 32'hFFFF_FFFC; |
3'b111 : tos_offset = 32'hFFFF_FFF8; |
endcase |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) ld_ea_reg <= 1'b0; |
else ld_ea_reg <= (LDEA | ld_ea_reg) & ~DISP_OK; |
|
assign ld_ea_i = (LDEA | ld_ea_reg) & DISP_OK; |
|
assign ea_ok = (READ | WRITE | LDEA | ld_ea_reg) & ~FULLACC & DISP_OK; |
|
always @(posedge BCLK) icache_adr <= PC_ICACHE; |
|
// Memory for the calculated address for reuse and Register for POST modified addresses : |
always @(posedge BCLK) |
if (ld_ea_i) |
begin |
casex ({MMU_UPDATE[1],INDEX[0],POST}) |
3'b10x : ea_reg <= MMU_UPDATE[0] ? vadr_reg : icache_adr; // TEAR |
3'b11x : ea_reg <= MMU_UPDATE[0] ? |
{24'h0000_00,3'b101, u_ddt, tex_feld} // MSR |
: {24'h0000_00,3'b100,IC_TEX[2],ABO_STAT[0],1'b0,IC_TEX[1:0]}; // only READ from ICACHE |
3'b0x1 : ea_reg <= source2 + tos_offset ; |
3'b0x0 : ea_reg <= final_addr; |
endcase |
end |
|
assign ADDR = ea_reg; // used for ADDR opcode and TOS Addressing |
|
// This pulse stores all parameters of access |
assign init_acc = ((FULLACC ? (NEWACC & acc_ende) : acc_ende) | ~acc_run) & DISP_OK & (READ | WRITE |
|
assign fa_out = init_acc | ADIVAR; // special case for LMR IVAR,... |
|
always @(fa_out or acc_ok or final_addr or qw_align or pg_op or pg_areg or vadr_reg or next_vadr) |
casex ({fa_out,acc_ok}) |
2'b1x : VADR = {final_addr[31:3],(final_addr[2] | qw_align),final_addr[1:0]}; |
2'b00 : VADR = pg_op ? {pg_areg,12'h0} : vadr_reg; |
2'b01 : VADR = next_vadr; |
endcase |
|
always @(posedge BCLK) |
if (init_acc) vadr_reg <= {final_addr[31:3],(final_addr[2] | qw_align),final_addr[1:0]}; |
else |
if (pg_op && ZTEST && acc_err) vadr_reg <= {pg_areg,12'h0}; // for TEAR ! |
else |
if (acc_ok) vadr_reg <= next_vadr; |
|
assign next_vadr = qwa_flag ? {vadr_reg[31:3],3'b000} : ({vadr_reg[31:2],2'b00} + 32'h0000_0004); |
|
// Logic for Page border WRITE Test |
assign pg_addr = final_addr + {29'h0,(ASIZE[1] & ASIZE[0]),ASIZE[1],(ASIZE[1] | ASIZE[0])}; |
always @(posedge BCLK) if (init_acc) pg_areg <= pg_addr[31:12]; |
assign pg_test = (final_addr[12] != pg_addr[12]) & ~OP_RMW; // At RMW no Test necessary |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) pg_op <= 1'b0; |
else |
pg_op <= init_acc ? (WRITE & ~RWVAL_1 & pg_test) : (pg_op & ~acc_pass & ~acc_err); |
|
always @(posedge BCLK) do_wr <= pg_op & ZTEST & acc_pass; // All ok, Page exists => continue |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) READ_OUT <= 1'b0; |
else |
READ_OUT <= init_acc ? (READ & ~RWVAL_1) : (READ_OUT & ~acc_ende & ~acc_err); |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) write_reg <= 1'b0; |
else |
write_reg <= (init_acc ? (WRITE & ~RWVAL_1 & ~pg_test) : (write_reg & ~acc_ende & ~acc_err & ~FPU |
|
assign WRITE_OUT = write_reg & ~FPU_TRAP; |
|
// Special case for RDVAL and WRVAL |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) ZTEST <= 1'b0; |
else |
ZTEST <= pg_op ? (~ZTEST | (~acc_pass & ~acc_err)) : (init_acc ? RWVAL_1 : (ZTEST & ~acc_ende & |
|
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) RMW <= 1'b0; |
else |
RMW <= init_acc ? (OP_RMW & PHASE_17) : (RMW & ~acc_ende & ~acc_err); |
|
// Special case : first MSD access by aligned QWORD READ |
assign qw_align = (final_addr[2:0] == 3'b000) & READ & (ASIZE == 2'b11); |
|
always @(posedge BCLK) if (init_acc) qwa_flag <= qw_align; |
|
always @(posedge BCLK or negedge BRESET) // central flag that shows the ADDR_UNIT is busy |
if (!BRESET) acc_run <= 1'b0; |
else |
acc_run <= init_acc | (acc_run & ~acc_ende & ~acc_err & ~FPU_TRAP); |
|
always @(posedge BCLK) if (init_acc) SIZE <= ASIZE; |
|
assign inc_pack = (PACKET[1:0] == 2'b00) ? 2'b10 : {(SIZE[1] ^ SIZE[0]),(SIZE[1] & SIZE[0])}; |
|
// Counter for data packets 1 to 3 : special case aligned QWORD : only 2 packets. Additionally star |
// special coding (00) -> [01] -> (10) , [01] optional by QWORD and (10) shows always the end |
always @(posedge BCLK) |
if (init_acc) PACKET <= {2'b00,final_addr[1:0]}; |
else |
if (acc_ok) PACKET <= PACKET + {inc_pack,2'b00}; |
|
// This signal is the End signal for the ADDR_UNIT internally. |
always @(SIZE or PACKET or acc_ok) |
casex ({SIZE,PACKET[3],PACKET[1:0]}) |
5'b00_x_xx : acc_ende = acc_ok; // Byte |
5'b01_0_0x : acc_ende = acc_ok; // Word 1 packet |
5'b01_0_10 : acc_ende = acc_ok; // 1 packet |
5'b01_1_xx : acc_ende = acc_ok; // 2 packets |
5'b10_0_00 : acc_ende = acc_ok; // DWord 1 packet |
5'b10_1_xx : acc_ende = acc_ok; // 2 packets |
5'b11_1_xx : acc_ende = acc_ok; // QWord at least 2 packets |
default : acc_ende = 1'b0; |
endcase |
|
assign in_page = (vadr_reg[11:3] != 9'h1FF); // Access inside a page ? During WRITE address is incr |
|
always @(SIZE or vadr_reg or in_page or PACKET) |
casex (SIZE) |
2'b01 : frueh_ok = (vadr_reg[3:2] != 2'b11); //Word |
2'b10 : frueh_ok = (vadr_reg[3:2] != 2'b11); //DWord |
2'b11 : frueh_ok = (PACKET[1:0] == 2'b00) ? (~vadr_reg[3] | ~vadr_reg[2]) : ((PACKET[3:2] == 2'b |
default : frueh_ok = 1'b1; // Byte don't case |
endcase |
|
assign all_ok = SIZE[1] ? (PACKET[1:0] == 2'b00) : (PACKET[1:0] != 2'b11); // for DWord : Word |
|
always @(SIZE or READ_OUT or frueh_ok or PACKET or all_ok or io_acc or acc_ok or qwa_flag or io_rdy |
casex ({SIZE,READ_OUT,frueh_ok,PACKET[3],io_acc,all_ok}) |
7'b00_xxxx_x : acc_step = acc_ok; // Byte, all ok |
// |
7'b01_xxxx_1 : acc_step = acc_ok; // Word : aligned access , only 1 packet |
7'b01_1x1x_0 : acc_step = acc_ok; // READ must wait for all data |
7'b01_001x_0 : acc_step = acc_ok; // WRITE Adr. ist not perfect and waits for last packet |
7'b01_01xx_0 : acc_step = acc_ok; // WRITE Adr. perfect - acc_step after 1. packet |
// |
7'b10_xxxx_1 : acc_step = acc_ok; // DWord : aligned access , only 1 packet |
7'b10_1x1x_0 : acc_step = acc_ok; // READ must wait for all data |
7'b10_001x_0 : acc_step = acc_ok; // WRITE Adr. ist not perfect and waits for last packet |
7'b10_01xx_0 : acc_step = acc_ok; // WRITE Adr. perfect - acc_step after 1. packet |
// fast QWord READ : there would be a 2. acc_step if not ~PACK... |
7'b11_1xxx_x : acc_step = acc_ok & ( (qwa_flag & ~io_rdy & ca_hit) ? ~PACKET[3] : PACKET[3] ); |
7'b11_0x1x_x : acc_step = acc_ok; |
7'b11_0100_x : acc_step = acc_ok; // WRITE Adr. perfect - acc_step after 1. packet if not io_a |
default : acc_step = 1'b0; |
endcase |
|
// There is a 2. acc_step if packet (10) - this must be suppressed |
always @(posedge BCLK or negedge BRESET) |
if (!BRESET) no_done <= 1'b0; |
else no_done <= (~acc_ende & acc_step) | (no_done & ~(acc_run & acc_ende)); |
|
// The final DONE Multiplexer |
assign ACC_DONE = acc_run ? (acc_step & ~no_done) : ea_ok; |
|
always @(posedge BCLK) reg_out_i <= ~acc_step & BRESET & ((qwa_flag & (io_rdy | ~ca_hit) & acc_ok) |
|
always @(posedge BCLK) io_rdy <= IO_READY & (WRITE_OUT | READ_OUT); |
|
always @(posedge BCLK) next_reg <= (acc_step & ~qwa_flag) & (SIZE == 2'b11); |
assign REG_OUT = reg_out_i | next_reg; |
|
endmodule |