1 |
74 |
ja_rd |
0001 0000 ;*******************************************************************************
|
2 |
|
|
0002 0000 ; soc_tb.asm -- light8080 SoC basic test bench.
|
3 |
|
|
0003 0000 ;*******************************************************************************
|
4 |
|
|
0004 0000 ; Should be used with SoC core test bench entity vhdl\test\l80soc_tb.vhdl.
|
5 |
|
|
0005 0000 ; Assembler format compatible with TASM for DOS and Linux.
|
6 |
|
|
0006 0000 ;*******************************************************************************
|
7 |
|
|
0007 0000 ; This program will send a few bytes over a looped-back UART, using the UART
|
8 |
|
|
0008 0000 ; interrupt capability and verifying that received and transmitted data match.
|
9 |
|
|
0009 0000 ; It will then try one of the external interrupts, connected to one of the
|
10 |
|
|
0010 0000 ; general purpose outputs.
|
11 |
|
|
0011 0000 ; This minimal test bench relies on an already tested CPU core to do a
|
12 |
|
|
0012 0000 ; This program does not deserve to even be called a 'test' but if if works it
|
13 |
|
|
0013 0000 ; will at least rule out many obvious bug in the SoC core.
|
14 |
|
|
0014 0000 ;*******************************************************************************
|
15 |
|
|
0015 0000
|
16 |
|
|
0016 0000 ; DS pseudo-directive; reserve space in bytes, without initializing it
|
17 |
|
|
0017 0000 #define ds(n) \.org $+n
|
18 |
|
|
0018 0000
|
19 |
|
|
0019 0000 MASK_RX_IRQ: .equ 20h
|
20 |
|
|
0020 0000 MASK_TX_IRQ: .equ 10h
|
21 |
|
|
0021 0000 MASK_RX_RDY: .equ 02h
|
22 |
|
|
0022 0000 MASK_TX_RDY: .equ 01h
|
23 |
|
|
0023 0000
|
24 |
|
|
0024 0000 UART_DATA: .equ 80h
|
25 |
|
|
0025 0000 UART_STATUS: .equ 81h
|
26 |
|
|
0026 0000 UART_BAUDL: .equ 82h
|
27 |
|
|
0027 0000 UART_BAUDH: .equ 83h
|
28 |
|
|
0028 0000 IRQ_ENABLE: .equ 88h
|
29 |
|
|
0029 0000
|
30 |
|
|
0030 0000 P1IN: .equ 84h
|
31 |
|
|
0031 0000 P2OUT: .equ 86h
|
32 |
|
|
0032 0000
|
33 |
|
|
0033 0000
|
34 |
|
|
0034 0000 ;*******************************************************************************
|
35 |
|
|
0035 0000
|
36 |
|
|
0036 0000 .org 0H ; Reset entry point
|
37 |
|
|
0037 0000 C3 60 00 jmp start ; Skip the rst address area
|
38 |
|
|
0038 0003
|
39 |
|
|
0039 0003 ;***** Interrupt vectors in area 0008h-0038h *****************
|
40 |
|
|
0040 0003
|
41 |
|
|
0041 0008 .org 0h+(1*8) ; interrupt vector 1 (IRQ0)
|
42 |
|
|
0042 0008 C3 12 01 jmp isr0
|
43 |
|
|
0043 0010 .org 0h+(2*8) ; interrupt vector 2
|
44 |
|
|
0044 0010 FB ei
|
45 |
|
|
0045 0011 C9 ret
|
46 |
|
|
0046 0018 .org 0h+(3*8) ; interrupt vector 3 (IRQ1)
|
47 |
|
|
0047 0018 C3 1E 01 jmp isr1
|
48 |
|
|
0048 0020 .org 0h+(4*8) ; interrupt vector 4
|
49 |
|
|
0049 0020 FB ei
|
50 |
|
|
0050 0021 C9 ret
|
51 |
|
|
0051 0028 .org 0h+(5*8) ; interrupt vector 5 (IRQ2)
|
52 |
|
|
0052 0028 FB ei
|
53 |
|
|
0053 0029 C9 ret
|
54 |
|
|
0054 0030 .org 0h+(6*8) ; interrupt vector 6
|
55 |
|
|
0055 0030 FB ei
|
56 |
|
|
0056 0031 C9 ret
|
57 |
|
|
0057 0032
|
58 |
|
|
0058 0038 .org 0h+(7*8) ; interrupt vector 7 (IRQ3, UART)
|
59 |
|
|
0059 0038 C3 2A 01 int38h: jmp irq_uart ; UART interrupt
|
60 |
|
|
0060 003B
|
61 |
|
|
0061 003B ;***** program entry point *******************************************
|
62 |
|
|
0062 003B
|
63 |
|
|
0063 0060 start: .org 60H
|
64 |
|
|
0064 0060 31 DA 01 lxi sp,stack
|
65 |
|
|
0065 0063
|
66 |
|
|
0066 0063 ; Initialize UART RX and TX buffers
|
67 |
|
|
0067 0063 21 74 01 lxi h,void_buffer
|
68 |
|
|
0068 0066 22 75 01 shld ptr_tx
|
69 |
|
|
0069 0069 21 7A 01 lxi h,rx_buffer
|
70 |
|
|
0070 006C 22 77 01 shld ptr_rx
|
71 |
|
|
0071 006F 3E 00 mvi a,00h
|
72 |
|
|
0072 0071 32 79 01 sta len_rx
|
73 |
|
|
0073 0074
|
74 |
|
|
0074 0074 ; Clear all P2 output lines (used to simulate external interrupts)
|
75 |
|
|
0075 0074 3E 00 mvi a,00h
|
76 |
|
|
0076 0076 D3 86 out P2OUT
|
77 |
|
|
0077 0078
|
78 |
|
|
0078 0078 ; Set up interrupts
|
79 |
|
|
0079 0078 3E 0B mvi a,0bh ; Enable UART irq plus IRQ0 and IRQ1...
|
80 |
|
|
0080 007A D3 88 out IRQ_ENABLE
|
81 |
|
|
0081 007C FB ei ; ...and enable interrupts in the CPU
|
82 |
|
|
0082 007D
|
83 |
|
|
0083 007D ; print hello message to console
|
84 |
|
|
0084 007D 21 02 01 lxi h,msg_hello
|
85 |
|
|
0085 0080 CD 66 01 call print_string
|
86 |
|
|
0086 0083 ; Ok, now the message is being transferred through the looped back
|
87 |
|
|
0087 0083 ; UART, using the UART interrupts, which have the lowest priority.
|
88 |
|
|
0088 0083 ; We have plenty of time to make a few tests on the external interrupt
|
89 |
|
|
0089 0083 ; lines before the message transmission is finished.
|
90 |
|
|
0090 0083
|
91 |
|
|
0091 0083 ; The irq routines will leave some data at 'irq_data, each routine a
|
92 |
|
|
0092 0083 ; different value and all non-zero. This is how we know what irq
|
93 |
|
|
0093 0083 ; routines have executed and in which order.
|
94 |
|
|
0094 0083
|
95 |
|
|
0095 0083 ; Test IRQ0 alone
|
96 |
|
|
0096 0083 3E 01 mvi a,01h ; Initialize irq data
|
97 |
|
|
0097 0085 32 73 01 sta irq_data
|
98 |
|
|
0098 0088 3E 01 mvi a,01h ; Trigger IRQ0
|
99 |
|
|
0099 008A D3 86 out P2OUT
|
100 |
|
|
0100 008C test_irq0:
|
101 |
|
|
0101 008C 3A 73 01 lda irq_data
|
102 |
|
|
0102 008F FE 04 cpi 004h ; Do we see the IRQ test data?
|
103 |
|
|
0103 0091 CA 9C 00 jz done_irq0 ; If we do, proceed to next test
|
104 |
|
|
0104 0094 FE 01 cpi 001h ; Do we see some other IRQ test data instead?
|
105 |
|
|
0105 0096 C2 FB 00 jnz test_fail ; If we do, there's trouble with the irqs
|
106 |
|
|
0106 0099 C3 8C 00 jmp test_irq0 ; Keep waiting for some IRQ test data
|
107 |
|
|
0107 009C done_irq0:
|
108 |
|
|
0108 009C 3E 00 mvi a,00h ; Deassert all interrupt lines
|
109 |
|
|
0109 009E D3 86 out P2OUT
|
110 |
|
|
0110 00A0
|
111 |
|
|
0111 00A0 ; Test IRQ1 alone
|
112 |
|
|
0112 00A0 3E 01 mvi a,01h ; Initialize irq data
|
113 |
|
|
0113 00A2 32 73 01 sta irq_data
|
114 |
|
|
0114 00A5 3E 02 mvi a,02h ; Trigger IRQ1
|
115 |
|
|
0115 00A7 D3 86 out P2OUT
|
116 |
|
|
0116 00A9 test_irq1:
|
117 |
|
|
0117 00A9 3A 73 01 lda irq_data
|
118 |
|
|
0118 00AC FE 02 cpi 002h ; Do we see the IRQ test data?
|
119 |
|
|
0119 00AE CA B9 00 jz done_irq1 ; If we do, proceed to next test
|
120 |
|
|
0120 00B1 FE 01 cpi 001h ; Do we see some other IRQ test data instead?
|
121 |
|
|
0121 00B3 C2 FB 00 jnz test_fail ; If we do, there's trouble with the irqs
|
122 |
|
|
0122 00B6 C3 A9 00 jmp test_irq1 ; Keep waiting for some IRQ test data
|
123 |
|
|
0123 00B9 done_irq1:
|
124 |
|
|
0124 00B9 AF xra a ; Deassert all interrupt lines
|
125 |
|
|
0125 00BA D3 86 out P2OUT
|
126 |
|
|
0126 00BC
|
127 |
|
|
0127 00BC ; Test IRQ0 and IRQ1 simultaneously
|
128 |
|
|
0128 00BC 3E 01 mvi a,01h ; Initialize irq data
|
129 |
|
|
0129 00BE 32 73 01 sta irq_data
|
130 |
|
|
0130 00C1 3E 03 mvi a,03h ; Trigger IRQ0 and IRQ1
|
131 |
|
|
0131 00C3 D3 86 out P2OUT
|
132 |
|
|
0132 00C5
|
133 |
|
|
0133 00C5 ; Sequence IRQ0->IRQ1 will result in (1 << 2) + 1 = 5
|
134 |
|
|
0134 00C5 ; Sequence IRQ1->IRQ0 would result in (1 + 1) << 2 = 6
|
135 |
|
|
0135 00C5 ; We expect IRQ0->IRQ1, since IRQ0 has higher priority
|
136 |
|
|
0136 00C5 test_irq01:
|
137 |
|
|
0137 00C5 3A 73 01 lda irq_data
|
138 |
|
|
0138 00C8 FE 05 cpi 005h ; Do we see the IRQ0->IRQ1 test data?
|
139 |
|
|
0139 00CA CA D5 00 jz done_irq01 ; If we do, proceed to next test
|
140 |
|
|
0140 00CD FE 01 cpi 001h ; Do we see some other IRQ test data instead?
|
141 |
|
|
0141 00CF C2 FB 00 jnz test_fail ; If we do, there's trouble with the irqs
|
142 |
|
|
0142 00D2 C3 C5 00 jmp test_irq01 ; Keep waiting for some IRQ test data
|
143 |
|
|
0143 00D5 done_irq01:
|
144 |
|
|
0144 00D5 AF xra a ; Deassert all interrupt lines
|
145 |
|
|
0145 00D6 D3 86 out P2OUT
|
146 |
|
|
0146 00D8
|
147 |
|
|
0147 00D8 ; Ok, the external interrupts have been tested (well, 'tested'). Now
|
148 |
|
|
0148 00D8 ; wait for the UART looped-back transmission to end and compare
|
149 |
|
|
0149 00D8 ; the data.
|
150 |
|
|
0150 00D8
|
151 |
|
|
0151 00D8 ; Wait until the number of UART received characters equals the length
|
152 |
|
|
0152 00D8 ; of the test message.
|
153 |
|
|
0153 00D8 wait_for_message:
|
154 |
|
|
0154 00D8 3A 79 01 lda len_rx
|
155 |
|
|
0155 00DB FE 0F cpi msg_len
|
156 |
|
|
0156 00DD C2 D8 00 jnz wait_for_message
|
157 |
|
|
0157 00E0
|
158 |
|
|
0158 00E0 ; Compare the TX and RX strings
|
159 |
|
|
0159 00E0 21 7A 01 lxi h,rx_buffer
|
160 |
|
|
0160 00E3 11 02 01 lxi d,msg_hello
|
161 |
|
|
0161 00E6 compare_loop:
|
162 |
|
|
0162 00E6 1A ldax d
|
163 |
|
|
0163 00E7 FE 24 cpi '$'
|
164 |
|
|
0164 00E9 CA F5 00 jz test_ok
|
165 |
|
|
0165 00EC BE cmp m
|
166 |
|
|
0166 00ED C2 FB 00 jnz test_fail
|
167 |
|
|
0167 00F0 23 inx h
|
168 |
|
|
0168 00F1 13 inx d
|
169 |
|
|
0169 00F2 C3 E6 00 jmp compare_loop
|
170 |
|
|
0170 00F5
|
171 |
|
|
0171 00F5
|
172 |
|
|
0172 00F5
|
173 |
|
|
0173 00F5
|
174 |
|
|
0174 00F5
|
175 |
|
|
0175 00F5 test_ok:
|
176 |
|
|
0176 00F5 3E 80 mvi a,80h ; Raise 'success' output flag...
|
177 |
|
|
0177 00F7 D3 86 out P2OUT
|
178 |
|
|
0178 00F9 F3 done: di ; ...and block here.
|
179 |
|
|
0179 00FA 76 hlt
|
180 |
|
|
0180 00FB
|
181 |
|
|
0181 00FB test_fail:
|
182 |
|
|
0182 00FB 3E 40 mvi a,40h ; Raise 'failure' flag...
|
183 |
|
|
0183 00FD D3 86 out P2OUT
|
184 |
|
|
0184 00FF C3 F9 00 jmp done ; ...and block.
|
185 |
|
|
0185 0102
|
186 |
|
|
0186 0102
|
187 |
|
|
0187 0102
|
188 |
|
|
0188 0102 0A 0D 0A 48 msg_hello: .text "\n\r\nHello World!$"
|
189 |
|
|
0188 0106 65 6C 6C 6F
|
190 |
|
|
0188 010A 20 57 6F 72
|
191 |
|
|
0188 010E 6C 64 21 24
|
192 |
|
|
0189 0112 msg_end: .equ $
|
193 |
|
|
0190 0112 msg_len: .equ msg_end - msg_hello - 1
|
194 |
|
|
0191 0112
|
195 |
|
|
0192 0112 F5 isr0: push psw
|
196 |
|
|
0193 0113 3A 73 01 lda irq_data
|
197 |
|
|
0194 0116 07 rlc
|
198 |
|
|
0195 0117 07 rlc
|
199 |
|
|
0196 0118 32 73 01 sta irq_data
|
200 |
|
|
0197 011B F1 pop psw
|
201 |
|
|
0198 011C FB ei
|
202 |
|
|
0199 011D C9 ret
|
203 |
|
|
0200 011E
|
204 |
|
|
0201 011E F5 isr1: push psw
|
205 |
|
|
0202 011F 3A 73 01 lda irq_data
|
206 |
|
|
0203 0122 C6 01 adi 1
|
207 |
|
|
0204 0124 32 73 01 sta irq_data
|
208 |
|
|
0205 0127 F1 pop psw
|
209 |
|
|
0206 0128 FB ei
|
210 |
|
|
0207 0129 C9 ret
|
211 |
|
|
0208 012A
|
212 |
|
|
0209 012A ;irq_uart: UART interrupt processing
|
213 |
|
|
0210 012A irq_uart:
|
214 |
|
|
0211 012A E5 push h
|
215 |
|
|
0212 012B F5 push psw
|
216 |
|
|
0213 012C
|
217 |
|
|
0214 012C ; Deal with RX interrupt (if any) first and then the TX interrupt.
|
218 |
|
|
0215 012C DB 81 in UART_STATUS ; Is there new data in the RX register?
|
219 |
|
|
0216 012E E6 20 ani MASK_RX_IRQ
|
220 |
|
|
0217 0130 CA 48 01 jz irq_uart_rx_done ; If there isn't, process TX interrupt.
|
221 |
|
|
0218 0133
|
222 |
|
|
0219 0133 ; Process UART RX interrupt
|
223 |
|
|
0220 0133 irq_uart_rx:
|
224 |
|
|
0221 0133 3E 20 mvi a,MASK_RX_IRQ ; Clear IRQ flag.
|
225 |
|
|
0222 0135 D3 81 out UART_STATUS
|
226 |
|
|
0223 0137 DB 80 in UART_DATA ; Get RX byte...
|
227 |
|
|
0224 0139 2A 77 01 lhld ptr_rx ; ...and store it in the rx buffer.
|
228 |
|
|
0225 013C 77 mov m,a
|
229 |
|
|
0226 013D 23 inx h
|
230 |
|
|
0227 013E 22 77 01 shld ptr_rx ; Update the rx buffer pointer.
|
231 |
|
|
0228 0141 3A 79 01 lda len_rx ; Update RX buffer length
|
232 |
|
|
0229 0144 3C inr a
|
233 |
|
|
0230 0145 32 79 01 sta len_rx
|
234 |
|
|
0231 0148
|
235 |
|
|
0232 0148 ; Note there's no check for RX buffer overrun! we shouldn't need it
|
236 |
|
|
0233 0148 ; here, a runaway condition would be readily apparent in the
|
237 |
|
|
0234 0148 ; simulation, anyway.
|
238 |
|
|
0235 0148
|
239 |
|
|
0236 0148 irq_uart_rx_done:
|
240 |
|
|
0237 0148 ; Ok, RX is done. Now deal with TX irq, if any
|
241 |
|
|
0238 0148 DB 81 in UART_STATUS ; Is the TX buffer re new data in the RX register?
|
242 |
|
|
0239 014A E6 10 ani MASK_TX_IRQ
|
243 |
|
|
0240 014C CA 62 01 jz irq_uart_end ; If there isn't, we're done.
|
244 |
|
|
0241 014F
|
245 |
|
|
0242 014F ; process UART TX interrupt
|
246 |
|
|
0243 014F irq_uart_tx:
|
247 |
|
|
0244 014F 3E 10 mvi a,MASK_TX_IRQ ; Clear IRQ flag.
|
248 |
|
|
0245 0151 D3 81 out UART_STATUS
|
249 |
|
|
0246 0153 2A 75 01 lhld ptr_tx ; Get next byte from the TX buffer
|
250 |
|
|
0247 0156 7E mov a,m
|
251 |
|
|
0248 0157 FE 24 cpi '$' ; Did we reach the end of the buffer?
|
252 |
|
|
0249 0159 CA 62 01 jz irq_uart_tx_done ; If we did, we're done here...
|
253 |
|
|
0250 015C 23 inx h ; ...otherwise increment the TX pointer...
|
254 |
|
|
0251 015D 22 75 01 shld ptr_tx
|
255 |
|
|
0252 0160 D3 80 out UART_DATA ; ...and transmit the data byte.
|
256 |
|
|
0253 0162
|
257 |
|
|
0254 0162 irq_uart_tx_done:
|
258 |
|
|
0255 0162
|
259 |
|
|
0256 0162 irq_uart_end:
|
260 |
|
|
0257 0162 F1 pop psw ; Done, quit.
|
261 |
|
|
0258 0163 E1 pop h
|
262 |
|
|
0259 0164 FB ei
|
263 |
|
|
0260 0165 C9 ret
|
264 |
|
|
0261 0166
|
265 |
|
|
0262 0166 ;print_string: print $-terminated string at HL
|
266 |
|
|
0263 0166 print_string:
|
267 |
|
|
0264 0166 ; We don't check if there's a transmission going on
|
268 |
|
|
0265 0166 7E mov a,m ; Get first character from string...
|
269 |
|
|
0266 0167 23 inx h ; ...and move updated string pointer to TX
|
270 |
|
|
0267 0168 22 75 01 shld ptr_tx ; buffer pointer.
|
271 |
|
|
0268 016B FE 24 cpi '$' ; Kickstart transmission by sending 1st byte...
|
272 |
|
|
0269 016D CA 72 01 jz print_string_end; ...unless its the end of string marker.
|
273 |
|
|
0270 0170 D3 80 out UART_DATA ;
|
274 |
|
|
0271 0172 print_string_end:
|
275 |
|
|
0272 0172 C9 ret
|
276 |
|
|
0273 0173
|
277 |
|
|
0274 0173
|
278 |
|
|
0275 0173 ; data space, placed immediately after object code in memory
|
279 |
|
|
0276 0173 irq_data: ds(1)
|
280 |
|
|
0276 0174
|
281 |
|
|
0277 0174 24 void_buffer: .text "$"
|
282 |
|
|
0278 0175 ptr_tx: ds(2)
|
283 |
|
|
0278 0177
|
284 |
|
|
0279 0177 ptr_rx: ds(2)
|
285 |
|
|
0279 0179
|
286 |
|
|
0280 0179 len_rx: ds(1)
|
287 |
|
|
0280 017A
|
288 |
|
|
0281 017A rx_buffer: ds(32)
|
289 |
|
|
0281 019A
|
290 |
|
|
0282 019A ds(64)
|
291 |
|
|
0282 01DA
|
292 |
|
|
0283 01DA stack: ds(2)
|
293 |
|
|
0283 01DC
|
294 |
|
|
0284 01DC .end
|
295 |
|
|
0285 01DC tasm: Number of errors = 0
|