|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68000 emulation
5: *
6: * Copyright 1995 Bernd Schmidt
7: */
8:
9: #ifndef NEWCPU_H
10: #define NEWCPU_H
11:
1.1.1.4 ! root 12: #include "options_cpu.h"
! 13:
1.1 root 14: #include "readcpu.h"
15: //#include "machdep/m68k.h"
16: #include "m68k.h"
17: #include "compat.h"
18: #include "maccess.h"
19: #include "events.h"
20: #include "memory.h"
21: #include "custom.h"
22:
23: /* Possible exceptions sources for M68000_Exception() and Exception() */
24: #define M68000_EXC_SRC_CPU 1 /* Direct CPU exception */
25: #define M68000_EXC_SRC_AUTOVEC 2 /* Auto-vector exception (e.g. VBL) */
26: #define M68000_EXC_SRC_INT_MFP 3 /* MFP interrupt exception */
27: #define M68000_EXC_SRC_INT_DSP 4 /* DSP interrupt exception */
28:
29:
30: /* Special flags */
31: #define SPCFLAG_DEBUGGER 1
32: #define SPCFLAG_STOP 2
33: #define SPCFLAG_BUSERROR 4
34: #define SPCFLAG_INT 8
35: #define SPCFLAG_BRK 0x10
36: #define SPCFLAG_EXTRA_CYCLES 0x20
37: #define SPCFLAG_TRACE 0x40
38: #define SPCFLAG_DOTRACE 0x80
39: #define SPCFLAG_DOINT 0x100
40: #define SPCFLAG_MFP 0x200
41: #define SPCFLAG_EXEC 0x400
42: #define SPCFLAG_MODE_CHANGE 0x800
43:
44:
45: #ifndef SET_CFLG
46:
47: #define SET_CFLG(x) (CFLG() = (x))
48: #define SET_NFLG(x) (NFLG() = (x))
49: #define SET_VFLG(x) (VFLG() = (x))
50: #define SET_ZFLG(x) (ZFLG() = (x))
51: #define SET_XFLG(x) (XFLG() = (x))
52:
53: #define GET_CFLG() CFLG()
54: #define GET_NFLG() NFLG()
55: #define GET_VFLG() VFLG()
56: #define GET_ZFLG() ZFLG()
57: #define GET_XFLG() XFLG()
58:
59: #define CLEAR_CZNV() do { \
60: SET_CFLG (0); \
61: SET_ZFLG (0); \
62: SET_NFLG (0); \
63: SET_VFLG (0); \
64: } while (0)
65:
66: #define COPY_CARRY() (SET_XFLG (GET_CFLG ()))
67: #endif
68:
69: extern const int areg_byteinc[];
70: extern const int imm8_table[];
71:
72: extern int movem_index1[256];
73: extern int movem_index2[256];
74: extern int movem_next[256];
75:
76: #ifdef FPUEMU
77: extern int fpp_movem_index1[256];
78: extern int fpp_movem_index2[256];
79: extern int fpp_movem_next[256];
80: #endif
81:
82: extern int OpcodeFamily;
83:
1.1.1.4 ! root 84: typedef uae_u32 REGPARAM3 cpuop_func (uae_u32) REGPARAM;
1.1 root 85: typedef void REGPARAM3 cpuop_func_ce (uae_u32) REGPARAM;
86:
87: struct cputbl {
88: cpuop_func *handler;
89: uae_u16 opcode;
90: };
91:
92: #ifdef JIT
1.1.1.4 ! root 93: typedef uae_u32 REGPARAM3 compop_func (uae_u32) REGPARAM;
1.1 root 94:
95: struct comptbl {
96: compop_func *handler;
97: uae_u32 opcode;
98: int specific;
99: };
100: #endif
101:
1.1.1.4 ! root 102: extern uae_u32 REGPARAM3 op_illg (uae_u32) REGPARAM;
! 103: extern void REGPARAM3 op_unimpl (uae_u16) REGPARAM;
1.1 root 104:
105: typedef uae_u8 flagtype;
106:
107: #ifdef FPUEMU
108: /* You can set this to long double to be more accurate. However, the
109: resulting alignment issues will cost a lot of performance in some
110: apps */
1.1.1.4 ! root 111: #if 1 /* set to 1 if your system supports long extended precision long double */
1.1.1.2 root 112: #define USE_LONG_DOUBLE 1
1.1.1.4 ! root 113: #else
! 114: #define USE_LONG_DOUBLE 0
! 115: #define USE_SOFT_LONG_DOUBLE 1
! 116: #endif
1.1 root 117:
118: #if USE_LONG_DOUBLE
119: typedef long double fptype;
120: #define LDPTR tbyte ptr
121: #else
122: typedef double fptype;
123: #define LDPTR qword ptr
124: #endif
125: #endif
126:
127: #define CPU_PIPELINE_MAX 2
128: #define CPU000_MEM_CYCLE 4
129: #define CPU000_CLOCK_MULT 2
130: #define CPU020_MEM_CYCLE 3
131: #define CPU020_CLOCK_MULT 4
132:
133: #define CACHELINES020 64
134: struct cache020
135: {
136: uae_u32 data;
137: uae_u32 tag;
138: bool valid;
139: };
140:
141: #define CACHELINES030 16
142: struct cache030
143: {
144: uae_u32 data[4];
145: bool valid[4];
146: uae_u32 tag;
147: };
148:
149: #define CACHESETS040 64
150: #define CACHELINES040 4
151: struct cache040
152: {
153: uae_u32 data[CACHELINES040][4];
154: bool valid[CACHELINES040];
155: uae_u32 tag[CACHELINES040];
156: };
157:
1.1.1.3 root 158: uae_u64 srp_030, crp_030;
159: uae_u32 tt0_030, tt1_030, tc_030;
160: uae_u16 mmusr_030;
161:
162: struct mmufixup
163: {
164: int reg;
165: uae_u32 value;
166: };
167: extern struct mmufixup mmufixup[2];
1.1 root 168:
1.1.1.4 ! root 169: typedef struct
! 170: {
! 171: fptype fp;
! 172: #ifdef USE_SOFT_LONG_DOUBLE
! 173: bool fpx;
! 174: uae_u32 fpm;
! 175: uae_u64 fpe;
! 176: #endif
! 177: } fpdata;
! 178:
1.1 root 179: struct regstruct
180: {
181: uae_u32 regs[16];
182:
183: uae_u32 pc;
184: uae_u8 *pc_p;
185: uae_u8 *pc_oldp;
1.1.1.4 ! root 186: uae_u32 instruction_pc;
1.1 root 187:
188: uae_u16 irc, ir;
189: uae_u32 spcflags;
190:
191: uaecptr usp, isp, msp;
192: uae_u16 sr;
193: flagtype t1;
194: flagtype t0;
195: flagtype s;
196: flagtype m;
197: flagtype x;
198: flagtype stopped;
199: int intmask;
200: int ipl, ipl_pin;
201:
202: uae_u32 vbr, sfc, dfc;
203:
204: #ifdef FPUEMU
1.1.1.4 ! root 205: fpdata fp[8];
! 206: fpdata fp_result;
! 207: uae_u32 fp_result_status;
1.1 root 208: uae_u32 fpcr, fpsr, fpiar;
1.1.1.4 ! root 209: uae_u32 fpu_state;
! 210: uae_u32 fpu_exp_state;
! 211: fpdata exp_src1, exp_src2;
! 212: uae_u32 exp_pack[3];
! 213: uae_u16 exp_opcode, exp_extra, exp_type;
! 214: bool fp_exception;
1.1 root 215: #endif
216: #ifndef CPUEMU_68000_ONLY
217: uae_u32 cacr, caar;
218: uae_u32 itt0, itt1, dtt0, dtt1;
219: uae_u32 tcr, mmusr, urp, srp, buscr;
1.1.1.4 ! root 220: uae_u32 mmu_fslw;
! 221: uae_u32 mmu_fault_addr, mmu_effective_addr;
1.1 root 222: uae_u16 mmu_ssw;
1.1.1.4 ! root 223: uae_u32 wb2_address;
1.1 root 224: uae_u32 wb3_data;
1.1.1.4 ! root 225: uae_u16 wb3_status, wb2_status;
1.1 root 226: int mmu_enabled;
1.1.1.4 ! root 227: int mmu_page_size;
1.1 root 228: #endif
229:
230: uae_u32 pcr;
231: uae_u32 address_space_mask;
232:
233: uae_u8 panic;
234: uae_u32 panic_pc, panic_addr;
235:
236: uae_u32 prefetch020data[CPU_PIPELINE_MAX];
237: uae_u32 prefetch020addr[CPU_PIPELINE_MAX];
238: int ce020memcycles;
239: };
240:
241: extern struct regstruct regs;
242:
243: STATIC_INLINE uae_u32 munge24 (uae_u32 x)
244: {
245: return x & regs.address_space_mask;
246: }
247:
248: extern int mmu_enabled, mmu_triggered;
249: extern int cpu_cycles;
250: extern int cpucycleunit;
251: STATIC_INLINE void set_special (uae_u32 x)
252: {
253: regs.spcflags |= x;
254: cycles_do_special ();
255: }
256:
257: STATIC_INLINE void unset_special (uae_u32 x)
258: {
259: regs.spcflags &= ~x;
260: }
261:
262: #define m68k_dreg(r,num) ((r).regs[(num)])
263: #define m68k_areg(r,num) (((r).regs + 8)[(num)])
264:
265: STATIC_INLINE void m68k_setpc (uaecptr newpc)
266: {
1.1.1.4 ! root 267: regs.pc_p = regs.pc_oldp = 0;
! 268: regs.instruction_pc = regs.pc = newpc;
1.1 root 269: }
270:
271: STATIC_INLINE uaecptr m68k_getpc (void)
272: {
273: return (uaecptr)(regs.pc + ((uae_u8*)regs.pc_p - (uae_u8*)regs.pc_oldp));
274: }
275: #define M68K_GETPC m68k_getpc()
276:
277: STATIC_INLINE uaecptr m68k_getpc_p (uae_u8 *p)
278: {
279: return (uaecptr)(regs.pc + ((uae_u8*)p - (uae_u8*)regs.pc_oldp));
280: }
281:
282: STATIC_INLINE void fill_prefetch_0 (void)
283: {
284: }
285:
286: #define fill_prefetch_2 fill_prefetch_0
287:
288: STATIC_INLINE void m68k_incpc (int o)
289: {
290: regs.pc_p += o;
291: }
292:
293: STATIC_INLINE void m68k_setpc_mmu (uaecptr newpc)
294: {
1.1.1.4 ! root 295: regs.instruction_pc = regs.pc = newpc;
1.1 root 296: regs.pc_p = regs.pc_oldp = 0;
297: }
298: STATIC_INLINE void m68k_setpci (uaecptr newpc)
299: {
1.1.1.4 ! root 300: regs.instruction_pc = regs.pc = newpc;
1.1 root 301: }
302: STATIC_INLINE uaecptr m68k_getpci (void)
303: {
304: return regs.pc;
305: }
306: STATIC_INLINE void m68k_incpci (int o)
307: {
308: regs.pc += o;
309: }
310:
311: STATIC_INLINE void m68k_do_rts (void)
312: {
313: uae_u32 newpc = get_long (m68k_areg (regs, 7));
314: m68k_setpc (newpc);
315: m68k_areg (regs, 7) += 4;
316: }
317: STATIC_INLINE void m68k_do_rtsi (void)
318: {
319: m68k_setpci (get_long (m68k_areg (regs, 7)));
320: m68k_areg (regs, 7) += 4;
321: }
322:
323: STATIC_INLINE void m68k_do_bsr (uaecptr oldpc, uae_s32 offset)
324: {
325: m68k_areg (regs, 7) -= 4;
326: put_long (m68k_areg (regs, 7), oldpc);
327: m68k_incpc (offset);
328: }
329: STATIC_INLINE void m68k_do_bsri (uaecptr oldpc, uae_s32 offset)
330: {
331: m68k_areg (regs, 7) -= 4;
332: put_long (m68k_areg (regs, 7), oldpc);
333: m68k_incpci (offset);
334: }
335:
336: STATIC_INLINE uae_u32 get_ibyte (int o)
337: {
338: return do_get_mem_byte((uae_u8 *)((regs).pc_p + (o) + 1));
339: }
340: STATIC_INLINE uae_u32 get_iword (int o)
341: {
342: return do_get_mem_word((uae_u16 *)((regs).pc_p + (o)));
343: }
344: STATIC_INLINE uae_u32 get_ilong (int o)
345: {
346: return do_get_mem_long((uae_u32 *)((regs).pc_p + (o)));
347: }
348:
349: #define get_iwordi(o) get_wordi(o)
350: #define get_ilongi(o) get_longi(o)
351:
352: /* These are only used by the 68020/68881 code, and therefore don't
353: * need to handle prefetch. */
354: STATIC_INLINE uae_u32 next_ibyte (void)
355: {
356: uae_u32 r = get_ibyte (0);
357: m68k_incpc (2);
358: return r;
359: }
360: STATIC_INLINE uae_u32 next_iword (void)
361: {
362: uae_u32 r = get_iword (0);
363: m68k_incpc (2);
364: return r;
365: }
366: STATIC_INLINE uae_u32 next_iwordi (void)
367: {
368: uae_u32 r = get_iwordi (m68k_getpci ());
369: m68k_incpc (2);
370: return r;
371: }
372: STATIC_INLINE uae_u32 next_ilong (void)
373: {
374: uae_u32 r = get_ilong (0);
375: m68k_incpc (4);
376: return r;
377: }
378: STATIC_INLINE uae_u32 next_ilongi (void)
379: {
380: uae_u32 r = get_ilongi (m68k_getpci ());
381: m68k_incpc (4);
382: return r;
383: }
384:
1.1.1.4 ! root 385: extern uae_u32 (*x_prefetch)(int);
! 386: extern uae_u32 (*x_prefetch_long)(int);
1.1 root 387: extern uae_u32 (*x_get_byte)(uaecptr addr);
388: extern uae_u32 (*x_get_word)(uaecptr addr);
389: extern uae_u32 (*x_get_long)(uaecptr addr);
390: extern void (*x_put_byte)(uaecptr addr, uae_u32 v);
391: extern void (*x_put_word)(uaecptr addr, uae_u32 v);
392: extern void (*x_put_long)(uaecptr addr, uae_u32 v);
393: extern uae_u32 (*x_next_iword)(void);
394: extern uae_u32 (*x_next_ilong)(void);
1.1.1.4 ! root 395: extern uae_u32 (*x_get_ilong)(int);
! 396: extern uae_u32 (*x_get_iword)(int);
! 397: extern uae_u32 (*x_get_ibyte)(int);
! 398:
! 399: extern uae_u32 REGPARAM3 x_get_disp_ea_020 (uae_u32 base, int idx) REGPARAM;
! 400: extern uae_u32 REGPARAM3 x_get_disp_ea_ce020 (uae_u32 base, int idx) REGPARAM;
! 401: extern uae_u32 REGPARAM3 x_get_disp_ea_ce030 (uae_u32 base, int idx) REGPARAM;
1.1 root 402: extern uae_u32 REGPARAM3 x_get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) REGPARAM;
403: extern void REGPARAM3 x_put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) REGPARAM;
404:
1.1.1.4 ! root 405: extern uae_u32 (*x_cp_get_byte)(uaecptr addr);
! 406: extern uae_u32 (*x_cp_get_word)(uaecptr addr);
! 407: extern uae_u32 (*x_cp_get_long)(uaecptr addr);
! 408: extern void (*x_cp_put_byte)(uaecptr addr, uae_u32 v);
! 409: extern void (*x_cp_put_word)(uaecptr addr, uae_u32 v);
! 410: extern void (*x_cp_put_long)(uaecptr addr, uae_u32 v);
! 411: extern uae_u32 (*x_cp_next_iword)(void);
! 412: extern uae_u32 (*x_cp_next_ilong)(void);
! 413:
! 414: extern uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
! 415:
1.1 root 416: extern void m68k_setstopped (void);
417: extern void m68k_resumestopped (void);
418:
1.1.1.4 ! root 419: extern uae_u32 REGPARAM3 get_disp_ea_020 (uae_u32 base, int idx) REGPARAM;
1.1 root 420: extern uae_u32 REGPARAM3 get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) REGPARAM;
421: extern void REGPARAM3 put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) REGPARAM;
422:
423: extern void m68k_disasm_ea (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr);
424: extern void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt);
425: extern int get_cpu_model (void);
426:
1.1.1.4 ! root 427: extern void set_cpu_caches (bool flush);
1.1 root 428: extern void REGPARAM3 MakeSR (void) REGPARAM;
429: extern void REGPARAM3 MakeFromSR (void) REGPARAM;
430: extern void MakeSR (void);
431: extern void MakeFromSR (void);
1.1.1.4 ! root 432: extern void REGPARAM3 Exception (int) REGPARAM;
! 433: extern void REGPARAM3 ExceptionL (int/*, uaecptr*/) REGPARAM;
! 434: //extern void REGPARAM3 Exception (int, uaecptr, int) REGPARAM;
1.1 root 435: extern void NMI (void);
436: extern void NMI_delayed (void);
437: extern void prepare_interrupt (uae_u32);
438: extern void doint (void);
439: extern void dump_counts (void);
440: extern int m68k_move2c (int, uae_u32 *);
441: extern int m68k_movec2 (int, uae_u32 *);
1.1.1.4 ! root 442: extern bool m68k_divl (uae_u32, uae_u32, uae_u16);
! 443: extern bool m68k_mull (uae_u32, uae_u32, uae_u16);
! 444: //extern void m68k_divl (uae_u32, uae_u32, uae_u16, uaecptr);
! 445: //extern void m68k_mull (uae_u32, uae_u32, uae_u16);
1.1 root 446: extern void init_m68k (void);
447: extern void init_m68k_full (void);
448: extern void m68k_go (int);
449: extern void m68k_dumpstate (FILE *, uaecptr *);
450: extern void m68k_disasm (FILE *, uaecptr, uaecptr *, int);
451: extern void sm68k_disasm (TCHAR*, TCHAR*, uaecptr addr, uaecptr *nextpc);
452: extern void m68k_reset (int);
453: extern int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor);
454: extern int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor);
1.1.1.4 ! root 455: extern void divbyzero_special (bool issigned, uae_s32 dst);
1.1 root 456: extern void m68k_do_rte (void);
457:
458: extern void mmu_op (uae_u32, uae_u32);
459: extern void mmu_op30 (uaecptr, uae_u32, uae_u16, uaecptr);
460:
461: extern void fpuop_arithmetic(uae_u32, uae_u16);
462: extern void fpuop_dbcc(uae_u32, uae_u16);
463: extern void fpuop_scc(uae_u32, uae_u16);
464: extern void fpuop_trapcc(uae_u32, uaecptr, uae_u16);
465: extern void fpuop_bcc(uae_u32, uaecptr, uae_u32);
466: extern void fpuop_save(uae_u32);
467: extern void fpuop_restore(uae_u32);
468: extern uae_u32 fpp_get_fpsr (void);
469: extern void fpu_reset (void);
470: extern void fpux_save (int*);
471: extern void fpux_restore (int*);
472:
1.1.1.4 ! root 473: extern void exception3 (uae_u32 opcode, uaecptr addr);
! 474: extern void exception3i (uae_u32 opcode, uaecptr addr);
! 475: extern void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc);
! 476: extern void exception2 (uaecptr addr, bool read, int size, uae_u32 fc);
! 477: //extern void exception3 (uae_u32 opcode, uaecptr addr, uaecptr fault);
! 478: //extern void exception3i (uae_u32 opcode, uaecptr addr, uaecptr fault);
! 479: //extern void exception2 (uaecptr addr, uaecptr fault);
1.1 root 480: extern void cpureset (void);
1.1.1.4 ! root 481: extern void cpu_halt (int id);
1.1 root 482:
1.1.1.4 ! root 483: extern void fill_prefetch (void);
! 484: extern void fill_prefetch_020 (void);
! 485: extern void fill_prefetch_030 (void);
1.1 root 486:
487: #define CPU_OP_NAME(a) op ## a
488:
489: /* 68060 */
490: extern const struct cputbl op_smalltbl_0_ff[];
1.1.1.4 ! root 491: extern const struct cputbl op_smalltbl_22_ff[]; // CE
! 492: extern const struct cputbl op_smalltbl_33_ff[]; // MMU
1.1 root 493: /* 68040 */
494: extern const struct cputbl op_smalltbl_1_ff[];
1.1.1.4 ! root 495: extern const struct cputbl op_smalltbl_23_ff[]; // CE
1.1 root 496: extern const struct cputbl op_smalltbl_31_ff[]; // MMU
497: /* 68030 */
498: extern const struct cputbl op_smalltbl_2_ff[];
1.1.1.4 ! root 499: extern const struct cputbl op_smalltbl_24_ff[]; // CE
1.1.1.3 root 500: extern const struct cputbl op_smalltbl_32_ff[]; // MMU
1.1 root 501: /* 68020 */
502: extern const struct cputbl op_smalltbl_3_ff[];
1.1.1.4 ! root 503: extern const struct cputbl op_smalltbl_20_ff[]; // prefetch
! 504: extern const struct cputbl op_smalltbl_21_ff[]; // CE
1.1 root 505: /* 68010 */
506: extern const struct cputbl op_smalltbl_4_ff[];
1.1.1.4 ! root 507: extern const struct cputbl op_smalltbl_11_ff[]; // prefetch
! 508: extern const struct cputbl op_smalltbl_13_ff[]; // CE
1.1 root 509: /* 68000 */
510: extern const struct cputbl op_smalltbl_5_ff[];
1.1.1.4 ! root 511: extern const struct cputbl op_smalltbl_12_ff[]; // prefetch
! 512: extern const struct cputbl op_smalltbl_14_ff[]; // CE
1.1 root 513:
514: extern cpuop_func *cpufunctbl[65536] ASM_SYM_FOR_FUNC ("cpufunctbl");
515:
516: /* Added for hatari_glue.c */
517: extern void build_cpufunctbl(void);
518:
519: #ifdef JIT
520: extern void flush_icache (uaecptr, int);
521: extern void compemu_reset (void);
522: extern bool check_prefs_changed_comp (void);
523: #else
524: #define flush_icache(uaecptr, int) do {} while (0)
525: #endif
526: extern void flush_dcache (uaecptr, int);
527: extern void flush_mmu (uaecptr, int);
528:
529: extern int movec_illg (int regno);
530: extern uae_u32 val_move2c (int regno);
531: extern void val_move2c2 (int regno, uae_u32 val);
532: struct cpum2c {
533: int regno;
534: const TCHAR *regname;
535: };
536: extern struct cpum2c m2cregs[];
537:
538: /* Family of the latest instruction executed (to check for pairing) */
539: extern int OpcodeFamily; /* see instrmnem in readcpu.h */
540:
541: /* How many cycles to add to the current instruction in case a "misaligned" bus acces is made */
542: /* (used when addressing mode is d8(an,ix)) */
543: extern int BusCyclePenalty;
544:
545: STATIC_INLINE uae_u32 get_iword_prefetch (uae_s32 o)
546: {
547: /* Laurent : let's see this later
548: uae_u32 currpc = m68k_getpc ();
549: uae_u32 addr = currpc + o;
550: uae_u32 offs = addr - prefetch_pc;
551: uae_u32 v;
552: if (offs > 3) {
553: refill_prefetch (currpc, o);
554: offs = addr - prefetch_pc;
555: }
556: v = do_get_mem_word (((uae_u8 *)&prefetch) + offs);
557: if (offs >= 2)
558: refill_prefetch (currpc, 2);
559: */
560: /* printf ("get_iword PC %lx ADDR %lx OFFS %lx V %lx\n", currpc, addr, offs, v); */
561: //return v;
562: return 0;
563: }
564:
565: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.