OpenCores
URL https://opencores.org/ocsvn/blue/blue/trunk

Subversion Repositories blue

[/] [blue/] [trunk/] [blue8/] [top.v] - Rev 4

Go to most recent revision | Compare with Previous | Blame | View Log

/*
    This file is part of Blue8.
 
    Foobar 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 3 of the License, or
    (at your option) any later version.
 
    Foobar 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 Blue8.  If not, see <http://www.gnu.org/licenses/>.
 
    Blue8 by Al Williams alw@al-williams.com
 
*/
 
// OK this is the blue CPU -- Williams
 
 `default_nettype	 none
 
 
 module blue(input wire clear,input wire clkin, output [15:0] accout, input wire start,
             input wire stop, input wire exam, input wire deposit, output wire [11:0] pcout,
				 input wire [15:0] swreg, input wire swloadpc, output wire [15:0] irout, output wire running,
				 /* memory interface */
				 output wire [11:0] xmaddress, inout wire [15:0] xmdata, output wire xmwrite, 
				 output wire xmsend,
				 output wire clk, output reg Q
 
				 );
   wire [15:0] 	 bus;
   wire [15:0] 	 mabus;  // memory address bus (11:0 significant)
   wire [15:0] 	 aluzbus;
   wire [15:0] 	 aluybus;
   wire [8:1] 	 cp;  // clock pulses
	wire [8:1] cpw;  // write clock pulses
   wire [15:0] 	 ibus;
   wire [15:0] 	 accbus;
   wire mclear;
	wire sendxor, sendx2, sendhalf;
	wire ihlt, ophlt, opxor, opand, opior, opnot, oplda, opsta, opsrj, opjmp, opldx;
	wire opral, opnop, opinc, opdec, opskip, opspn, opq, opqtog, opsub, opcmp, opldi, oprar, opidx;
	wire opstx, opjmpa, opswap, oplds, oppush, oppop, opframe, opldxa;
 
 
 
 
   wor 		 sendpc,writemar, writeZ,msend,mwrite, sendone,writeY, sendsum, senddiff;
   wor 		 sendir, sendbar, sendand, sendacc;
   wor 		  writeacc, sendor, sendffff, sendidx, writeidx;
	wire writeir;
   wire 	 DTA, ARITH, REF;
   wor s2bus, writepc;
  	wire doexam, dodep;
	wire sendzero;
	wor abortcycle;
	wire opadd; // ought to provide the others here too
	wire overflow, aluzero, carry;   
	reg zflag, oflag, cflag;
	wire [11:0] idxbus;
	wor writesp, sendsp;
 
 
   assign 	 accout=accbus;
	assign	 irout=ibus;
 
 
   // make the data path items
   register IR(clk,bus,writeir,bus,sendir,ibus,mclear);
   aregister MAR(clk,bus,writemar,,1'b1,mabus[11:0],mclear);
	aregister INDEX(clk,bus,writeidx,bus,sendidx,idxbus,mclear);
	aregister SP(clk,bus,writesp,bus,sendsp,,mclear);
   register Y(clk,bus,writeY,,1'b0,aluybus,mclear);
   register Z(clk,bus,writeZ,,1'b0,aluzbus,mclear);
//   mem core(clk,mabus,bus,mwrite,bus,msend);
   assign xmaddress=mabus;
	assign xmdata=mwrite?bus:16'bz;
	assign bus=xmsend?xmdata:16'bz;
   assign xmwrite=mwrite;
	assign xmsend=msend;
 
   register acc(clk,bus,writeacc,bus,sendacc,accbus,mclear);
   aregister pc(clk,bus,writepc,bus,sendpc,pcout,mclear);
   one One(sendone,bus);
   ffff Ffff(sendffff,bus);
	zero Zero(sendzero,bus);
 
   alu alu(aluybus,aluzbus,bus,sendsum,sendor,sendand,sendxor,sendbar,sendx2,senddiff,sendhalf, overflow,aluzero,carry,cflag);
 
   wire coverflow, writezf, writecf, writeflag;
	wire writepc1;
	assign writepc=writepc1;
//	assign coverflow=overflow & opadd;  // only overflow on adding
 assign coverflow=1'b0;  // we don't halt on overflow anymore
 
   // TODO: Tried to add abort cycle to let short instructions recycle faster. Doesn't seem to work (yet)
 
	control ctl(clkin,start,stop,exam,deposit,ihlt,coverflow,cp,cpw,clear,mclear,s2bus,writepc1,swloadpc, doexam,dodep,running,clk,abortcycle);
   idecode decoder(ibus,ophlt,opadd,opxor,opand,opior,opnot,oplda,opsta,
		   opsrj, opjmp, opldx,  opral, opnop,opinc,opdec, opskip, opspn,opq,opqtog,opsub,opcmp,
			opldi, oprar, opidx, opstx, opjmpa, opswap, oplds, oppush, oppop, opframe, opldxa);
 
 
   always @(posedge clk or posedge mclear) begin			  // manage Q output
	  if (mclear) Q<=0;
	  else if (cpw[5]) begin
	    if (opq) Q<=ibus[0];
	    else if (opqtog) Q<=~Q;
     end
	  else Q<=Q;
	end
 
   always @(posedge clk or posedge mclear) begin		 // manage z flag (not Z register)
	  if (mclear) zflag<=1'b0;
	  else if (writeflag) zflag<=bus[1]; 
	  else if ((sendsum|senddiff|sendor|sendand|sendxor|sendbar|sendx2)&(writeacc|writezf)) zflag<=aluzero;
	  else zflag<=zflag;
	end   
 
	always @(posedge clk or posedge mclear) begin		// manage overflow flag
	  if (mclear) oflag<=1'b0;
	  else if (writeflag) oflag<=bus[0]; 
	  else if (sendsum&writeacc) oflag<=overflow;
	  else oflag<=oflag;
	end 
 
	always @(posedge clk or posedge mclear) begin	  // manage carry flag
	  if (mclear) cflag<=1'b0;
	  else if (writeflag) cflag<=bus[2]; 
	  else if ((sendsum|sendx2|senddiff|sendhalf)&(writeacc|writecf)) cflag<=carry;
	  else cflag<=cflag;
	end 
 
// load pc (switch)
   assign bus=s2bus?swreg:16'bz;
 
   // instructions
// first part of F cycle
    assign sendpc=cp[1];
	 assign writemar=cpw[1];
	 assign writeZ=cpw[1];
 
 
	// So here this was in cp[6] but I moved things and will move this to cp2
// which leaves cp5,6,7,8/F free for processing.. placing it before PC++
// means the async decoder can be pretty sloppy since the result is not needed until cp5
   and u7(msend,cp[2],~(doexam|dodep));
	and u7z(sendzero, cp[2],(doexam|dodep));		// assumes NOP or HALT=0
   assign writeir=cpw[2];
 
 
	 assign sendone=cp[3];
	 assign writeY=cpw[3];
 
// writeback PC... cycles 5-8 are free for execute
 
    assign sendsum=cp[4];
	 assign writepc=cpw[4];
 
 
// do an exam 
   and uex1(msend,cp[5],doexam);
	and uex2(writeacc,cpw[5],doexam);
 
 
// do a deposit
   and udep1(s2bus,cp[5],dodep);
	and udep2(mwrite,cpw[5],dodep);
 
 
// halt instruction 
   and u9(ihlt,cp[7],ophlt);
 
// 2 jump instruction
   and u12(sendir,opjmp,cp[5]);
   and u13(writepc,opjmp,cpw[5]);
 
	// abort 6 cycle instructions
 	and u13x(abortcycle,opjmp|opldx|opstx|opjmpa|opswap|oplds|opnop|opframe|opq|opqtog,cp[5]);
	// abort 7 cycle instructions
	and u13y(abortcycle, opskip|opspn|opnot|opral|oprar|opidx,cp[6]);
 
// RAL, NOT, CSA
// don't need the next 3 anymore
// because I preload ACC to Z in CP5/F
//   or u16(nr1,opnot,opral);
//   and u17a(sendacc,nr1,cp[7]);
//   and u17b(writeZ,nr1,cp[7]);
// update: changed CP5/F to execute cycle so now Ido this later 
 
 
// not (pt 2)
   and u19a(sendbar,opnot,cp[6]);
   and u19b(writeacc,opnot,cpw[6]);
// ral, rar
   and u20a(sendx2,opral,cp[6]);
   and u20c(sendhalf,oprar,cp[6]);
   and u20b(writeacc,opral|oprar,cpw[6]);
 
// skipped input/output TODO
 
// ARITH, DTA, REF (internal)
   assign 	 ARITH=opand|opxor|opior|opadd|opsub|opcmp;
   assign 	 DTA=ARITH | oplda;
   assign 	 REF=DTA | opsta;
 
  // for some reason, asserting estate on cp[8] worked in simulation, but 
  // in real life, single stepping would halt before E state in a two cycle
  // instruction. So that implies an async stop could hold the machine in E state
  // moving estate assert to cp[7] fixed this even though sim says no difference
 
  //V3 moves all 2 cycle instructions to 1 cycle, 
//   and u21(estate,REF,F,cp[7]);		  // was cp[8] but no REF instruction uses cp[7] for anything
   and u22a(sendir,cp[5], ARITH|((opsta|oplda) & ~ibus[15]));		// ir[15] = 1 for ldax, stax
   assign bus=((opsta|oplda) & cp[5]  & ibus[15])?ibus[11:0]+idxbus:16'bz;      
   and u22b(writemar,REF,cpw[5]);		  
 
 
   and u23a(sendacc,REF,cp[6]);	  // These could be ARITH? DTA/REF don't use Z register, but harmless
   and u23b(writeZ,REF,cpw[6]);
 
//   and u24(msend,DTA,E,cp[5]);
// my design does not use cp5/F so I am going to use that
// cycle to load Acc to Z in case we want it for future
// So in execute phase ACC ->Z 1->Y and no need to do it over
// However, since then I have changed the design so that cp5 is
// a regular execute slot so this is now specific to the INCA, DECA
// NOT and RAL instructions
   and u40a(sendacc,opinc|opdec|opnot|opral|oprar,cp[5]);
   and u40b(writeZ,opinc|opdec|opnot|opral|oprar,cpw[5]);
 
 
   and u25a(sendacc,opsta,cp[8]);
   and u25b(mwrite,opsta,cpw[8]);
 
   and u26a(msend,oplda,cp[8]);
   and u27a(writeacc,oplda,cpw[8]);
 
   and u28a(msend,ARITH,cp[7]);
   and u28b(writeY,ARITH,cpw[7]);
 
   and u29a(sendsum,opadd,cp[8]);
   and u29b(writeacc,opadd,cpw[8]);
 
   and u29c(senddiff,opsub|opcmp,cp[8]);  
   and u29d(writeacc,opsub,cpw[8]);
	and u29e(writezf, opcmp,  cpw[8]);   
	and u29f(writecf, opcmp, cpw[8]);
 
 
   and u30a(sendxor,opxor,cp[8]);
   and u30b(writeacc,opxor,cpw[8]);
 
   and u31a(sendor,opior,cp[8]);
   and u31b(writeacc,opior,cpw[8]);
 
   and u32a(sendand,opand,cp[8]);
   and u32b(writeacc,opand,cpw[8]);
 
// Increment and dec instruction -- we already made cp5/F copy ACC->Z
   // and Y still has 1 in it, so...
// for decrement cp7/F needs to load -1 instead of 1
   and u42a(sendffff,opdec,cp[7]);
   and u42b(writeY,opdec,cpw[7]);
 
   and u41a(sendsum,opinc|opdec,cp[8]);
   and u41b(writeacc,opinc|opdec,cpw[8]);
 
 
	// skip instructions	(note OK to reuse ALU because C Z and O are latched on specific instructions
	wire [2:0] flags;
	assign flags={cflag, zflag, oflag};
	and u43a(sendpc,opskip,cp[5]);   
	and u43b(writeZ,opskip,cpw[5]);
	and u44a(sendsum,opskip,((ibus[3]?~flags:flags)&ibus[2:0])!=0,cp[6]);
// -- another way:   assign bus=opskip & cp[6]?skippc:16'bz;
	and u44b(writepc,opskip,((ibus[3]?~flags:flags)&ibus[2:0])!=0,cpw[6]);
 
// Could write skip on sign and get rid of JMA
   and u45a(sendpc,opspn,cp[5]);
	and u45b(writeZ, opspn,cpw[5]);
	and u46a(sendsum,opspn,ibus[0]?~accbus[15]:accbus[15],cp[6]);
// -- another way   assign bus=(opspn & cp[6])?skippc:16'bz;
	and u46b(writepc,opspn,ibus[0]?~accbus[15]:accbus[15],cpw[6]);
 
// LDI
   and u47a(sendpc,cp[5],opldi);
   and u47b(writemar,cpw[5],opldi);
   and u47c(writeZ,cpw[5],opldi);
   and u48a(sendsum,cp[6],opldi);
   and u48b(writepc,cpw[6],opldi);
   and u49a(msend,opldi,cp[7]);
   and u49b(writeacc,opldi,cpw[7]);
 
// LDX
   and u50a(sendir,cp[5],opldx);
	and u50aa(sendacc,cp[5],opldxa);
	and u50b(writeidx,cpw[5],opldx|opldxa);
 
 
// INCX/DECX
	and u51a(sendidx,cp[5],opidx);
	and u51b(writeZ,cpw[5],opidx);
	and u52a(sendsum,cp[6],opidx,~ibus[0]);
	and u52b(senddiff,cp[6],opidx,ibus[0]);
	and u52c(writeidx,cpw[6],opidx);
 
// STX
   and u53a(sendidx,cp[5],opstx);
	and u53b(writeacc,cpw[5],opstx);
 
// JMPA
   and u54a(sendacc,cp[5],opjmpa);
	and u54b(writepc,cpw[5],opjmpa);   
 
// SWAP
   assign bus[15:8]=opswap&cp[5]?accbus[7:0]:8'bz;
	assign bus[7:0]=opswap&cp[5]?accbus[15:8]:8'bz;
	and u55(writeacc,cpw[5],opswap);
 
// LDS
   and u56a(sendir,cp[5],oplds);
	and u56b(writesp,cpw[5],oplds);
 
// PUSH and CALL
   wire pushcall;
	assign pushcall=oppush|opsrj;
	and u57a(sendsp,cp[5],pushcall);
	and u57b(writemar,cpw[5],pushcall);
	and u57c(writeZ,cpw[5],pushcall);
	and u58a(sendacc,cp[6],oppush, ibus[1:0]==2'b00);
	and u58aa(sendidx,cp[6],oppush, ibus[1:0]==2'b10);
   assign bus=(cp[6]&oppush&ibus[1:0]==2'b11)?({13'b0, flags}):16'bz;
	and u58b(sendpc, cp[6], opsrj);
	and u58c(mwrite, cpw[6], pushcall);
	and u59a(senddiff,cp[7], pushcall);
	and u59b(writesp,cpw[7], pushcall);
	and u59c(sendir,cp[8],opsrj);
	and u59d(writepc, cpw[8],opsrj);
 
// POP and RET
 
   and u60a(sendsp,cp[5],oppop);
	and u60b(writeZ,cpw[5], oppop);
	and u61a(sendsum,cp[6],oppop);
	and u61b(writesp, cpw[6], oppop);
	and u61c(writemar,cpw[6], oppop);
	and u62a(msend, cp[7], oppop);
	and u62b(writeacc, cpw[7], oppop, ibus[1:0]==2'b00); 
	and u62c(writepc, cpw[7], oppop, ibus[1:0]==2'b01);
	and u62d(writeidx, cpw[7], oppop, ibus[1:0]==2'b10);	
	and u63a(writeflag, cp[7], oppop, ibus[1:0]==2'b11);  // pop flag -- not sure this works?  
 
 // frame
   and u64a(sendsp,cp[5],opframe);
	and u64b(writeidx,cpw[5],opframe);
 
endmodule
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.