whitespace
[soc.git] / src / soc / debug / firmware_upload.py
1 """JTAG Wishbone firmware upload program
2
3 to test, run "python3 debug/test/test_jtag_tap_srv.py server"
4
5 """
6
7 import sys
8 from nmigen import (Module, Signal, Elaboratable, Const)
9 from c4m.nmigen.jtag.tap import TAP, IOType
10 from c4m.nmigen.jtag.bus import Interface as JTAGInterface
11 from soc.debug.dmi import DMIInterface, DBGCore, DBGStat, DBGCtrl
12 from soc.debug.test.dmi_sim import dmi_sim
13 from soc.debug.jtag import JTAG
14 from soc.debug.test.jtagremote import JTAGServer, JTAGClient
15
16 from soc.bus.sram import SRAM
17 from nmigen import Memory, Signal, Module
18
19 from nmigen.back.pysim import Simulator, Delay, Settle, Tick
20 from nmutil.util import wrap
21 from soc.debug.jtagutils import (jtag_read_write_reg,
22 jtag_srv, jtag_set_reset,
23 jtag_set_ir, jtag_set_get_dr)
24 from openpower.simulator.program import Program
25
26 def test_pinset():
27 return {
28 # in, out, tri-out, tri-inout
29 'test': ['io0-', 'io1+', 'io2>', 'io3*'],
30 }
31
32 def brev(n, width):
33 b = '{:0{width}b}'.format(n, width=width)
34 return int(b[::-1], 2)
35
36
37 # JTAG-ircodes for accessing DMI
38 DMI_ADDR = 8
39 DMI_READ = 9
40 DMI_WRRD = 10
41
42 # JTAG-ircodes for accessing Wishbone
43 WB_ADDR = 5
44 WB_READ = 6
45 WB_WRRD = 7
46
47
48 def read_dmi_addr(dut, dmi_addr):
49 # write DMI address
50 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, dmi_addr)
51
52 # read DMI register
53 return (yield from jtag_read_write_reg(dut, DMI_READ, 64))
54
55 def writeread_dmi_addr(dut, dmi_addr, data):
56 # write DMI address
57 yield from jtag_read_write_reg(dut, DMI_ADDR, 8, dmi_addr)
58
59 # write and read DMI register
60 return (yield from jtag_read_write_reg(dut, DMI_WRRD, 64, data))
61
62
63 def jtag_sim(dut, firmware):
64 """uploads firmware with the following commands:
65 * read IDcode (to check)
66 * set "stopped" and reset
67 * repeat until confirmed "stopped"
68 * upload data over wishbone
69 * read data back and check it
70 * issue cache flush command
71 * issue "start" command
72 """
73
74 ####### JTAGy stuff (IDCODE) ######
75
76 # read idcode
77 yield from jtag_set_reset(dut)
78 idcode = yield from jtag_read_write_reg(dut, 0b1, 32)
79 print ("idcode", hex(idcode))
80 assert idcode == 0x18ff
81
82 ####### JTAG to DMI Setup (stop, reset) ######
83
84 yield from read_dmi_addr(dut, DBGCore.CTRL)
85 # read DMI CTRL reg
86 status = yield from read_dmi_addr(dut, DBGCore.CTRL)
87 print ("dmi ctrl status", bin(status))
88
89 # write DMI CTRL register - STOP and RESET
90 status = yield from writeread_dmi_addr(dut, DBGCore.CTRL,
91 (1<<DBGCtrl.STOP) |
92 (1<<DBGCtrl.RESET))
93 print ("dmi ctrl status", hex(status))
94 assert status == 0 # returned old value (nice! cool feature!)
95
96 # read STAT and wait for "STOPPED"
97 while True:
98 status = yield from read_dmi_addr(dut, DBGCore.STAT)
99 print ("dmi ctrl status", bin(status))
100 if (status & (1<<DBGStat.STOPPED)) or (status & (1<<DBGStat.TERM)):
101 break
102
103 ####### JTAG to Wishbone - hard-coded 30-bit addr, 32-bit data ######
104
105 # write Wishbone address
106 yield from jtag_read_write_reg(dut, WB_ADDR, 30, 0)
107
108 # write/read wishbone data
109 for val in firmware:
110 data = yield from jtag_read_write_reg(dut, WB_WRRD, 32, val)
111 print ("wb write", hex(val), hex(data))
112
113 # write Wishbone address
114 yield from jtag_read_write_reg(dut, WB_ADDR, 30, 0)
115
116 # confirm data written
117 for val in firmware:
118 data = yield from jtag_read_write_reg(dut, WB_READ, 32, val)
119 print ("wb read", hex(val), hex(data))
120
121 ####### JTAG to DMI Setup (IC-Reset, start) ######
122
123 # write DMI CTRL register - ICRESET
124 status = yield from writeread_dmi_addr(dut, DBGCore.CTRL,
125 1<<DBGCtrl.ICRESET)
126 print ("dmi ctrl status", hex(status))
127
128 # write DMI CTRL register - START
129 status = yield from writeread_dmi_addr(dut, DBGCore.CTRL,
130 1<<DBGCtrl.START)
131 print ("dmi ctrl status", hex(status))
132
133 # read STAT just for info
134 for i in range(4):
135 status = yield from read_dmi_addr(dut, DBGCore.STAT)
136 print ("dmi stat status", bin(status))
137
138 ####### done - tell dmi_sim to stop (otherwise it won't) ########
139
140 print ("jtag sim stopping")
141
142
143 if __name__ == '__main__':
144 # rather than the client access the JTAG bus directly
145 # create an alternative that the client sets
146 class Dummy: pass
147 cdut = Dummy()
148 cdut.cbus = JTAGInterface()
149
150 # set up client-server on port 44843-something
151 cdut.c = JTAGClient()
152
153 # take copy of ir_width and scan_len
154 cdut._ir_width = 4
155
156 flag = Signal()
157 m = Module()
158 m.d.sync += flag.eq(~flag) # get us a "sync" domain
159
160 sim = Simulator(m)
161 sim.add_clock(1e-6, domain="sync") # standard clock
162
163 # blinken lights...
164 lst = """
165 blink:
166 li 3, 0
167 lis 4, 1234
168 lis 5, 5678
169 .LBB0_1:
170 std 3, 6780(4)
171 mtctr 5
172 .LBB0_2:
173 bdnz .LBB0_2
174 xori 3, 3, 1
175 b .LBB0_1
176 """
177 # simple loop
178 lst = ["addi 9, 0, 0x10", # i = 16
179 "addi 9,9,-1", # i = i - 1
180 "cmpi 2,1,9,12", # compare 9 to value 12, store in CR2
181 "bc 4,10,-16", # branch if CR2 "test was != 12"
182 'attn',
183 ]
184
185 data = []
186 with Program(lst, False) as p:
187 data = list(p.generate_instructions())
188 for instruction in data:
189 print (hex(instruction))
190
191 sim.add_sync_process(wrap(jtag_sim(cdut, data)))
192
193 with sim.write_vcd("jtag_firmware_upload.vcd"):
194 sim.run()