cpu.v
上传用户:bltddc
上传日期:2020-07-09
资源大小:4428k
文件大小:27k
源码类别:

SCSI/ASPI

开发平台:

VHDL

  1. module cpu (
  2.    clk,
  3.    reset,
  4.    
  5.    paddr,
  6.    pdata,
  7.    portain,
  8.    portbout,
  9.    portcout,
  10.    
  11.    expdin,
  12.    expdout,
  13.    expaddr,
  14.    expread,
  15.    expwrite,
  16.    
  17.    debugw,
  18.    debugpc,
  19.    debuginst,
  20.    debugstatus
  21. );
  22. // Basic Core I/O.
  23. input clk;
  24. input reset;
  25. // Program memory interface
  26. output [10:0] paddr;
  27. input  [11:0] pdata;
  28. // Basic I/O Ports
  29. input  [7:0] portain;
  30. output [7:0] portbout;
  31. output [7:0] portcout;
  32. // Expansion Interface
  33. input [7:0] expdin; // Data from expansion circuits TO the PIC Core
  34. output [7:0] expdout; // Data to the expansion circuits FROM the PIC Core
  35. output [6:0] expaddr; // File address
  36. output expread; // Active high read signal (read FROM expansion circuit)
  37. output expwrite; // Active high write signal (write TO expansion circuit)
  38. // Debugging
  39. output [7:0] debugw;
  40. output [10:0] debugpc;
  41. output [11:0] debuginst;
  42. output [7:0] debugstatus;
  43. // Register declarations for outputs
  44. reg [10:0] paddr;
  45. reg [7:0] portbout;
  46. reg [7:0] portcout;
  47. reg [7:0] expdout;
  48. reg [6:0] expaddr;
  49. reg expread;
  50. reg expwrite;
  51. //
  52. // Copyright (c) 1999 Thomas Coonan (tcoonan@mindspring.com)
  53. //
  54. //    This source code is free software; you can redistribute it
  55. //    and/or modify it in source code form under the terms of the GNU
  56. //    General Public License as published by the Free Software
  57. //    Foundation; either version 2 of the License, or (at your option)
  58. //    any later version.
  59. //
  60. //    This program is distributed in the hope that it will be useful,
  61. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  62. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  63. //    GNU General Public License for more details.
  64. //
  65. //    You should have received a copy of the GNU General Public License
  66. //    along with this program; if not, write to the Free Software
  67. //    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  68. //
  69. // This should be set to the ROM location where our restart vector is.
  70. // As set here, we have 512 words of program space.
  71. //
  72. parameter RESET_VECTOR = 11'h7FF;
  73. parameter INDF_ADDRESS = 3'h0,
  74. TMR0_ADDRESS = 3'h1,
  75. PCL_ADDRESS = 3'h2,
  76. STATUS_ADDRESS = 3'h3,
  77. FSR_ADDRESS = 3'h4,
  78. PORTA_ADDRESS = 3'h5,
  79. PORTB_ADDRESS = 3'h6,
  80. PORTC_ADDRESS = 3'h7;
  81. // *********  Special internal registers
  82. // Instruction Register
  83. reg  [11:0] inst;
  84. // Program Counter
  85. reg  [10:0] pc, pc_in;
  86. // Stack Registers and Stack "levels" register.
  87. reg [ 1:0] stacklevel;
  88. reg [10:0] stack1;
  89. reg [10:0] stack2;
  90. // W Register
  91. reg [ 7:0] w;
  92. // The STATUS register (#3) is 8 bits wide, however, we only currently use 2 bits
  93. // of it; the C and Z bit.
  94. //
  95. // bit 0  -  C
  96. // bit 2  -  Z
  97. //
  98. reg [ 7:0] status;
  99. // The FSR register is the pointer register used for Indirect addressing (e.g. using INDF).
  100. reg  [ 7:0] fsr;
  101. // Timer 0
  102. reg  [ 7:0] tmr0;
  103. reg  [ 7:0] prescaler;
  104. // Option Register
  105. reg [7:0] option;
  106. // Tristate Control registers. We do not neccessarily support bidirectional ports, but
  107. //    will save a place for these registers and the TRIS instruction.  Use for debug.
  108. reg [7:0] trisa;
  109. reg [7:0] trisb;
  110. reg [7:0] trisc;
  111. // I/O Port registers
  112. //
  113. reg [7:0] porta; // Input PORT
  114. reg [7:0] portb; // Output PORT
  115. reg [7:0] portc; // Output PORT
  116. // ********** Instruction Related signals ******
  117. reg  skip;  // When HI force a NOP (all zeros) into inst
  118. // Derive special sub signals from inst register
  119. wire [ 7:0] k;
  120. wire [ 4:0] fsel;
  121. wire d;
  122. wire [ 2:0] b;
  123. // ********** File Address ************
  124. //
  125. // This is the 7-bit Data Address that includes the lower 5-bit fsel, the
  126. // FSR bits and any indirect addressing.
  127. // Use this bus to address the Register File as well as all special registers, etc.
  128. //
  129. reg [6:0] fileaddr;
  130. // Address Selects
  131. reg specialsel;
  132. reg regfilesel;
  133. reg expsel;
  134. // ******  Instruction Decoder Outputs **************
  135. // Write enable for the actual ZERO and CARRY bits within the status register.
  136. // Generated by the Instruction Decoder.
  137. //
  138. wire [1:0] aluasel;
  139. wire [1:0] alubsel;
  140. wire [3:0] aluop;
  141. wire zwe;
  142. wire cwe;
  143. wire isoption;
  144. wire istris;
  145. wire fwe; // High if any "register" is being written to at all.
  146. wire wwe; // Write Enable for the W register.  Produced by Instruction Decoder.
  147. // *************  Internal Busses, mux connections, etc.  ********************
  148. // Bit decoder bits.  
  149. reg [7:0] bd; // Final decoder value after any polarity inversion.
  150. reg [7:0] bdec; // e.g. "Bit Decoded"
  151. wire bdpol; // Polarity bit for the bit test operations.
  152. // Data in and out of the and out of the register file
  153. //
  154. reg [7:0] regfilein; // Input into Register File, is connected to the dbus.
  155. wire [7:0] regfileout; // Path leaving the register file, goes to SBUS Mux
  156. reg regfilewe; // Write Enable
  157. reg regfilere; // Read Enable
  158. //
  159. // The dbus (Destination Bus) comes out of the ALU.  It is available to all
  160. // writable registers.
  161. //
  162. // The sbus (Source Bus) comes from all readable registers as well as the output
  163. // of the Register File.  It is one of the primary inputs into the ALU muxes.
  164. //
  165. // The (Expansion Bus) is another potential source.  See the 'exp' signals.
  166. //
  167. reg  [7:0] dbus;
  168. reg  [7:0] sbus;
  169. // ALU Signals
  170. //
  171. reg  [7:0] alua;
  172. reg  [7:0] alub;
  173. wire [7:0] aluout;
  174. wire alucout;
  175. wire        aluz;
  176. // ALU A and B mux selects.
  177. //
  178. parameter [1:0] ALUASEL_W = 2'b00,
  179. ALUASEL_SBUS = 2'b01,
  180. ALUASEL_K = 2'b10,
  181. ALUASEL_BD = 2'b11;
  182. parameter [1:0] ALUBSEL_W = 2'b00,
  183. ALUBSEL_SBUS = 2'b01,
  184. ALUBSEL_K = 2'b10,
  185. ALUBSEL_1 = 2'b11;
  186. // ALU Operation codes.
  187. //
  188. parameter  [3:0] ALUOP_ADD  = 4'b0000;
  189. parameter  [3:0] ALUOP_SUB  = 4'b1000;
  190. parameter  [3:0] ALUOP_AND  = 4'b0001;
  191. parameter  [3:0] ALUOP_OR   = 4'b0010;
  192. parameter  [3:0] ALUOP_XOR  = 4'b0011;
  193. parameter  [3:0] ALUOP_COM  = 4'b0100;
  194. parameter  [3:0] ALUOP_ROR  = 4'b0101;
  195. parameter  [3:0] ALUOP_ROL  = 4'b0110;
  196. parameter  [3:0] ALUOP_SWAP = 4'b0111;
  197. // Instantiate each of our subcomponents
  198. //
  199. regs  regs (
  200.    .clk (clk), 
  201.    .reset (reset),
  202.    .we   (regfilewe),
  203.    .re (regfilere),
  204.    .bank (fileaddr[6:5]), 
  205.    .location (fileaddr[4:0]),
  206.    .din (regfilein), 
  207.    .dout (regfileout)
  208. );
  209. // Instatiate the ALU.
  210. //
  211. alu alu  (
  212.    .op         (aluop), 
  213.    .a          (alua), 
  214.    .b          (alub),
  215.    .y          (aluout),
  216.    .cin        (status[0]), 
  217.    .cout       (alucout), 
  218.    .zout       (aluz)
  219. );
  220. // Instantiate the Instruction Decoder.  This is really just a lookup table.
  221. // Given the instruction, generate all the signals we need.  
  222. //
  223. // For example, each instruction implies a specific ALU operation.  Some of
  224. // these are obvious such as the ADDW uses an ADD alu op.  Less obvious is
  225. // that a mov instruction uses an OR op which lets us do a simple copy.
  226. // 
  227. // Data has to funnel through the ALU, which sometimes makes for contrived
  228. // ALU ops.
  229. //
  230. wire idecwwe;
  231. wire idecfwe;
  232. wire ideczwe;
  233. wire ideccwe;
  234. idec idec (
  235.    .inst     (inst),
  236.    .aluasel  (aluasel),
  237.    .alubsel  (alubsel),
  238.    .aluop    (aluop),
  239.    .wwe      (idecwwe),
  240.    .fwe      (idecfwe),
  241.    .zwe      (ideczwe),
  242.    .cwe      (ideccwe),
  243.    .bdpol    (bdpol),
  244.    .option   (isoption),
  245.    .tris     (istris)
  246. );
  247. // Wire decoder enables to enables in at this module.  I did this because at
  248. // one time I had another global 'enable' that was ANDed in, but I removed that.
  249. //
  250. assign wwe = idecwwe;
  251. assign fwe = idecfwe;
  252. assign zwe = ideczwe;
  253. assign cwe = ideccwe;
  254. // *********** Debug ****************
  255. assign debugw = w;
  256. assign debugpc = pc;
  257. assign debuginst = inst;
  258. assign debugstatus = status;
  259. // *********** REGISTER FILE Addressing ****************
  260. //
  261. // We implement the following:
  262. //    - The 5-bit fsel address is within a "BANK" which is 32 bytes.
  263. //    - The FSR bits 6:5 are the BANK select, so there are 4 BANKS, a 
  264. //      total of 128 bytes.  Minus the 8 special registers, that's 
  265. //      really 120 bytes.
  266. //    - The INDF register is for indirect addressing.  Referencing INDF
  267. //      uses FSR as the pointer.  Therefore, using INDF/FSR you address
  268. //      7-bits of memory.
  269. // We DO NOT currently implement the PAGE for program (e.g. STATUS register
  270. // bits 6:5)
  271. //
  272. // The fsel address *may* be zero in which case, we are to do indirect
  273. // addressing, using FSR register as the 8-bit pointer.
  274. //
  275. // Otherwise, use the 5-bits of FSEL (from the Instruction itself) and 
  276. // 2 bank bits from the FSR register (bits 6:5).
  277. //
  278. always @(fsel or fsr or status) begin
  279.    if (fsel == INDF_ADDRESS) begin
  280.       // The INDEX register is addressed.  There really is no INDEX register.
  281.       // Use the FSR as an index, e.g. the FSR contents are the fsel.
  282.       //
  283.       fileaddr = fsr[6:0];
  284.    end
  285.    else begin
  286.       // Use FSEL field and status bank select bits
  287.       //
  288.       fileaddr = {status[6:5], fsel};
  289.    end
  290. end
  291. // Write Enable to Register File.  
  292. // Assert this when the general fwe (write enable to *any* register) is true AND Register File
  293. //    address range is specified.
  294. //  
  295. always @(regfilesel or fwe)
  296.    regfilewe = regfilesel & fwe;
  297. // Read Enable (this if nothing else, helps in debug.)
  298. // Assert if Register File address range is specified AND the ALU is actually using some
  299. //    data off the SBUS.
  300. //   
  301. always @(regfilesel or aluasel or alubsel)
  302.    regfilere = regfilesel & ((aluasel == ALUASEL_SBUS) | (alubsel == ALUBSEL_SBUS));
  303. // *********** Address Decodes **************
  304. //
  305. // Generate 3 selects: specialsel, regfilesel and expsel
  306. //
  307. // ** NOTE: Must change this whenever more or few expansion addresses are
  308. // added or removed from the memory map.  Otherwise, the dbus mux
  309. //  won't be controlled properly!
  310. //
  311. always @(fileaddr) begin
  312.    casex (fileaddr) // synopsys full_case parallel_case
  313.       // This shouldn't really change.
  314.       //
  315.       7'bXX00XXX: // The SPECIAL Registers are lower 8 addresses, in ALL BANKS
  316.          begin
  317.             specialsel = 1'b1;
  318.             regfilesel = 1'b0;
  319.             expsel = 1'b0;
  320.          end
  321.          
  322.       // Adjust this case as EXPANSION locations change!
  323.       //
  324.       7'b11111XX: // EXPANSION Registers are the top (4) addresses
  325.          begin
  326.             specialsel = 1'b0;
  327.             regfilesel = 1'b0;
  328.             expsel = 1'b1;
  329.          end
  330.          
  331.       // Assume everything else must be the Register File..
  332.       //
  333.       default:
  334.          begin
  335.             specialsel = 1'b0;
  336.             regfilesel = 1'b1;
  337.             expsel = 1'b0;
  338.          end
  339.    endcase
  340. end
  341.   
  342. // *********** Expansion Interface **************
  343. always @(dbus)
  344.    expdout = dbus;
  345.    
  346. always @(fileaddr)
  347.    expaddr = fileaddr;
  348. always @(expsel or aluasel or alubsel)
  349.    expread = expsel & ((aluasel == ALUASEL_SBUS) | (alubsel == ALUBSEL_SBUS));
  350. always @(expsel or fwe)
  351.    expwrite = expsel & fwe;
  352. //
  353. // *********** SBUS **************
  354. // The sbus (Source Bus) is the output of a multiplexor that takes
  355. // inputs from the Register File, and all other special registers
  356. // and input ports.  The Source Bus then, one of the inputs to the ALU
  357. // First MUX selects from all the special regsiters
  358. //
  359. always @(fsel or fsr or tmr0 or pc or status
  360.          or porta or portb or portc or regfileout or expdin
  361.          or specialsel or regfilesel or expsel) begin
  362.          
  363.    // For our current mix of registers and peripherals, only the first 8 addresses
  364.    // are "special" registers (e.g. not in the Register File).  As more peripheral
  365.    // registers are added, they must be muxed into this MUX as well.
  366.    //
  367.    // We currently prohibit tristates.
  368.    //
  369.    //
  370.    if (specialsel) begin
  371.       // Special register
  372.       case (fsel[2:0]) // synopsys parallel_case full_case
  373.          3'h0: sbus = fsr;
  374.          3'h1: sbus = tmr0;
  375.          3'h2: sbus = pc[7:0];
  376.          3'h3: sbus = status;
  377.          3'h4: sbus = fsr;
  378.          3'h5: sbus = porta; // PORTA is an input-only port
  379.          3'h6: sbus = portb; // PORTB is an output-only port
  380.          3'h7: sbus = portc; // PORTC is an output-only port
  381.       endcase
  382.    end
  383.    else begin
  384.       //
  385.       // Put whatever address equation is neccessary here.  Remember to remove unnecessary
  386.       // memory elements from Register File (regs.v).  It'll still work, but they'd be
  387.       // wasted flip-flops.
  388.       //
  389.       if (expsel) begin
  390.          sbus = expdin;
  391.       end
  392.       else begin
  393.          if (regfilesel) begin
  394.             // Final Priority is Choose the register file
  395.             sbus = regfileout;
  396.          end
  397.          else begin
  398.             sbus = 8'h00;
  399.          end
  400.       end
  401.    end
  402. end
  403. // ************** DBUS ******
  404. //  The Destination bus is just the output of the ALU.
  405. //
  406. always @(aluout)
  407.    dbus = aluout;
  408. always @(dbus)
  409.    regfilein = dbus;
  410.    
  411. // Drive the ROM address bus straight from the PC_IN bus
  412. //
  413. always @(pc_in)
  414.    paddr = pc_in;
  415. // Define sub-signals out of inst
  416. //
  417. assign k =     inst[7:0];
  418. assign fsel  = inst[4:0];
  419. assign d     = inst[5];
  420. assign b     = inst[7:5];
  421. // Bit Decoder.
  422. //
  423. // Simply take the 3-bit b field in the PIC instruction and create the
  424. // expanded 8-bit decoder field, which is used as a mask.
  425. //
  426. always @(b) begin
  427.    case (b) // synopsys parallel_case
  428.       3'b000: bdec = 8'b00000001;
  429.       3'b001: bdec = 8'b00000010;
  430.       3'b010: bdec = 8'b00000100;
  431.       3'b011: bdec = 8'b00001000;
  432.       3'b100: bdec = 8'b00010000;
  433.       3'b101: bdec = 8'b00100000;
  434.       3'b110: bdec = 8'b01000000;
  435.       3'b111: bdec = 8'b10000000;
  436.    endcase
  437. end
  438. always @(bdec or bdpol)
  439.    bd = (bdpol) ? ~bdec : bdec;
  440. // Instruction regsiter usually get the ROM data as its input, but
  441. // sometimes for branching, the skip signal must cause a NOP.
  442. //
  443. always @(posedge clk) begin
  444.    if (reset) begin
  445.       inst <= 12'h000;
  446.    end
  447.    else begin
  448.       if (skip == 1'b1) begin
  449.          inst <= 12'b000000000000; // FORCE NOP
  450.       end
  451.       else begin
  452.          inst <= pdata;
  453.       end
  454.    end
  455. end
  456. // SKIP signal.
  457. //
  458. // We want to insert the NOP instruction for the following conditions:
  459. //    GOTO,CALL and RETLW instructions (All have inst[11:10] = 2'b10
  460. //    BTFSS instruction when aluz is HI  (
  461. //    BTFSC instruction when aluz is LO
  462. //
  463. always @(inst or aluz) begin
  464.    casex ({inst, aluz}) // synopsys parallel_case
  465.       13'b10??_????_????_?:    // A GOTO, CALL or RETLW instructions
  466.          skip = 1'b1;
  467.          
  468.       13'b0110_????_????_1:    // BTFSC instruction and aluz == 1
  469.          skip = 1'b1;
  470.       13'b0111_????_????_0:    // BTFSS instruction and aluz == 0
  471.          skip = 1'b1;
  472.       
  473.       13'b0010_11??_????_1:    // DECFSZ instruction and aluz == 1
  474.          skip = 1'b1;
  475.       13'b0011_11??_????_1:    // INCFSZ instruction and aluz == 1
  476.          skip = 1'b1;
  477.       default:
  478.          skip = 1'b0;
  479.    endcase
  480. end
  481. // 4:1 Data MUX into alua
  482. //
  483. //
  484. always @(aluasel or w or sbus or k or bd) begin
  485.    case (aluasel) // synopsys parallel_case
  486.       2'b00: alua = w;
  487.       2'b01: alua = sbus;
  488.       2'b10: alua = k;
  489.       2'b11: alua = bd;
  490.    endcase
  491. end
  492. // 4:1 Data MUX into alub
  493. //
  494. //
  495. always @(alubsel or w or sbus or k) begin
  496.    case (alubsel) // synopsys parallel_case
  497.       2'b00: alub = w;
  498.       2'b01: alub = sbus;
  499.       2'b10: alub = k;
  500.       2'b11: alub = 8'b00000001;
  501.    endcase
  502. end
  503. // W Register
  504. always @(posedge clk) begin
  505.    if (reset) begin
  506.       w <= 8'h00;
  507.    end
  508.    else begin
  509.       if (wwe) begin
  510.          w <= dbus;
  511.       end
  512.    end   
  513. end
  514. // ************ Writes to various Special Registers (fsel between 0 and 7)
  515. // INDF Register (Register #0)
  516. //
  517. //    Not a real register.  This is the Indirect Addressing mode register.
  518. //    See the regfileaddr logic.
  519. // TMR0 Register (Register #1)
  520. //
  521. //    Timer0 is currently only a free-running timer clocked by the main system clock.
  522. //
  523. always @(posedge clk) begin
  524.    if (reset) begin
  525.       tmr0 <= 8'h00;
  526.    end
  527.    else begin
  528.       // See if the status register is actually being written to
  529.       if (fwe & specialsel & (fileaddr[2:0] == TMR0_ADDRESS)) begin
  530.          // Yes, so just update the register from the dbus
  531.          tmr0 <= dbus;
  532.       end
  533.       else begin
  534.          if (~option[5]) begin
  535.             // OPTION[3]  -  Assigns prescaler to either WDT or TIMER0.  We don't implement WDT.
  536.             //               If this bit is 0, then use the prescaler.  If 1 then increment.
  537.             //
  538.             // Mask off the prescaler value based on desired divide ratio.
  539.             // Whenever this is zero, then that is our divided pulse.  Increment
  540.             // the final timer value when it's zero.
  541.             //
  542.             casex (option[3:0]) // synopsys parallel_case full_case
  543.                4'b1XXX: tmr0 <= tmr0 + 1;
  544.                4'b0000: if (~|(prescaler & 8'b00000001)) tmr0 <= tmr0 + 1;
  545.                4'b0001: if (~|(prescaler & 8'b00000011)) tmr0 <= tmr0 + 1;
  546.                4'b0010: if (~|(prescaler & 8'b00000111)) tmr0 <= tmr0 + 1;
  547.                4'b0011: if (~|(prescaler & 8'b00001111)) tmr0 <= tmr0 + 1;
  548.                4'b0100: if (~|(prescaler & 8'b00011111)) tmr0 <= tmr0 + 1;
  549.                4'b0101: if (~|(prescaler & 8'b00111111)) tmr0 <= tmr0 + 1;
  550.                4'b0110: if (~|(prescaler & 8'b01111111)) tmr0 <= tmr0 + 1;
  551.                4'b0111: if (~|(prescaler & 8'b11111111)) tmr0 <= tmr0 + 1;
  552.             endcase            
  553.          end
  554.       end
  555.    end
  556. end
  557. // The prescaler is always counting from 00 to FF whenever OPTION[5] is cleared (e.g. T0CS)
  558. always @(posedge clk) begin
  559.    if (reset) begin
  560.       prescaler <= 8'h00;
  561.    end
  562.    else begin
  563.       if (~option[5]) begin
  564.          prescaler <= prescaler + 1;
  565.       end
  566.    end
  567. end
  568. // PCL Register (Register #2)
  569. //
  570. //    PC Lower 8 bits.  This is handled in the PC section below...
  571. // STATUS Register (Register #3)
  572. //
  573. parameter STATUS_RESET_VALUE = 8'h18;
  574. always @(posedge clk) begin
  575.    if (reset) begin
  576.       status <= STATUS_RESET_VALUE;
  577.    end
  578.    else begin
  579.       // See if the status register is actually being written to
  580.       if (fwe & specialsel & (fileaddr[2:0] == STATUS_ADDRESS)) begin
  581.          // Yes, so just update the register from the dbus
  582.          status <= dbus;
  583.       end
  584.       else begin
  585.          // Update status register on a bit-by-bit basis.
  586.          //
  587.          // For the carry and zero flags, each instruction has its own rule as
  588.          // to whether to update this flag or not.  The instruction decoder is
  589.          // providing us with an enable for C and Z.  Use this to decide whether
  590.          // to retain the existing value, or update with the new alu status output.
  591.          //
  592.          status <= {
  593.             status[7], // BIT 7: Undefined.. (maybe use for debugging)
  594.             status[6], // BIT 6: Program Page, HI bit
  595.             status[5], // BIT 5: Program Page, LO bit
  596.             status[4], // BIT 4: Time Out bit (not implemented at this time)
  597.             status[3], // BIT 3: Power Down bit (not implemented at this time)
  598.             (zwe) ? aluz : status[2], // BIT 2: Z
  599.             status[1], // BIT 1: DC
  600.             (cwe) ? alucout : status[0] // BIT 0: C
  601.          };
  602.       end
  603.    end
  604. end
  605. // FSR Register  (Register #4)
  606. //            
  607. always @(posedge clk) begin
  608.    if (reset) begin
  609.       fsr <= 8'h00;
  610.    end
  611.    else begin
  612.       // See if the status register is actually being written to
  613.       if (fwe & specialsel & (fileaddr[2:0] == FSR_ADDRESS)) begin
  614.          fsr <= dbus;
  615.       end
  616.    end
  617. end
  618. // OPTION Register
  619. //
  620. // The special OPTION instruction should move W into the OPTION register.
  621. //
  622. parameter OPTION_RESET_VALUE = 8'h3F;
  623. always @(posedge clk) begin
  624.    if (reset) begin
  625.       option <= OPTION_RESET_VALUE;
  626.    end
  627.    else begin
  628.       if (isoption)
  629.          option <= dbus;
  630.    end   
  631. end
  632. // PORTA Input Port   (Register #5)
  633. //
  634. // Register anything on the module's porta input on every single clock.
  635. //
  636. always @(posedge clk)
  637.    if (reset) porta <= 8'h00;
  638.    else       porta <= portain;
  639. // PORTB Output Port  (Register #6)
  640. always @(posedge clk) begin
  641.    if (reset) begin
  642.       portb <= 8'h00;
  643.    end
  644.    else begin
  645.       if (fwe & specialsel & (fileaddr[2:0] == PORTB_ADDRESS) & ~istris) begin
  646.          portb <= dbus;
  647.       end
  648.    end   
  649. end
  650. // Connect the output ports to the register output.
  651. always @(portb)
  652.    portbout = portb;
  653.    
  654. // PORTC Output Port  (Register #7)
  655. always @(posedge clk) begin
  656.    if (reset) begin
  657.       portc <= 8'h00;
  658.    end
  659.    else begin
  660.       if (fwe & specialsel & (fileaddr[2:0] == PORTC_ADDRESS) & ~istris) begin
  661.          portc <= dbus;
  662.       end
  663.    end   
  664. end
  665. // Connect the output ports to the register output.
  666. always @(portc)
  667.    portcout = portc;
  668.  
  669. // TRIS Registers
  670. always @(posedge clk) begin
  671.    if (reset) begin
  672.       trisa <= 8'hff; // Default is to tristate them
  673.    end
  674.    else begin
  675.       if (fwe & specialsel & (fileaddr[2:0] == PORTA_ADDRESS) & istris) begin
  676.          trisa <= dbus;
  677.       end
  678.    end   
  679. end
  680. always @(posedge clk) begin
  681.    if (reset) begin
  682.       trisb <= 8'hff; // Default is to tristate them
  683.    end
  684.    else begin
  685.       if (fwe & specialsel & (fileaddr[2:0] == PORTB_ADDRESS) & istris) begin
  686.          trisb <= dbus;
  687.       end
  688.    end   
  689. end
  690. always @(posedge clk) begin
  691.    if (reset) begin
  692.       trisc <= 8'hff; // Default is to tristate them
  693.    end
  694.    else begin
  695.       if (fwe & specialsel & (fileaddr[2:0] == PORTC_ADDRESS) & istris) begin
  696.          trisc <= dbus;
  697.       end
  698.    end   
  699. end
  700.   
  701. // ********** PC AND STACK *************************
  702. //
  703. // There are 4 ways to change the PC.  They are:
  704. //    GOTO  101k_kkkk_kkkk
  705. //    CALL  1001_kkkk_kkkk
  706. //    RETLW 1000_kkkk_kkkk
  707. //    MOVF  0010_0010_0010  (e.g. a write to reg #2)
  708. //    MOVWF 0000_0010_0010  (write from W to reg #2)
  709. //
  710. // Remember that the skip instructions work by inserting
  711. // a NOP instruction or not into program stream and don't
  712. // change the PC.
  713. //
  714. // Implmenent PC
  715. //
  716. // Seperate the PC_IN input bus into PC from the sequential register so that we
  717. // can feed the PC_IN bus into the PRAM address input.
  718. always @(posedge clk)
  719.    if (reset) pc <= RESET_VECTOR;
  720.    else       pc <= pc_in;
  721. always @(inst or stacklevel or status or stack1 or stack2 or pc or dbus) begin
  722.    casex ({inst, stacklevel}) // synopsys parallel_case
  723.       14'b101?_????_????_??: pc_in = {status[6:5],       inst[8:0]}; // GOTO
  724.       14'b1001_????_????_??: pc_in = {status[6:5], 1'b0, inst[7:0]}; // CALL
  725.       14'b1000_????_????_00: pc_in = stack1; // RETLW
  726.       14'b1000_????_????_01: pc_in = stack1; // RETLW
  727.       14'b1000_????_????_10: pc_in = stack2; // RETLW
  728.       14'b1000_????_????_11: pc_in = stack2; // RETLW
  729.       14'b00?0_0010_0010_??: pc_in = {pc[10:8], dbus}; // MOVF or MOVWF where f=PC
  730.       default:
  731.          pc_in = pc + 1;
  732.    endcase
  733. end
  734. // Implement STACK1 and STACK2 registers
  735. //
  736. // The Stack registers are only fed from the PC itself!
  737. //
  738. always @(posedge clk) begin
  739.    if (reset) begin
  740.       stack1 <= 9'h000;
  741.    end
  742.    else begin
  743.       // CALL instruction
  744.       if (inst[11:8] == 4'b1001) begin
  745.          case (stacklevel) // synopsys parallel_case
  746.             2'b00:
  747.                // No previous CALLs 
  748.                begin
  749.                   stack1 <= pc;
  750.                end
  751.             2'b01:
  752.                // ONE previous CALL 
  753.                begin
  754.                   stack2 <= pc;
  755.                end
  756.             2'b10:
  757.                // TWO previous CALLs -- This is illegal on the 16C5X! 
  758.                begin
  759.                   $display ("Too many CALLs!!");
  760.                end
  761.             2'b11: 
  762.                begin
  763.                   $display ("Too many CALLs!!");
  764.                end
  765.          endcase
  766.       end
  767.    end
  768. end
  769. // Write to stacklevel
  770. //
  771. // The stacklevel register keeps track of the current stack depth.  On this
  772. // puny processor, there are only 2 levels (you could fiddle with this and
  773. // increase the stack depth).  There are two stack registers, stack1 and stack2.
  774. // The stack1 register is used first (e.g. the first time a call is performed),
  775. // then stack2.  As CALLs are done, stacklevel increments.  Conversely, as
  776. // RETs are done, stacklevel goes down. 
  777. always @(posedge clk) begin
  778.    if (reset == 1'b1) begin
  779.       stacklevel <= 2'b00;  // On reset, there should be no CALLs in progress
  780.    end
  781.    else begin
  782.       casex ({inst, stacklevel}) // synopsys parallel_case
  783.          // Call instructions
  784.          14'b1001_????_????_00: stacklevel <= 2'b01;  // Record 1st CALL
  785.          14'b1001_????_????_01: stacklevel <= 2'b10;  // Record 2nd CALL
  786.          14'b1001_????_????_10: stacklevel <= 2'b10;  // Already 2! Ignore
  787.          14'b1001_????_????_11: stacklevel <= 2'b00;  // {shouldn't happen}
  788.          // Return instructions
  789.          14'b1000_????_????_00: stacklevel <= 2'b00;  // {shouldn't happen}
  790.          14'b1000_????_????_01: stacklevel <= 2'b00;  // Go back to no CALL in progress
  791.          14'b1000_????_????_10: stacklevel <= 2'b01;  // Go back to 1 CALL in progress
  792.          14'b1000_????_????_11: stacklevel <= 2'b10;  // {shouldn't happen} sort of like, Go back to 2 calls in progress
  793.          default:
  794.             stacklevel <= stacklevel;
  795.       endcase
  796.    end
  797. end
  798. // *******  Debug Stuff  ******** //
  799. //
  800. // The following is NOT synthesizable.  This code simply allows you to see the ASCII name
  801. // for the instruction in the INST register while in a waveform viewer.
  802. //
  803. // synopsys translate_off
  804. reg [8*8-1:0] inst_string;
  805. always @(inst) begin
  806.    casex (inst)
  807.       12'b0000_0000_0000: inst_string = "NOP     ";
  808.       12'b0000_001X_XXXX: inst_string = "MOVWF   ";
  809.       12'b0000_0100_0000: inst_string = "CLRW    ";
  810.       12'b0000_011X_XXXX: inst_string = "CLRF    ";
  811.       12'b0000_10XX_XXXX: inst_string = "SUBWF   ";
  812.       12'b0000_11XX_XXXX: inst_string = "DECF    ";
  813.       12'b0001_00XX_XXXX: inst_string = "IORWF   ";
  814.       12'b0001_01XX_XXXX: inst_string = "ANDWF   ";
  815.       12'b0001_10XX_XXXX: inst_string = "XORWF   ";
  816.       12'b0001_11XX_XXXX: inst_string = "ADDWF   ";
  817.       12'b0010_00XX_XXXX: inst_string = "MOVF    ";
  818.       12'b0010_01XX_XXXX: inst_string = "COMF    ";
  819.       12'b0010_10XX_XXXX: inst_string = "INCF    ";
  820.       12'b0010_11XX_XXXX: inst_string = "DECFSZ  ";
  821.       12'b0011_00XX_XXXX: inst_string = "RRF     ";
  822.       12'b0011_01XX_XXXX: inst_string = "RLF     ";
  823.       12'b0011_10XX_XXXX: inst_string = "SWAPF   ";
  824.       12'b0011_11XX_XXXX: inst_string = "INCFSZ  ";
  825.       // *** Bit-Oriented File Register Operations
  826.       12'b0100_XXXX_XXXX: inst_string = "BCF     ";
  827.       12'b0101_XXXX_XXXX: inst_string = "BSF     ";
  828.       12'b0110_XXXX_XXXX: inst_string = "BTFSC   ";
  829.       12'b0111_XXXX_XXXX: inst_string = "BTFSS   ";
  830.       // *** Literal and Control Operations
  831.       12'b0000_0000_0010: inst_string = "OPTION  ";
  832.       12'b0000_0000_0011: inst_string = "SLEEP   ";
  833.       12'b0000_0000_0100: inst_string = "CLRWDT  ";
  834.       12'b0000_0000_0101: inst_string = "TRIS    ";
  835.       12'b0000_0000_0110: inst_string = "TRIS    ";
  836.       12'b0000_0000_0111: inst_string = "TRIS    ";
  837.       12'b1000_XXXX_XXXX: inst_string = "RETLW   ";
  838.       12'b1001_XXXX_XXXX: inst_string = "CALL    ";
  839.       12'b101X_XXXX_XXXX: inst_string = "GOTO    ";
  840.       12'b1100_XXXX_XXXX: inst_string = "MOVLW   ";
  841.       12'b1101_XXXX_XXXX: inst_string = "IORLW   ";
  842.       12'b1110_XXXX_XXXX: inst_string = "ANDLW   ";
  843.       12'b1111_XXXX_XXXX: inst_string = "XORLW   ";
  844.       default:            inst_string = "-XXXXXX-";
  845.    endcase
  846. end
  847.    
  848. // synopsys translate_on
  849. endmodule