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

Subversion Repositories bluespec_md6

[/] [bluespec_md6/] [trunk/] [lib/] [bsv/] [SPI/] [src/] [SPIMaster.bsv] - Blame information for rev 7

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 kfleming
import FIFO::*;
2
import ClientServer::*;
3
import GetPut::*;
4
import Clocks::*;
5
 
6
import RegisterMapper::*;
7
import FIFOUtility::*;
8
import Debug::*;
9
 
10
Bool spiMasterDebug = False;
11
 
12
 
13
 
14
/* This module implements the SPI bus, a simple protocol. */
15
typedef struct {
16
  Bit#(TLog#(slaves))  slave;
17
  data_t               data;
18
} SPIMasterRequest#( numeric type slaves,
19
                     type data_t) deriving (Bits,Eq);
20
 
21
interface SPIMasterWires#(numeric type slaves);
22
 (* always_ready, always_enabled, prefix="", result="spi_slave_enable" *)
23
  method Bit#(slaves) slaveEnables();
24
 (* always_ready, always_enabled, result="spi_output_line" *)
25
  method Bit#(1) outputLine();
26
 (* always_ready, always_enabled, result="spi_input_line" *)
27
  method Action inputLine(Bit#(1) dataIn);
28
  interface Clock clock;
29
endinterface
30
 
31
interface SPIMaster#(numeric type slaves, type data);
32
  interface Server#(SPIMasterRequest#(slaves,data),data) server;
33
  interface SPIMasterWires#(slaves) wires;
34
endinterface
35
 
36
  typedef enum {
37
    Idle,
38
    ClockWait,
39
    Data,
40
    Cleanup
41
  } SPIState deriving (Bits,Eq);
42
 
43
 
44
//Need to chop
45
 
46
module mkSPIMaster#(Integer divisor) (SPIMaster#(slaves,data_t))
47
  provisos (Bits#(data_t,data_sz),
48
            Add#(1, TLog#(data_sz), TAdd#(1, TLog#(data_sz)))
49
            );
50
 
51
  Clock clock <- exposeCurrentClock;
52
  Reset reset <- exposeCurrentReset;
53
 
54
  if(divisor < 2)
55
    begin
56
      error("divisor must be at least 2");
57
    end
58
 
59
  ClockDividerIfc spiClock <- mkClockDivider(divisor);
60
  ClockDividerIfc toggleClock <- mkClockDivider(divisor/2);
61
 
62
  Reset toggleReset <- mkAsyncReset(1,reset,toggleClock.slowClock);  // is this right?
63
  Reset spiReset <- mkAsyncReset(1,reset,spiClock.slowClock);  // is this right?
64
 
65
  // This could be disasterous, if we up clock during the high edge of the gated clock.  toggle reg should prevent this
66
  GatedClockIfc gatedSlowClock <- mkGatedClock(False,spiClock.slowClock, clocked_by toggleClock.slowClock, reset_by toggleReset);
67
 
68
  SyncFIFOIfc#(SPIMasterRequest#(slaves, data_t)) infifo <- mkSyncFIFOToSlow(2,toggleClock,toggleReset);
69
  SyncFIFOIfc#(data_t) outfifo <- mkSyncFIFOToFast(2,toggleClock,toggleReset);
70
 
71
  Reg#(Bit#(TLog#(data_sz))) dataCount <- mkRegA(0,clocked_by toggleClock.slowClock,
72
                                                 reset_by toggleReset);
73
  Reg#(SPIState) state <- mkRegA(Idle, clocked_by toggleClock.slowClock,
74
                                                 reset_by toggleReset);
75
 
76
  Reg#(Bit#(data_sz)) data <- mkRegU(clocked_by toggleClock.slowClock,
77
                                                 reset_by toggleReset);
78
 
79
  // toggle may not be quite right.
80
  Reg#(Bool) toggle <- mkReg(False, clocked_by toggleClock.slowClock, reset_by toggleReset); // this reg makes sure the we are in-phase with the low edge of spiClock
81
 
82
 
83
  Reg#(Bit#(slaves)) enableReg <- mkReg(~0, clocked_by toggleClock.slowClock, reset_by toggleReset);
84
  ReadOnly#(Bit#(slaves)) enableCrossing <- mkNullCrossingWire(spiClock.slowClock,enableReg._read, clocked_by toggleClock.slowClock, reset_by toggleReset);
85
 
86
  Reg#(Bit#(1))      outputReg <- mkReg(~0, clocked_by toggleClock.slowClock, reset_by toggleReset);
87
  ReadOnly#(Bit#(1)) outputCrossing <- mkNullCrossingWire(spiClock.slowClock, outputReg._read, clocked_by toggleClock.slowClock, reset_by toggleReset);
88
 
89
//XXX fix me
90
//  Reg#(Bit#(1)) inputReg <- mkReg(0,clocked_by spiClock.slowClock, reset_by spiReset);
91
//  ReadOnly#(Bit#(1)) outputCrossing <- mkNullCrossingWire(spiClock.slowClock, inputReg.read, clocked_by spiClock.slowClock, reset_by spiReset);
92
 
93
  Bit#(TAdd#(1,TLog#(data_sz))) dataPlus = zeroExtend(dataCount) + 1;
94
 
95
  // treat the top bit of ticks per transfer as the serial clock
96
  // We do a state transition on serial clock  1->0 to ensure signal stability in the slave.
97
 
98
  rule toggleTick;
99
    toggle <= !toggle;
100
  endrule
101
 
102
  rule setup(state == Idle && infifo.notEmpty && toggle);
103
    debug(spiMasterDebug,$display("SPIMaster Setup called data: %b slave: %d",infifo.first.data ,infifo.first.slave ));
104
    gatedSlowClock.setGateCond(True);
105
    state <= Data;
106
    enableReg <= ~(1<<(infifo.first.slave));
107
    debug(spiMasterDebug,$display("SPIMaster sending setupWait:  %h", pack(infifo.first.data)[dataCount]));
108
    outputReg <= (pack(infifo.first.data)[dataCount]);
109
  endrule
110
 
111
 
112
  rule cleanup(state == Cleanup && toggle);
113
    outfifo.enq(unpack(data));
114
    state <= Idle;
115
    enableReg <= ~0;
116
  endrule
117
 
118
 
119
  rule handleData(state == Data && toggle);
120
    debug(spiMasterDebug,$display("SPIMaster Data  called"));
121
    if(dataPlus == fromInteger(valueof(data_sz)))
122
      begin
123
        debug(spiMasterDebug,$display("SPIMaster transfer done"));
124
        dataCount <= 0;
125
        infifo.deq;
126
        state <= Cleanup;
127
        gatedSlowClock.setGateCond(False); // may be too early
128
      end
129
    else
130
      begin
131
        dataCount <= truncate(dataPlus);
132
      end
133
 
134
 
135
    Bit#(TLog#(data_sz)) dataIndex = truncate(dataPlus);
136
    outputReg <= pack(infifo.first.data)[dataIndex];
137
    debug(spiMasterDebug,$display("SPIMaster sending:  %h", pack(infifo.first.data)[dataIndex]));
138
  //  data[dataCount] <= fromMaybe(0,inputWire.wget);
139
  endrule
140
 
141
  interface Server server;
142
    interface Put request = syncFifoToPut(infifo);
143
    interface Get response = syncFifoToGet(outfifo);
144
  endinterface
145
 
146
interface SPIMasterWires wires;
147
  //method slaveEnables = enableCrossing._read;
148
  //method outputLine = outputCrossing._read;
149
 
150
  method Bit#(slaves) slaveEnables();
151
    return enableCrossing._read;
152
  endmethod
153
 
154
  method Bit#(1) outputLine();
155
    return outputCrossing._read;
156
  endmethod
157
 
158
  method Action inputLine(Bit#(1) dataIn);
159
//    inputWire.wset(dataIn);
160
  endmethod
161
 
162
  interface clock = gatedSlowClock.new_clk;
163
endinterface
164
 
165
endmodule
166
 

powered by: WebSVN 2.1.0

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